зеркало из https://github.com/github/ruby.git
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
This commit is contained in:
Родитель
9eb4344a16
Коммит
9b7fe0a250
|
@ -18,7 +18,7 @@ ripper.o: ripper.c
|
||||||
all: check
|
all: check
|
||||||
static: check
|
static: check
|
||||||
|
|
||||||
ripper.y: $(srcdir)/tools/preproc.rb $(top_srcdir)/parse.y {$(VPATH)}id.h
|
ripper.y: $(srcdir)/tools/preproc.rb $(srcdir)/tools/dsl.rb $(top_srcdir)/parse.y {$(VPATH)}id.h
|
||||||
$(ECHO) extracting $@ from $(top_srcdir)/parse.y
|
$(ECHO) extracting $@ from $(top_srcdir)/parse.y
|
||||||
$(Q) $(RUBY) $(top_srcdir)/tool/id2token.rb --path-separator=.$(PATH_SEPARATOR)./ \
|
$(Q) $(RUBY) $(top_srcdir)/tool/id2token.rb --path-separator=.$(PATH_SEPARATOR)./ \
|
||||||
--vpath=$(VPATH)$(PATH_SEPARATOR)$(top_srcdir) id.h $(top_srcdir)/parse.y > ripper.tmp.y
|
--vpath=$(VPATH)$(PATH_SEPARATOR)$(top_srcdir) id.h $(top_srcdir)/parse.y > ripper.tmp.y
|
||||||
|
@ -32,11 +32,11 @@ check: .eventids2-check
|
||||||
$(Q) $(RUBY) $(GEN) --mode=check --ids1src=$(SRC1) --ids2src=$(SRC2)
|
$(Q) $(RUBY) $(GEN) --mode=check --ids1src=$(SRC1) --ids2src=$(SRC2)
|
||||||
@exit > $@
|
@exit > $@
|
||||||
|
|
||||||
eventids1.c: $(srcdir)/tools/generate.rb $(SRC1)
|
eventids1.c: $(GEN) $(srcdir)/tools/dsl.rb $(SRC1)
|
||||||
$(ECHO) generating $@ from $(SRC1)
|
$(ECHO) generating $@ from $(SRC1)
|
||||||
$(Q) $(RUBY) $(GEN) --mode=eventids1 --ids1src=$(SRC1) --output=$@
|
$(Q) $(RUBY) $(GEN) --mode=eventids1 --ids1src=$(SRC1) --output=$@
|
||||||
|
|
||||||
eventids2table.c: $(srcdir)/tools/generate.rb $(SRC2)
|
eventids2table.c: $(GEN) $(srcdir)/tools/dsl.rb $(SRC2)
|
||||||
$(ECHO) generating $@ from $(SRC2)
|
$(ECHO) generating $@ from $(SRC2)
|
||||||
$(Q) $(RUBY) $(GEN) --mode=eventids2table --ids2src=$(SRC2) --output=$@
|
$(Q) $(RUBY) $(GEN) --mode=eventids2table --ids2src=$(SRC2) --output=$@
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -135,6 +135,8 @@ def check_arity(h)
|
||||||
abort if invalid
|
abort if invalid
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require_relative "dsl"
|
||||||
|
|
||||||
def read_ids1_with_locations(path)
|
def read_ids1_with_locations(path)
|
||||||
h = {}
|
h = {}
|
||||||
File.open(path) {|f|
|
File.open(path) {|f|
|
||||||
|
@ -144,6 +146,13 @@ def read_ids1_with_locations(path)
|
||||||
line.scan(/\bdispatch(\d)\((\w+)/) do |arity, event|
|
line.scan(/\bdispatch(\d)\((\w+)/) do |arity, event|
|
||||||
(h[event] ||= []).push [f.lineno, arity.to_i]
|
(h[event] ||= []).push [f.lineno, arity.to_i]
|
||||||
end
|
end
|
||||||
|
if line =~ %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
|
||||||
|
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
|
end
|
||||||
}
|
}
|
||||||
h
|
h
|
||||||
|
|
|
@ -72,9 +72,13 @@ def prelude(f, out)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
require_relative "dsl"
|
||||||
|
|
||||||
def grammar(f, out)
|
def grammar(f, out)
|
||||||
while line = f.gets
|
while line = f.gets
|
||||||
case line
|
case line
|
||||||
|
when %r</\*% *ripper(?:\[(.*?)\])?: *(.*?) *%\*/>
|
||||||
|
out << DSL.new($2, ($1 || "").split(",")).generate << $/
|
||||||
when %r</\*%%%\*/>
|
when %r</\*%%%\*/>
|
||||||
out << '#if 0' << $/
|
out << '#if 0' << $/
|
||||||
when %r</\*%c%\*/>
|
when %r</\*%c%\*/>
|
||||||
|
|
1176
parse.y
1176
parse.y
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче