summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2020-09-10 18:12:38 +0900
committerGitHub <[email protected]>2020-09-10 18:12:38 +0900
commitc27e45193177b6e4d09d526a248af63c0961035a (patch)
tree863c5082109295c880311b2abe1eefc4c748dc4d
parentc345fe432171cc2b90b614a0b44305b218090de6 (diff)
parent9840e5352b2abf96235068f0e9d08f14b1d333cf (diff)
downloadmruby-c27e45193177b6e4d09d526a248af63c0961035a.tar.gz
mruby-c27e45193177b6e4d09d526a248af63c0961035a.zip
Merge pull request #4933 from dearblue/variables
Fix take over file scope variables with `mruby` and `mirb` command
-rw-r--r--include/mruby/compile.h1
-rw-r--r--lib/mruby/gem.rb5
-rw-r--r--mrbgems/mruby-bin-mirb/bintest/mirb.rb17
-rw-r--r--mrbgems/mruby-bin-mirb/tools/mirb/mirb.c13
-rw-r--r--mrbgems/mruby-bin-mruby/bintest/mruby.rb21
-rw-r--r--mrbgems/mruby-bin-mruby/tools/mruby/mruby.c6
-rw-r--r--mrbgems/mruby-compiler/core/parse.y10
7 files changed, 69 insertions, 4 deletions
diff --git a/include/mruby/compile.h b/include/mruby/compile.h
index 7b878d460..e8ab91eb9 100644
--- a/include/mruby/compile.h
+++ b/include/mruby/compile.h
@@ -42,6 +42,7 @@ MRB_API mrbc_context* mrbc_context_new(mrb_state *mrb);
MRB_API void mrbc_context_free(mrb_state *mrb, mrbc_context *cxt);
MRB_API const char *mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s);
MRB_API void mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*partial_hook)(struct mrb_parser_state*), void*data);
+MRB_API void mrbc_cleanup_local_variables(mrb_state *mrb, mrbc_context *c);
/* AST node structure */
typedef struct mrb_ast_node {
diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb
index 4c3cd7f02..6fcaad9c1 100644
--- a/lib/mruby/gem.rb
+++ b/lib/mruby/gem.rb
@@ -180,6 +180,7 @@ module MRuby
f.puts %Q[]
f.puts %Q[void GENERATED_TMP_mrb_#{funcname}_gem_init(mrb_state *mrb) {]
f.puts %Q[ int ai = mrb_gc_arena_save(mrb);]
+ f.puts %Q[ struct REnv *e;] unless rbfiles.empty?
f.puts %Q[ mrb_#{funcname}_gem_init(mrb);] if objs != [objfile("#{build_dir}/gem_init")]
unless rbfiles.empty?
f.puts %Q[ mrb_load_irep(mrb, gem_mrblib_irep_#{funcname});]
@@ -188,6 +189,9 @@ module MRuby
f.puts %Q[ mrb_close(mrb);]
f.puts %Q[ exit(EXIT_FAILURE);]
f.puts %Q[ }]
+ f.puts %Q[ e = mrb->c->cibase->env;]
+ f.puts %Q[ mrb->c->cibase->env = NULL;]
+ f.puts %Q[ mrb_env_unshare(mrb, e);]
end
f.puts %Q[ mrb_gc_arena_restore(mrb, ai);]
f.puts %Q[}]
@@ -214,6 +218,7 @@ module MRuby
f.puts %Q[#include <stdlib.h>] unless rbfiles.empty?
f.puts %Q[#include <mruby.h>]
f.puts %Q[#include <mruby/irep.h>] unless rbfiles.empty?
+ f.puts %Q[#include <mruby/proc.h>] unless rbfiles.empty?
end
def print_gem_test_header(f)
diff --git a/mrbgems/mruby-bin-mirb/bintest/mirb.rb b/mrbgems/mruby-bin-mirb/bintest/mirb.rb
index 0058896f1..3a03726bb 100644
--- a/mrbgems/mruby-bin-mirb/bintest/mirb.rb
+++ b/mrbgems/mruby-bin-mirb/bintest/mirb.rb
@@ -32,3 +32,20 @@ EOS
o, _ = Open3.capture2("bin/mirb -r #{lib.path}", :stdin_data => "Hoge.new.hoge\n")
assert_true o.include?('=> :hoge')
end
+
+assert('top level local variables are in file scope') do
+ lib = Tempfile.new('lib.rb')
+ lib.write <<-TESTLIB
+a = 1
+A = -> { a }
+ TESTLIB
+ lib.flush
+
+ o, _ = Open3.capture2("bin/mirb -r #{lib.path}", :stdin_data => <<-TESTCODE)
+a
+a = 5
+A.call
+ TESTCODE
+
+ assert_kind_of Integer, o =~ /\bundefined method 'a' \(NoMethodError\).*=> 5\b.*=> 1\b/m
+end
diff --git a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
index a0eeaf459..51ba3fd78 100644
--- a/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
+++ b/mrbgems/mruby-bin-mirb/tools/mirb/mirb.c
@@ -495,12 +495,9 @@ main(int argc, char **argv)
cxt = mrbc_context_new(mrb);
-#ifndef DISABLE_MIRB_UNDERSCORE
- decl_lv_underscore(mrb, cxt);
-#endif
-
/* Load libraries */
for (i = 0; i < args.libc; i++) {
+ struct REnv *e;
FILE *lfp = fopen(args.libv[i], "r");
if (lfp == NULL) {
printf("Cannot open library file. (%s)\n", args.libv[i]);
@@ -509,8 +506,16 @@ main(int argc, char **argv)
}
mrb_load_file_cxt(mrb, lfp, cxt);
fclose(lfp);
+ e = mrb->c->cibase->env;
+ mrb->c->cibase->env = NULL;
+ mrb_env_unshare(mrb, e);
+ mrbc_cleanup_local_variables(mrb, cxt);
}
+#ifndef DISABLE_MIRB_UNDERSCORE
+ decl_lv_underscore(mrb, cxt);
+#endif
+
cxt->capture_errors = TRUE;
cxt->lineno = 1;
mrbc_filename(mrb, cxt, "(mirb)");
diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
index 9887a2830..a04093529 100644
--- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb
+++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb
@@ -162,3 +162,24 @@ assert('codegen error') do
code = "def f(#{(1..100).map{|n| "a#{n}"} * ","}); end"
assert_mruby("", /\Acodegen error:.*\n\z/, false, ["-e", code])
end
+
+assert('top level local variables are in file scope') do
+ arb, amrb = Tempfile.new('a.rb'), Tempfile.new('a.mrb')
+ brb, bmrb = Tempfile.new('b.rb'), Tempfile.new('b.mrb')
+ crb, cmrb = Tempfile.new('c.rb'), Tempfile.new('c.mrb')
+ drb, dmrb = Tempfile.new('d.rb'), Tempfile.new('d.mrb')
+
+ File.write arb.path, 'a = 1'
+ system "#{cmd('mrbc')} -g -o #{amrb.path} #{arb.path}"
+ File.write brb.path, 'p a'
+ system "#{cmd('mrbc')} -g -o #{bmrb.path} #{brb.path}"
+ assert_mruby("", /:1: undefined method 'a' \(NoMethodError\)\n\z/, false, ["-r", arb.path, brb.path])
+ assert_mruby("", /:1: undefined method 'a' \(NoMethodError\)\n\z/, false, ["-b", "-r", amrb.path, bmrb.path])
+
+ File.write crb.path, 'a, b, c = 1, 2, 3; A = -> { b = -2; [a, b, c] }'
+ system "#{cmd('mrbc')} -g -o #{cmrb.path} #{crb.path}"
+ File.write drb.path, 'a, b = 5, 6; p A.call; p a, b'
+ system "#{cmd('mrbc')} -g -o #{dmrb.path} #{drb.path}"
+ assert_mruby("[1, -2, 3]\n5\n6\n", "", true, ["-r", crb.path, drb.path])
+ assert_mruby("[1, -2, 3]\n5\n6\n", "", true, ["-b", "-r", cmrb.path, dmrb.path])
+end
diff --git a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
index e5c8f3466..793245875 100644
--- a/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
+++ b/mrbgems/mruby-bin-mruby/tools/mruby/mruby.c
@@ -10,6 +10,7 @@
#include <mruby/compile.h>
#include <mruby/dump.h>
#include <mruby/variable.h>
+#include <mruby/proc.h>
struct _args {
FILE *rfp;
@@ -307,6 +308,7 @@ main(int argc, char **argv)
/* Load libraries */
for (i = 0; i < args.libc; i++) {
+ struct REnv *e;
FILE *lfp = fopen(args.libv[i], args.mrbfile ? "rb" : "r");
if (lfp == NULL) {
fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]);
@@ -321,6 +323,10 @@ main(int argc, char **argv)
v = mrb_load_file_cxt(mrb, lfp, c);
}
fclose(lfp);
+ e = mrb->c->cibase->env;
+ mrb->c->cibase->env = NULL;
+ mrb_env_unshare(mrb, e);
+ mrbc_cleanup_local_variables(mrb, c);
}
/* Load program */
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index 3ae2022cf..9de45a536 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -6377,6 +6377,16 @@ mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser
}
MRB_API void
+mrbc_cleanup_local_variables(mrb_state *mrb, mrbc_context *c)
+{
+ if (c->syms) {
+ mrb_free(mrb, c->syms);
+ c->syms = NULL;
+ c->slen = 0;
+ }
+}
+
+MRB_API void
mrb_parser_set_filename(struct mrb_parser_state *p, const char *f)
{
mrb_sym sym;