mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	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:
		
							parent
							
								
									9eb4344a16
								
							
						
					
					
						commit
						9b7fe0a250
					
				
					 5 changed files with 501 additions and 740 deletions
				
			
		| 
						 | 
					@ -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=$@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										46
									
								
								ext/ripper/tools/dsl.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								ext/ripper/tools/dsl.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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%\*/>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue