summaryrefslogtreecommitdiff
path: root/ext/ripper
diff options
context:
space:
mode:
authormame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-01-20 17:45:24 +0000
committermame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-01-20 17:45:24 +0000
commitd24f1fddd770ca5ac488602207649ac678fb10ad (patch)
treee4c0c6dda33d23f7a20a3dcb33cdfe0709f88814 /ext/ripper
parent7ba7a2f70ebc27fd097843bf866d46b665475cbb (diff)
downloadruby-d24f1fddd770ca5ac488602207649ac678fb10ad.tar.gz
ext/ripper/tools/dsl.rb: Serialize dispatch calls
To avoid the unspecified behavior (the evaluation order of arguments). In `$$ = foo(bar(), baz());`, it is unspecified which `bar` or `baz` is called earlier. This commit changes the code to `v1=bar(); v2=baz(); $$ = foo();`. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61991 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/ripper')
-rw-r--r--ext/ripper/tools/dsl.rb26
1 files changed, 22 insertions, 4 deletions
diff --git a/ext/ripper/tools/dsl.rb b/ext/ripper/tools/dsl.rb
index c4c5a36e27..44a8f4233d 100644
--- a/ext/ripper/tools/dsl.rb
+++ b/ext/ripper/tools/dsl.rb
@@ -1,7 +1,11 @@
# Simple DSL implementation for Ripper code generation
#
# input: /*% ripper: stmts_add(stmts_new, void_stmt) %*/
-# output: $$ = dispatch2(stmts_add, dispatch0(stmts_new), dispatch0(void_stmt))
+# output:
+# VALUE v1, v2;
+# v1 = dispatch0(stmts_new);
+# v2 = dispatch0(void_stmt);
+# $$ = dispatch2(stmts_add, v1, v2);
class DSL
def initialize(code, options)
@@ -9,6 +13,7 @@ class DSL
@error = options.include?("error")
@brace = options.include?("brace")
@final = options.include?("final")
+ @vars = 0
# create $1 == "$1", $2 == "$2", ...
re, s = "", ""
@@ -21,7 +26,8 @@ class DSL
# struct parser_params *p
p = "p"
- @code = eval(code)
+ @code = ""
+ @last_value = eval(code)
end
attr_reader :events
@@ -33,17 +39,29 @@ class DSL
def generate
s = "$$"
s = "p->result" if @final
- s = "#{ s } = #@code;"
+ s = "#@code#{ s }=#@last_value;"
+ s = "{VALUE #{ (1..@vars).map {|v| "v#{ v }" }.join(",") };#{ s }}" if @vars > 0
s << "ripper_error(p);" if @error
s = "{#{ s }}" if @brace
"\t\t\t#{s}"
end
+ def new_var
+ "v#{ @vars += 1 }"
+ end
+
def method_missing(event, *args)
if event.to_s =~ /!\z/
event = $`
@events[event] = args.size
- "dispatch#{ args.size }(#{ [event, *args].join(", ") })"
+ vars = []
+ args.each do |arg|
+ vars << v = new_var
+ @code << "#{ v }=#{ arg };"
+ end
+ v = new_var
+ @code << "#{ v }=dispatch#{ args.size }(#{ [event, *vars].join(",") });"
+ v
elsif args.empty? and /\Aid[A-Z]/ =~ event.to_s
event
else