From 9b7fe0a25012d615f1cae8da1f5c444f61ffb7c7 Mon Sep 17 00:00:00 2001 From: mame Date: Fri, 19 Jan 2018 10:48:08 +0000 Subject: ext/ripper: Introduce a simple DSL for ripper.y code generation Currently, parse.y actions are hard to read and write because the code has double meaning (for core parser and for ripper). I think that, if it is easy to write ripper's code shortly and simply, the double meaning trick is not needed. For the sake, this change adds a simple DSL for ripper's code. For example, in parse.y, we can write: /*% ripper: stmts_add(stmts_new, void_stmt) %*/ instead of: $$ = dispatch2(stmts_add, dispatch0(stmts_new), dispatch0(void_stmt)); git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61952 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/ripper/tools/dsl.rb | 46 ++++++++++++++++++++++++++++++++++++++++++++ ext/ripper/tools/generate.rb | 9 +++++++++ ext/ripper/tools/preproc.rb | 4 ++++ 3 files changed, 59 insertions(+) create mode 100644 ext/ripper/tools/dsl.rb (limited to 'ext/ripper/tools') diff --git a/ext/ripper/tools/dsl.rb b/ext/ripper/tools/dsl.rb new file mode 100644 index 0000000000..e321019d7e --- /dev/null +++ b/ext/ripper/tools/dsl.rb @@ -0,0 +1,46 @@ +# 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)) + +class DSL + def initialize(code, options) + @events = {} + @error = options.include?("error") + @brace = options.include?("brace") + + # create $1 == "$1", $2 == "$2", ... + re, s = "", "" + 1.upto(9) do |n| + re << "(..)" + s << "$#{ n }" + end + /#{ re }/ =~ s + + @code = eval(code) + end + + attr_reader :events + + undef lambda + undef hash + undef class + + def generate + s = "$$" + s = "\t\t\t#{ s } = #@code;" + s << "ripper_error(p);" if @error + s = "{#{ s }}" if @brace + s + end + + def method_missing(*args) + if args.first =~ /\A_/ + "#{ $' }(#{ args.drop(1).join(", ") })" + else + @events[args.first.to_s] = args.size - 1 + "dispatch#{ args.size - 1 }(#{ args.join(", ") })" + end + end +end + diff --git a/ext/ripper/tools/generate.rb b/ext/ripper/tools/generate.rb index cf24f1398d..883e6ef2df 100755 --- a/ext/ripper/tools/generate.rb +++ b/ext/ripper/tools/generate.rb @@ -135,6 +135,8 @@ def check_arity(h) abort if invalid end +require_relative "dsl" + def read_ids1_with_locations(path) h = {} File.open(path) {|f| @@ -144,6 +146,13 @@ def read_ids1_with_locations(path) line.scan(/\bdispatch(\d)\((\w+)/) do |arity, event| (h[event] ||= []).push [f.lineno, arity.to_i] end + if line =~ %r + gen = DSL.new($2, ($1 || "").split(",")) + gen.generate + gen.events.each do |event, arity| + (h[event] ||= []).push [f.lineno, arity.to_i] + end + end end } h diff --git a/ext/ripper/tools/preproc.rb b/ext/ripper/tools/preproc.rb index 8b68579164..560a82e54f 100755 --- a/ext/ripper/tools/preproc.rb +++ b/ext/ripper/tools/preproc.rb @@ -72,9 +72,13 @@ def prelude(f, out) end end +require_relative "dsl" + def grammar(f, out) while line = f.gets case line + when %r + out << DSL.new($2, ($1 || "").split(",")).generate << $/ when %r out << '#if 0' << $/ when %r -- cgit v1.2.3