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
	
	 mame
						mame