ruby_parser
Advanced tools
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
+69
-0
@@ -0,1 +1,70 @@ | ||
| === 3.0.0.a1 / 2012-05-22 | ||
| This is the first alpha release of the 3.0.0 series. It is probably | ||
| woefully incomplete, bug ridden, and hasn't showered in several days. | ||
| Please please please beat the crap out of it and send | ||
| bugs/patches/complaints/suggestions. | ||
| * 5 major enhancements: | ||
| * 1.9 parsing! Thanks to EVERYONE for submitting patches for this! | ||
| * Removed :arglist from everything but :op_asgn1 | ||
| * Removed :block from resbody | ||
| * Removed :block from when | ||
| * Removed :block nodes inside of scope nodes (defn/defs/class/sclass). | ||
| * Removed :scope nodes in defn/defs/class/sclass nodes. | ||
| * (probably more sexp cleanup to come before 3.0.0 final) | ||
| * 25 minor enhancements: | ||
| * 1.9: Fix \!a. (wanabe) | ||
| * 1.9: Method calling with postargs. (wanabe) | ||
| * 1.9: Method definition with postargs. (wanabe) | ||
| * 1.9: Support lambda args without parentheses. (wanabe) | ||
| * Added R arg to `rake debug` to debug ruby straight up | ||
| * Added RubyParser, subclassing Ruby18Parser but warning on instantiation. | ||
| * Added backref_assign_error (needs tests) | ||
| * Added bin/ruby_parse_extract_error to help with error submissions | ||
| * Added debug task to help quickly get into a bug | ||
| * Added more 18 vs 19 lexing tests for ?c. | ||
| * Added ruby_parser.rb that pulls everything together in proper order. | ||
| * Added tLABEL. (brynary) | ||
| * Branched ruby_parser.y to ruby18_parser.y | ||
| * Fix to pass test_lambda_args_block__19 test. (mrmargolis) | ||
| * Got rid of one instance of unread_many. (Confusion) | ||
| * Moved everything from RubyParser to RubyParserStuff and included module in both. | ||
| * Refactored 1.9 args handling | ||
| * Refactored and added new_resbody to ruby_parser_extras. | ||
| * Refactored and added new_when | ||
| * Refactored tests infrastructure and added both 1.8 and 1.9 test branches. | ||
| * Removed unused methods: unread, begin_of_line? was_begin_of_line. (YAY!) (Confusion) | ||
| * Renamed ruby_parser.y to ruby19_parser.y | ||
| * RubyLexer now takes a version specifier. | ||
| * Started doing comparative refactoring between MRI's 1.9 parser and RP's. Shouldn't differ functionally except where we missed stuff in RP. | ||
| * `rake debug` prints the output if it succeeds. | ||
| * 21 bug fixes: | ||
| * Added missing gvar arg error. (1.8) | ||
| * Attach parser files to isolate to ensure they can build | ||
| * Conditionalize handling of tLABEL to ruby19+. Fixes issue #33. | ||
| * DOH. I deactivated some tests and never reactivated them. (Confusion ftw) | ||
| * Duplicate the input so that heredoc processing doesn't morph original. (banister) | ||
| * Entirely reworked block arg handling. (1.8) | ||
| * Fix ?x char literal. (nobu) | ||
| * Fixed 4/5 of literal lambda tests (jamie) | ||
| * Fixed deps for parser | ||
| * Fixed lexing of ?c for ruby 1.8 and 1.9. | ||
| * Fixed more Ruby 1.9 args tests (brynary) | ||
| * Fixed reswords to match MRI (1.8, 1.9) | ||
| * Fixed symbols with no spaces in method calls (e.g. foo:bar) (YAY! brynary) | ||
| * Fixed ternary_nil_no_space and other ternary edge cases for 1.9. (lastobelus) | ||
| * Fixed test_call_not_equal__19. First bug bounty! (albus522) | ||
| * Made lambda w/o arg list zero out the arg slot. | ||
| * Renamed awords to qwords to match stupid MRI naming. (1.8, 1.9) :( | ||
| * Rolled out brynary's symbols-no-spaces (foo:bar) changes when parsing 1.8 code | ||
| * Split 1.8 from 1.9 open paren lexer. Gawd that's ugly code. | ||
| * Split block_var from for_var. (1.8, 1.9) | ||
| * Use binread (and emulate in ruby 1.8) to avoid encoding issues | ||
| === 2.3.1 / 2011-09-21 | ||
@@ -2,0 +71,0 @@ |
+130
-37
@@ -5,2 +5,3 @@ class RubyLexer | ||
| attr_accessor :cond | ||
| attr_accessor :tern | ||
| attr_accessor :nest | ||
@@ -10,2 +11,8 @@ | ||
| ## | ||
| # What version of ruby to parse. 18 and 19 are the only valid values | ||
| # currently supported. | ||
| attr_accessor :version | ||
| # Additional context surrounding tokens that both the lexer and | ||
@@ -40,3 +47,3 @@ # grammar use. | ||
| STR_FUNC_REGEXP = 0x04 | ||
| STR_FUNC_AWORDS = 0x08 | ||
| STR_FUNC_QWORDS = 0x08 | ||
| STR_FUNC_SYMBOL = 0x10 | ||
@@ -64,2 +71,3 @@ STR_FUNC_INDENT = 0x20 # <<-HEREDOC | ||
| "=~" => :tMATCH, | ||
| "->" => :tLAMBDA, | ||
| } | ||
@@ -137,3 +145,3 @@ | ||
| until src.scan(eos_re) do | ||
| until src.check(eos_re) do | ||
| c = tokadd_string func, "\n", nil | ||
@@ -154,5 +162,2 @@ | ||
| end | ||
| # tack on a NL after the heredoc token - FIX NL should not be needed | ||
| src.unread_many(eos + "\n") # TODO: remove this... stupid stupid stupid | ||
| else | ||
@@ -204,8 +209,6 @@ until src.check(eos_re) do | ||
| if src.check(/.*\n/) then | ||
| if src.scan(/.*\n/) then | ||
| # TODO: think about storing off the char range instead | ||
| line = src.string[src.pos, src.matched_size] | ||
| src.string[src.pos, src.matched_size] = "\n" | ||
| line = src.matched | ||
| src.extra_lines_added += 1 | ||
| src.pos += 1 | ||
| else | ||
@@ -226,5 +229,7 @@ line = nil | ||
| def initialize | ||
| def initialize v = 18 | ||
| self.version = v | ||
| self.cond = RubyParser::StackState.new(:cond) | ||
| self.cmdarg = RubyParser::StackState.new(:cmdarg) | ||
| self.tern = RubyParser::StackState.new(:tern) | ||
| self.nest = 0 | ||
@@ -320,6 +325,6 @@ @comments = [] | ||
| src.scan(/\s*/) | ||
| [:tWORDS_BEG, STR_DQUOTE | STR_FUNC_AWORDS] | ||
| [:tWORDS_BEG, STR_DQUOTE | STR_FUNC_QWORDS] | ||
| when 'w' then | ||
| src.scan(/\s*/) | ||
| [:tAWORDS_BEG, STR_SQUOTE | STR_FUNC_AWORDS] | ||
| [:tQWORDS_BEG, STR_SQUOTE | STR_FUNC_QWORDS] | ||
| when 'x' then | ||
@@ -350,3 +355,3 @@ [:tXSTRING_BEG, STR_XQUOTE] | ||
| awords = (func & STR_FUNC_AWORDS) != 0 | ||
| qwords = (func & STR_FUNC_QWORDS) != 0 | ||
| regexp = (func & STR_FUNC_REGEXP) != 0 | ||
@@ -360,6 +365,6 @@ expand = (func & STR_FUNC_EXPAND) != 0 | ||
| space = true if awords and src.scan(/\s+/) | ||
| space = true if qwords and src.scan(/\s+/) | ||
| if self.nest == 0 && src.scan(/#{term_re}/) then | ||
| if awords then | ||
| if qwords then | ||
| quote[1] = nil | ||
@@ -487,2 +492,6 @@ return :tSPACE | ||
| def ruby18 | ||
| Ruby18Parser === parser | ||
| end | ||
| def src= src | ||
@@ -514,3 +523,3 @@ raise "bad src: #{src.inspect}" unless String === src | ||
| def tokadd_string(func, term, paren) # 105 lines | ||
| awords = (func & STR_FUNC_AWORDS) != 0 | ||
| qwords = (func & STR_FUNC_QWORDS) != 0 | ||
| escape = (func & STR_FUNC_ESCAPE) != 0 | ||
@@ -535,3 +544,3 @@ expand = (func & STR_FUNC_EXPAND) != 0 | ||
| self.nest -= 1 | ||
| when awords && src.scan(/\s/) then | ||
| when qwords && src.scan(/\s/) then | ||
| src.pos -= 1 | ||
@@ -546,6 +555,6 @@ break | ||
| case | ||
| when awords && src.scan(/\\\n/) then | ||
| when qwords && src.scan(/\\\n/) then | ||
| string_buffer << "\n" | ||
| next | ||
| when awords && src.scan(/\\\s/) then | ||
| when qwords && src.scan(/\\\s/) then | ||
| c = ' ' | ||
@@ -579,3 +588,3 @@ when expand && src.scan(/\\\n/) then | ||
| x = Regexp.escape(paren) if paren && paren != "\000" | ||
| re = if awords then | ||
| re = if qwords then | ||
| /[^#{t}#{x}\#\0\\\n\ ]+|./ # |. to pick up whatever | ||
@@ -649,3 +658,2 @@ else | ||
| def yylex # 826 lines | ||
| c = '' | ||
@@ -707,2 +715,3 @@ space_seen = false | ||
| }[src.matched] | ||
| self.tern.lexpop if [:tRBRACK, :tRCURLY].include?(result) | ||
| return result | ||
@@ -722,16 +731,8 @@ elsif src.scan(/\.\.\.?|,|![=~]?/) then | ||
| elsif src.scan(/\(/) then | ||
| result = :tLPAREN2 | ||
| self.command_start = true | ||
| result = if ruby18 then | ||
| yylex_paren18 space_seen | ||
| else | ||
| yylex_paren19 space_seen | ||
| end | ||
| if lex_state == :expr_beg || lex_state == :expr_mid then | ||
| result = :tLPAREN | ||
| elsif space_seen then | ||
| if lex_state == :expr_cmdarg then | ||
| result = :tLPAREN_ARG | ||
| elsif lex_state == :expr_arg then | ||
| warning("don't put space before argument parentheses") | ||
| result = :tLPAREN2 | ||
| end | ||
| end | ||
| self.expr_beg_push "(" | ||
@@ -829,5 +830,9 @@ | ||
| elsif lex_state == :expr_beg || lex_state == :expr_mid then | ||
| self.tern.push false | ||
| result = :tLBRACK | ||
| elsif lex_state.is_argument && space_seen then | ||
| self.tern.push false | ||
| result = :tLBRACK | ||
| else | ||
| result = :tLBRACK2 | ||
| end | ||
@@ -861,2 +866,8 @@ | ||
| elsif src.scan(/\{/) then | ||
| if defined?(@hack_expects_lambda) && @hack_expects_lambda | ||
| @hack_expects_lambda = false | ||
| self.lex_state = :expr_beg | ||
| return :tLAMBEG | ||
| end | ||
| result = if lex_state.is_argument || lex_state == :expr_end then | ||
@@ -867,2 +878,3 @@ :tLCURLY # block (primary) | ||
| else | ||
| self.tern.push false | ||
| :tLBRACE # hash | ||
@@ -875,2 +887,6 @@ end | ||
| return result | ||
| elsif src.scan(/->/) then | ||
| @hack_expects_lambda = true | ||
| self.lex_state = :expr_arg | ||
| return :tLAMBDA | ||
| elsif src.scan(/[+-]/) then | ||
@@ -1021,2 +1037,3 @@ sign = src.matched | ||
| self.lex_state = :expr_beg | ||
| self.tern.push true | ||
| self.yacc_value = "?" | ||
@@ -1046,2 +1063,3 @@ return :tEH | ||
| self.lex_state = :expr_beg | ||
| self.tern.push true | ||
| self.yacc_value = "?" | ||
@@ -1051,2 +1069,3 @@ return :tEH | ||
| self.lex_state = :expr_beg | ||
| self.tern.push true | ||
| self.yacc_value = "?" | ||
@@ -1062,4 +1081,10 @@ return :tEH | ||
| self.lex_state = :expr_end | ||
| self.yacc_value = c[0].ord & 0xff | ||
| return :tINTEGER | ||
| if version == 18 then | ||
| self.yacc_value = c[0].ord & 0xff | ||
| return :tINTEGER | ||
| else | ||
| self.yacc_value = c | ||
| return :tSTRING | ||
| end | ||
| elsif src.check(/\&/) then | ||
@@ -1238,2 +1263,49 @@ if src.scan(/\&\&\=/) then | ||
| def yylex_paren18 space_seen | ||
| self.command_start = true | ||
| result = :tLPAREN2 | ||
| if lex_state == :expr_beg || lex_state == :expr_mid then | ||
| result = :tLPAREN | ||
| elsif space_seen then | ||
| if lex_state == :expr_cmdarg then | ||
| result = :tLPAREN_ARG | ||
| elsif lex_state == :expr_arg then | ||
| self.tern.push false | ||
| warning "don't put space before argument parentheses" | ||
| end | ||
| else | ||
| self.tern.push false | ||
| end | ||
| result | ||
| end | ||
| def yylex_paren19 space_seen | ||
| if (lex_state == :expr_beg || lex_state == :expr_mid || | ||
| lex_state == :expr_value || lex_state == :expr_class) then | ||
| result = :tLPAREN | ||
| elsif ((lex_state == :expr_arg || lex_state == :expr_cmdarg) and | ||
| space_seen) then | ||
| result = :tLPAREN_ARG | ||
| else | ||
| self.tern.push false | ||
| result = :tLPAREN2 | ||
| end | ||
| # HACK paren_nest++; | ||
| # HACK: this is a mess, but it makes the tests pass, so suck it | ||
| # (stolen from the 1.8 side) | ||
| if lex_state == :expr_beg || lex_state == :expr_mid then | ||
| # do nothing | ||
| elsif space_seen then | ||
| if lex_state == :expr_arg then | ||
| self.tern.push false | ||
| end | ||
| else | ||
| self.tern.push false | ||
| end | ||
| result | ||
| end | ||
| def process_token(command_state) | ||
@@ -1246,3 +1318,2 @@ | ||
| case token | ||
@@ -1275,2 +1346,20 @@ when /^\$/ then | ||
| unless self.tern.is_in_state | ||
| if (lex_state == :expr_beg && (ruby18 || !command_state)) || | ||
| lex_state == :expr_arg || | ||
| lex_state == :expr_cmdarg then | ||
| colon = src.scan(/:/) | ||
| if colon && src.peek(1) != ":" | ||
| src.unscan | ||
| self.lex_state = :expr_beg | ||
| src.scan(/:/) | ||
| self.yacc_value = [token, src.lineno] | ||
| return :tLABEL | ||
| end | ||
| src.unscan if colon | ||
| end | ||
| end unless ruby18 | ||
| unless lex_state == :expr_dot then | ||
@@ -1295,2 +1384,6 @@ # See if it is a reserved word. | ||
| return :kDO_BLOCK if state == :expr_endarg | ||
| if defined?(@hack_expects_lambda) && @hack_expects_lambda | ||
| @hack_expects_lambda = false | ||
| return :kDO_LAMBDA | ||
| end | ||
| return :kDO | ||
@@ -1297,0 +1390,0 @@ end |
+195
-48
@@ -6,6 +6,11 @@ require 'stringio' | ||
| def d o | ||
| $stderr.puts o.inspect | ||
| end | ||
| # WHY do I have to do this?!? | ||
| class Regexp | ||
| unless defined? ONCE then | ||
| ONCE = 0 # 16 # ? | ||
| ONCE = 0 unless defined? ONCE # FIX: remove this - it makes no sense | ||
| unless defined? ENC_NONE then | ||
| ENC_NONE = /x/n.options | ||
@@ -51,7 +56,2 @@ ENC_EUC = /x/e.options | ||
| # TODO: current_line and lineno much more accurate and easy to do | ||
| def unread c # TODO: remove this entirely - we should not need it | ||
| return if c.nil? # UGH | ||
| warn({:unread => caller[0]}.inspect) if ENV['TALLY'] | ||
| string[pos, 0] = c | ||
| end | ||
@@ -64,10 +64,2 @@ def unread_many str # TODO: remove this entirely - we should not need it | ||
| def begin_of_line? | ||
| pos == 0 or string[pos-1] == ?\n | ||
| end | ||
| def was_begin_of_line # TODO: kill me | ||
| pos <= 2 or string[pos-2] == ?\n | ||
| end | ||
| if ENV['DEBUG'] then | ||
@@ -84,3 +76,3 @@ alias :old_getch :getch | ||
| s = old_scan re | ||
| p :scan => [s, caller.first] if s | ||
| d :scan => [s, caller.first] if s | ||
| s | ||
@@ -129,4 +121,4 @@ end | ||
| class RubyParser < Racc::Parser | ||
| VERSION = '2.3.1' unless constants.include? "VERSION" # SIGH | ||
| module RubyParserStuff | ||
| VERSION = '3.0.0.a1' unless constants.include? "VERSION" # SIGH | ||
@@ -157,3 +149,28 @@ attr_accessor :lexer, :in_def, :in_single, :file | ||
| def args arg, optarg, rest_arg, block_arg | ||
| def block_var ary, splat, block | ||
| ary ||= s(:array) | ||
| if splat then | ||
| if splat == s(:splat) then | ||
| ary << splat | ||
| else | ||
| ary << s(:splat, splat) | ||
| end | ||
| end | ||
| if block then | ||
| block[-1] = :"&#{block[-1]}" | ||
| ary << block | ||
| end | ||
| result = if ary.length > 2 or ary.splat then | ||
| s(:masgn, ary) | ||
| else | ||
| ary.last | ||
| end | ||
| result | ||
| end | ||
| def args arg, optarg, rest_arg, block_arg, post_arg = nil | ||
| arg ||= s(:args) | ||
@@ -170,4 +187,6 @@ | ||
| result << rest_arg if rest_arg | ||
| result << :"&#{block_arg.last}" if block_arg | ||
| result << optarg if optarg # TODO? huh - processed above as well | ||
| post_arg[1..-1].each {|pa| result << pa } if post_arg | ||
@@ -177,5 +196,41 @@ result | ||
| def args19 vals # TODO: migrate to args once 1.8 tests pass as well | ||
| result = s(:args) | ||
| block = nil | ||
| vals.each do |val| | ||
| case val | ||
| when Sexp then | ||
| case val.first | ||
| when :args then | ||
| val[1..-1].each do |name| | ||
| result << name | ||
| end | ||
| when :block_arg then | ||
| result << :"&#{val.last}" | ||
| when :block then | ||
| block = val | ||
| val[1..-1].each do |lasgn| # FIX clean sexp iter | ||
| raise "wtf? #{val.inspect}" unless lasgn[0] == :lasgn | ||
| result << lasgn[1] | ||
| end | ||
| else | ||
| raise "unhandled sexp: #{val.inspect}" | ||
| end | ||
| when Symbol then | ||
| result << val | ||
| when ",", nil then | ||
| # ignore | ||
| else | ||
| raise "unhandled val: #{val.inspect} in #{vals.inspect}" | ||
| end | ||
| end | ||
| result << block if block | ||
| result | ||
| end | ||
| def aryset receiver, index | ||
| index[0] = :arglist if index[0] == :array | ||
| s(:attrasgn, receiver, :"[]=", index) | ||
| s(:attrasgn, receiver, :"[]=", *index[1..-1]) | ||
| end | ||
@@ -299,3 +354,3 @@ | ||
| return s(:call, lhs, :"=~", s(:arglist, rhs)).line(lhs.line) | ||
| return new_call(lhs, :"=~", argl(rhs)).line(lhs.line) | ||
| end | ||
@@ -319,6 +374,4 @@ | ||
| s(type, id) | ||
| elsif env.dynamic? and :dvar == env[id] then | ||
| s(:lvar, id) | ||
| else | ||
| s(:call, nil, id, s(:arglist)) | ||
| new_call(nil, id) | ||
| end | ||
@@ -345,3 +398,5 @@ end | ||
| super() | ||
| self.lexer = RubyLexer.new | ||
| v = self.class.name[/1[89]/] | ||
| self.lexer = RubyLexer.new v && v.to_i | ||
| self.lexer.parser = self | ||
@@ -467,2 +522,19 @@ @env = Environment.new | ||
| def argl x | ||
| x = s(:arglist, x) if x and x[0] != :arglist | ||
| x | ||
| end | ||
| def backref_assign_error ref | ||
| # TODO: need a test for this... obviously | ||
| case ref.first | ||
| when :nth_ref then | ||
| raise SyntaxError, "Can't set variable %p" % ref.last | ||
| when :back_ref then | ||
| raise SyntaxError, "Can't set back reference %p" % ref.last | ||
| else | ||
| raise "Unknown backref type: #{ref.inspect}" | ||
| end | ||
| end | ||
| def new_call recv, meth, args = nil | ||
@@ -472,6 +544,12 @@ result = s(:call, recv, meth) | ||
| # TODO: need a test with f(&b) to produce block_pass | ||
| # TODO: need a test with f(&b) { } to produce warning | ||
| args ||= s(:arglist) | ||
| args[0] = :arglist if args.first == :array | ||
| args = s(:arglist, args) unless args.first == :arglist | ||
| result << args | ||
| # HACK quick hack to make this work quickly... easy to clean up above | ||
| result.concat args[1..-1] | ||
| result | ||
@@ -489,2 +567,7 @@ end | ||
| result[2..-1].each do |node| | ||
| block = node.block(:delete) | ||
| node.concat block[1..-1] if block | ||
| end | ||
| # else | ||
@@ -500,4 +583,13 @@ body = nil if body == s(:block) | ||
| line, path, superclass, body = val[1], val[2], val[3], val[5] | ||
| scope = s(:scope, body).compact | ||
| result = s(:class, path, superclass, scope) | ||
| result = s(:class, path, superclass) | ||
| if body then | ||
| if body.first == :block then | ||
| result.push(*body[1..-1]) | ||
| else | ||
| result.push body | ||
| end | ||
| end | ||
| result.line = line | ||
@@ -518,6 +610,12 @@ result.comments = self.comments.pop | ||
| body ||= s(:block) | ||
| body = s(:block, body) unless body.first == :block | ||
| result = s(:defn, name.to_sym, args) | ||
| result = s(:defn, name.to_sym, args, s(:scope, body)) | ||
| if body then | ||
| if body.first == :block then | ||
| result.push(*body[1..-1]) | ||
| else | ||
| result.push body | ||
| end | ||
| end | ||
| result.line = line | ||
@@ -531,6 +629,12 @@ result.comments = self.comments.pop | ||
| body ||= s(:block) | ||
| body = s(:block, body) unless body.first == :block | ||
| result = s(:defs, recv, name.to_sym, args) | ||
| result = s(:defs, recv, name.to_sym, args, s(:scope, body)) | ||
| if body then | ||
| if body.first == :block then | ||
| result.push(*body[1..-1]) | ||
| else | ||
| result.push body | ||
| end | ||
| end | ||
| result.line = recv.line | ||
@@ -575,3 +679,3 @@ result.comments = self.comments.pop | ||
| body = s(:scope, body).compact | ||
| result = s(:module, path, body) | ||
| result = s(:module, path, *body[1..-1]) | ||
| result.line = line | ||
@@ -595,4 +699,3 @@ result.comments = self.comments.pop | ||
| # TODO: why [2] ? | ||
| lhs[2] = new_call(self.gettable(name), asgn_op, | ||
| s(:arglist, arg)) | ||
| lhs[2] = new_call(self.gettable(name), asgn_op, argl(arg)) | ||
| lhs | ||
@@ -649,6 +752,24 @@ end | ||
| def new_resbody cond, body | ||
| if body && body.first == :block then | ||
| body.shift # remove block and splat it in directly | ||
| else | ||
| body = [body] | ||
| end | ||
| s(:resbody, cond, *body) | ||
| end | ||
| def new_sclass val | ||
| recv, in_def, in_single, body = val[3], val[4], val[6], val[7] | ||
| scope = s(:scope, body).compact | ||
| result = s(:sclass, recv, scope) | ||
| result = s(:sclass, recv) | ||
| if body then | ||
| if body.first == :block then | ||
| result.push(*body[1..-1]) | ||
| else | ||
| result.push body | ||
| end | ||
| end | ||
| result.line = val[2] | ||
@@ -677,2 +798,6 @@ self.in_def = in_def | ||
| def new_until block, expr, pre | ||
| new_until_or_while :until, block, expr, pre | ||
| end | ||
| def new_until_or_while type, block, expr, pre | ||
@@ -695,4 +820,4 @@ other = type == :until ? :while : :until | ||
| def new_until block, expr, pre | ||
| new_until_or_while :until, block, expr, pre | ||
| def new_when cond, body | ||
| s(:when, cond, body) | ||
| end | ||
@@ -748,8 +873,7 @@ | ||
| case lhs[0] | ||
| when :gasgn, :iasgn, :lasgn, :dasgn, :dasgn_curr, | ||
| :masgn, :cdecl, :cvdecl, :cvasgn then | ||
| when :gasgn, :iasgn, :lasgn, :masgn, :cdecl, :cvdecl, :cvasgn then | ||
| lhs << rhs | ||
| when :attrasgn, :call then | ||
| args = lhs.pop unless Symbol === lhs.last | ||
| lhs << arg_add(args, rhs) | ||
| lhs.concat arg_add(args, rhs)[1..-1] | ||
| when :const then | ||
@@ -769,3 +893,3 @@ lhs[0] = :cdecl | ||
| self.file = file | ||
| self.lexer.src = str | ||
| self.lexer.src = str.dup | ||
@@ -836,6 +960,5 @@ @yydebug = ENV.has_key? 'DEBUG' | ||
| alias :old_yyerror :yyerror | ||
| def yyerror msg | ||
| # for now do nothing with the msg | ||
| old_yyerror | ||
| super | ||
| end | ||
@@ -1026,2 +1149,18 @@ | ||
| class Ruby19Parser < Racc::Parser | ||
| include RubyParserStuff | ||
| end | ||
| class Ruby18Parser < Racc::Parser | ||
| include RubyParserStuff | ||
| end | ||
| class RubyParser < Ruby18Parser | ||
| def initialize | ||
| super | ||
| warn "WA\RNING: Deprecated: RubyParser. Use Ruby18Parser or Ruby19Parser" | ||
| warn " from #{caller.first}" | ||
| end | ||
| end | ||
| ############################################################ | ||
@@ -1052,2 +1191,10 @@ # HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK | ||
| def add x | ||
| raise "no" # TODO: need a test to trigger this | ||
| end | ||
| def add_all x | ||
| raise "no" # TODO: need a test to trigger this | ||
| end | ||
| alias :node_type :sexp_type | ||
@@ -1054,0 +1201,0 @@ alias :values :sexp_body # TODO: retire |
+5
-1
@@ -7,5 +7,9 @@ .autotest | ||
| bin/ruby_parse | ||
| bin/ruby_parse_extract_error | ||
| lib/gauntlet_rubyparser.rb | ||
| lib/ruby18_parser.rb | ||
| lib/ruby18_parser.y | ||
| lib/ruby19_parser.rb | ||
| lib/ruby19_parser.y | ||
| lib/ruby_lexer.rb | ||
| lib/ruby_parser.y | ||
| lib/ruby_parser.rb | ||
@@ -12,0 +16,0 @@ lib/ruby_parser_extras.rb |
+65
-1
@@ -19,3 +19,6 @@ # -*- ruby -*- | ||
| self.perforce_ignore << "lib/ruby_parser.rb" if plugin? :perforce | ||
| if plugin? :perforce then | ||
| self.perforce_ignore << "lib/ruby18_parser.rb" | ||
| self.perforce_ignore << "lib/ruby19_parser.rb" | ||
| end | ||
@@ -25,2 +28,5 @@ self.racc_flags << " -g" if plugin?(:racc) && ENV["DEBUG"] | ||
| file "lib/ruby18_parser.rb" => "lib/ruby18_parser.y" | ||
| file "lib/ruby19_parser.rb" => "lib/ruby19_parser.y" | ||
| task :clean do | ||
@@ -112,2 +118,60 @@ rm_rf(Dir["**/*~"] + | ||
| def (task(:phony)).timestamp | ||
| Time.at 0 | ||
| end | ||
| task :isolate => :phony | ||
| file "lib/ruby18_parser.rb" => :isolate | ||
| file "lib/ruby19_parser.rb" => :isolate | ||
| task :compare18 do | ||
| sh "./yack.rb lib/ruby18_parser.output > racc18.txt" | ||
| sh "./yack.rb parse18.output > yacc18.txt" | ||
| sh "diff -du racc18.txt yacc18.txt || true" | ||
| puts | ||
| sh "diff -du racc18.txt yacc18.txt | wc -l" | ||
| end | ||
| task :compare19 do | ||
| sh "./yack.rb lib/ruby19_parser.output > racc19.txt" | ||
| sh "./yack.rb parse19.output > yacc19.txt" | ||
| sh "diff -du racc19.txt yacc19.txt || true" | ||
| puts | ||
| sh "diff -du racc19.txt yacc19.txt | wc -l" | ||
| end | ||
| task :debug => :isolate do | ||
| ENV["V"] ||= "18" | ||
| Rake.application[:parser].invoke # this way we can have DEBUG set | ||
| $: << "lib" | ||
| require 'ruby_parser' | ||
| parser = if ENV["V"] == "18" then | ||
| Ruby18Parser.new | ||
| else | ||
| Ruby19Parser.new | ||
| end | ||
| file = ENV["F"] || ENV["FILE"] | ||
| ruby = if file then | ||
| File.read(file) | ||
| else | ||
| file = "env" | ||
| ENV["R"] || ENV["RUBY"] | ||
| end | ||
| begin | ||
| p parser.process(ruby, file) | ||
| rescue Racc::ParseError => e | ||
| p e | ||
| ss = parser.lexer.src | ||
| src = ss.string | ||
| lines = src[0..ss.pos].split(/\n/) | ||
| abort "on #{file}:#{lines.size}" | ||
| end | ||
| end | ||
| # vim: syntax=Ruby |
+5
-5
| = ruby_parser | ||
| home :: https://github.com/seattlerb/ruby_parser | ||
| bugs :: https://github.com/seattlerb/ruby_parser/issues | ||
| rdoc :: http://docs.seattlerb.org/ruby_parser | ||
@@ -50,4 +51,4 @@ | ||
| RubyParser.new.parse "1+1" | ||
| # => s(:call, s(:lit, 1), :+, s(:array, s(:lit, 1))) | ||
| Ruby19Parser.new.parse "1+1" | ||
| # => s(:call, s(:lit, 1), :+, s(:lit, 1)) | ||
@@ -57,4 +58,3 @@ == REQUIREMENTS: | ||
| * ruby. woot. | ||
| * sexp_processor for Sexp and SexpProcessor classes. | ||
| * ParseTree for testing. | ||
| * sexp_processor for Sexp and SexpProcessor classes, and testing. | ||
| * racc full package for parser development (compiling .y to .rb). | ||
@@ -70,3 +70,3 @@ | ||
| Copyright (c) 2007-2008 Ryan Davis | ||
| Copyright (c) Ryan Davis, seattle.rb | ||
@@ -73,0 +73,0 @@ Permission is hereby granted, free of charge, to any person obtaining |
+94
-15
| #!/usr/local/bin/ruby | ||
| require 'rubygems' | ||
| gem "minitest" | ||
| require 'minitest/autorun' | ||
| require 'ruby_lexer' | ||
| require 'ruby_parser' | ||
| require 'ruby18_parser' | ||
@@ -12,3 +14,7 @@ class TestRubyLexer < MiniTest::Unit::TestCase | ||
| def setup | ||
| p = RubyParser.new | ||
| setup_lexer Ruby18Parser | ||
| end | ||
| def setup_lexer parser_class | ||
| p = parser_class.new | ||
| @lex = p.lexer | ||
@@ -129,2 +135,34 @@ @lex.src = "blah blah" | ||
| def test_yylex_label__18 | ||
| util_lex_token("{a:", | ||
| :tLBRACE, "{", | ||
| :tIDENTIFIER, "a", | ||
| :tSYMBEG, ":") | ||
| end | ||
| def test_yylex_label_in_params__18 | ||
| util_lex_token("foo(a:", | ||
| :tIDENTIFIER, "foo", | ||
| :tLPAREN2, "(", | ||
| :tIDENTIFIER, "a", | ||
| :tSYMBEG, ":") | ||
| end | ||
| def test_yylex_label__19 | ||
| setup_lexer Ruby19Parser | ||
| util_lex_token("{a:", | ||
| :tLBRACE, "{", | ||
| :tLABEL, "a") | ||
| end | ||
| def test_yylex_label_in_params__19 | ||
| setup_lexer Ruby19Parser | ||
| util_lex_token("foo(a:", | ||
| :tIDENTIFIER, "foo", | ||
| :tLPAREN2, "(", | ||
| :tLABEL, "a") | ||
| end | ||
| def test_yylex_back_ref | ||
@@ -615,3 +653,2 @@ util_lex_token("[$&, $`, $', $+]", | ||
| :tSTRING_CONTENT, "blah\nblah\n", | ||
| :tSTRING_CONTENT, "", | ||
| :tSTRING_END, "EOF", | ||
@@ -634,3 +671,2 @@ :tNL, nil) | ||
| :tSTRING_CONTENT, "blah\nblah\n", | ||
| :tSTRING_CONTENT, "", | ||
| :tSTRING_END, "EOF", | ||
@@ -812,10 +848,26 @@ :tNL, nil) | ||
| def test_yylex_integer_eh_a | ||
| util_lex_token '?a', :tINTEGER, 97 | ||
| def test_yylex_question_eh_a__18 | ||
| @lex = RubyLexer.new 18 | ||
| util_lex_token "?a", :tINTEGER, 97 | ||
| end | ||
| def test_yylex_integer_eh_escape_M_escape_C | ||
| def test_yylex_question_eh_a__19 | ||
| @lex = RubyLexer.new 19 | ||
| util_lex_token '?a', :tSTRING, "a" | ||
| end | ||
| def test_yylex_question_eh_escape_M_escape_C__18 | ||
| @lex = RubyLexer.new 18 | ||
| util_lex_token '?\M-\C-a', :tINTEGER, 129 | ||
| end | ||
| def test_yylex_question_eh_escape_M_escape_C__19 | ||
| @lex = RubyLexer.new 19 | ||
| util_lex_token '?\M-\C-a', :tSTRING, "\M-\C-a" | ||
| end | ||
| def test_yylex_integer_hex | ||
@@ -1036,3 +1088,3 @@ util_lex_token "0x2a", :tINTEGER, 42 | ||
| :tIDENTIFIER, "m", | ||
| "[", "[", | ||
| :tLBRACK2, "[", | ||
| :tINTEGER, 3, | ||
@@ -1098,6 +1150,14 @@ :tRBRACK, "]") | ||
| def test_yylex_question | ||
| def test_yylex_question__18 | ||
| @lex = RubyLexer.new 18 | ||
| util_lex_token "?*", :tINTEGER, 42 | ||
| end | ||
| def test_yylex_question__19 | ||
| @lex = RubyLexer.new 19 | ||
| util_lex_token "?*", :tSTRING, "*" | ||
| end | ||
| def test_yylex_question_bad_eos | ||
@@ -1116,3 +1176,5 @@ util_bad_token "?" | ||
| def test_yylex_question_ws_backslashed | ||
| def test_yylex_question_ws_backslashed__18 | ||
| @lex = RubyLexer.new 18 | ||
| @lex.lex_state = :expr_beg | ||
@@ -1132,2 +1194,19 @@ util_lex_token "?\\ ", :tINTEGER, 32 | ||
| def test_yylex_question_ws_backslashed__19 | ||
| @lex = RubyLexer.new 19 | ||
| @lex.lex_state = :expr_beg | ||
| util_lex_token "?\\ ", :tSTRING, " " | ||
| @lex.lex_state = :expr_beg | ||
| util_lex_token "?\\n", :tSTRING, "\n" | ||
| @lex.lex_state = :expr_beg | ||
| util_lex_token "?\\t", :tSTRING, "\t" | ||
| @lex.lex_state = :expr_beg | ||
| util_lex_token "?\\v", :tSTRING, "\v" | ||
| @lex.lex_state = :expr_beg | ||
| util_lex_token "?\\r", :tSTRING, "\r" | ||
| @lex.lex_state = :expr_beg | ||
| util_lex_token "?\\f", :tSTRING, "\f" | ||
| end | ||
| def test_yylex_rbracket | ||
@@ -1626,3 +1705,3 @@ util_lex_token "]", :tRBRACK, "]" | ||
| util_bad_token("%w[s1 s2 ", | ||
| :tAWORDS_BEG, "%w[", | ||
| :tQWORDS_BEG, "%w[", | ||
| :tSTRING_CONTENT, "s1", | ||
@@ -1636,3 +1715,3 @@ :tSPACE, nil, | ||
| util_lex_token("%w[s1 \\\ns2]", | ||
| :tAWORDS_BEG, "%w[", | ||
| :tQWORDS_BEG, "%w[", | ||
| :tSTRING_CONTENT, "s1", | ||
@@ -1647,3 +1726,3 @@ :tSPACE, nil, | ||
| util_lex_token("%w[s\\ 1 s\\ 2]", | ||
| :tAWORDS_BEG, "%w[", | ||
| :tQWORDS_BEG, "%w[", | ||
| :tSTRING_CONTENT, "s 1", | ||
@@ -1658,3 +1737,3 @@ :tSPACE, nil, | ||
| util_lex_token("%w[abc\tdef]", | ||
| :tAWORDS_BEG, "%w[", | ||
| :tQWORDS_BEG, "%w[", | ||
| :tSTRING_CONTENT, "abc\tdef", | ||
@@ -1836,3 +1915,3 @@ :tSPACE, nil, | ||
| assert @lex.advance, "no more tokens" | ||
| assert_equal [token, value], [@lex.token, [@lex.yacc_value].flatten.first] | ||
| assert_equal [token, value], [@lex.token, [@lex.yacc_value].flatten.first], input | ||
| end | ||
@@ -1839,0 +1918,0 @@ |
| require 'rubygems' | ||
| gem "minitest" | ||
| require 'minitest/autorun' | ||
| require 'ruby_parser_extras' | ||
| require 'minitest/unit' | ||
| class TestStackState < MiniTest::Unit::TestCase | ||
@@ -6,0 +9,0 @@ attr_reader :s |
+134
-80
@@ -6,2 +6,3 @@ #!/usr/local/bin/ruby | ||
| require 'rubygems' | ||
| gem "minitest" | ||
| require 'minitest/autorun' | ||
@@ -14,3 +15,3 @@ require 'ruby_parser' | ||
| class RubyParser | ||
| class Ruby18Parser # FIX | ||
| def process input | ||
@@ -21,3 +22,11 @@ parse input | ||
| class Ruby19Parser | ||
| def process input | ||
| parse input | ||
| end | ||
| end | ||
| class RubyParserTestCase < ParseTreeTestCase | ||
| attr_accessor :result, :processor | ||
| def self.previous key | ||
@@ -35,13 +44,3 @@ "Ruby" | ||
| end | ||
| end | ||
| class TestRubyParser < RubyParserTestCase | ||
| attr_accessor :result, :processor | ||
| def setup | ||
| super | ||
| self.processor = RubyParser.new | ||
| end | ||
| def assert_parse rb, pt | ||
@@ -56,3 +55,5 @@ self.result = processor.parse rb | ||
| end | ||
| end | ||
| module TestRubyParser | ||
| def test_attrasgn_array_lhs | ||
@@ -63,7 +64,6 @@ rb = '[1, 2, 3, 4][from .. to] = ["a", "b", "c"]' | ||
| :[]=, | ||
| s(:arglist, | ||
| s(:dot2, | ||
| s(:call, nil, :from, s(:arglist)), | ||
| s(:call, nil, :to, s(:arglist))), | ||
| s(:array, s(:str, "a"), s(:str, "b"), s(:str, "c")))) | ||
| s(:dot2, | ||
| s(:call, nil, :from), | ||
| s(:call, nil, :to)), | ||
| s(:array, s(:str, "a"), s(:str, "b"), s(:str, "c"))) | ||
@@ -109,6 +109,6 @@ assert_parse rb, pt | ||
| def test_block_append_tail_block | ||
| head = s(:call, nil, :f1, s(:arglist)) | ||
| head = s(:call, nil, :f1) | ||
| tail = s(:block, s(:undef, s(:lit, :x)), s(:undef, s(:lit, :y))) | ||
| expected = s(:block, | ||
| s(:call, nil, :f1, s(:arglist)), | ||
| s(:call, nil, :f1), | ||
| s(:block, s(:undef, s(:lit, :x)), s(:undef, s(:lit, :y)))) | ||
@@ -118,6 +118,13 @@ assert_equal expected, processor.block_append(head, tail) | ||
| def test_call_array_arg | ||
| rb = "1 == [:b, :c]" | ||
| pt = s(:call, s(:lit, 1), :==, s(:array, s(:lit, :b), s(:lit, :c))) | ||
| assert_parse rb, pt | ||
| end | ||
| def test_call_env | ||
| processor.env[:a] = :lvar | ||
| rb = "a.happy" | ||
| pt = s(:call, s(:lvar, :a), :happy, s(:arglist)) | ||
| pt = s(:call, s(:lvar, :a), :happy) | ||
@@ -130,3 +137,3 @@ assert_parse rb, pt | ||
| pt = s(:iter, | ||
| s(:call, nil, :a, s(:arglist)), | ||
| s(:call, nil, :a), | ||
| nil, | ||
@@ -147,4 +154,3 @@ s(:block, | ||
| pt = s(:class, :X, nil, | ||
| s(:scope, | ||
| s(:defn, :blah, s(:args), s(:scope, s(:block, s(:nil)))))) | ||
| s(:defn, :blah, s(:args), s(:nil))) | ||
@@ -154,3 +160,3 @@ assert_parse rb, pt | ||
| assert_equal "# blah 1\n# blah 2\n\n", result.comments | ||
| assert_equal "# blah 3\n", result.scope.defn.comments | ||
| assert_equal "# blah 3\n", result.defn.comments | ||
| end | ||
@@ -161,8 +167,7 @@ | ||
| pt = s(:module, :X, | ||
| s(:scope, | ||
| s(:defn, :blah, s(:args), s(:scope, s(:block, s(:nil)))))) | ||
| s(:defn, :blah, s(:args), s(:nil))) | ||
| assert_parse rb, pt | ||
| assert_equal "# blah 1\n\n# blah 2\n\n", result.comments | ||
| assert_equal "# blah 3\n", result.scope.defn.comments | ||
| assert_equal "# blah 3\n", result.defn.comments | ||
| end | ||
@@ -172,3 +177,3 @@ | ||
| rb = "# blah 1\n# blah 2\n\ndef blah\nend" | ||
| pt = s(:defn, :blah, s(:args), s(:scope, s(:block, s(:nil)))) | ||
| pt = s(:defn, :blah, s(:args), s(:nil)) | ||
@@ -181,3 +186,3 @@ assert_parse rb, pt | ||
| rb = "# blah 1\n# blah 2\n\ndef self.blah\nend" | ||
| pt = s(:defs, s(:self), :blah, s(:args), s(:scope, s(:block))) | ||
| pt = s(:defs, s(:self), :blah, s(:args)) | ||
@@ -191,5 +196,5 @@ assert_parse rb, pt | ||
| pt = s(:block, | ||
| s(:call, nil, :a, s(:arglist, s(:lit, 1))), | ||
| s(:call, nil, :a, s(:lit, 1)), | ||
| s(:iter, | ||
| s(:call, s(:call, nil, :a, s(:arglist)), :b, s(:arglist)), | ||
| s(:call, s(:call, nil, :a), :b), | ||
| s(:lasgn, :c))) | ||
@@ -211,3 +216,3 @@ | ||
| rb = 'g ( 1), 2' | ||
| pt = s(:call, nil, :g, s(:arglist, s(:lit, 1), s(:lit, 2))) | ||
| pt = s(:call, nil, :g, s(:lit, 1), s(:lit, 2)) | ||
@@ -223,7 +228,3 @@ assert_parse rb, pt | ||
| pt = s(:defn, :f, s(:args), | ||
| s(:scope, | ||
| s(:block, | ||
| s(:call, nil, :g, | ||
| s(:arglist, | ||
| s(:lit, 1), s(:lit, 2)))))) | ||
| s(:call, nil, :g, s(:lit, 1), s(:lit, 2))) | ||
@@ -243,3 +244,3 @@ assert_parse rb, pt | ||
| rb = "\"#\{'a'}#\{b}\"" | ||
| pt = s(:dstr, "a", s(:evstr, s(:call, nil, :b, s(:arglist)))) | ||
| pt = s(:dstr, "a", s(:evstr, s(:call, nil, :b))) | ||
@@ -265,3 +266,3 @@ assert_parse rb, pt | ||
| rb = "\"#\{a}#\{b}\"" | ||
| pt = s(:dstr, "", s(:evstr, s(:call, nil, :a, s(:arglist))), s(:evstr, s(:call, nil, :b, s(:arglist)))) | ||
| pt = s(:dstr, "", s(:evstr, s(:call, nil, :a)), s(:evstr, s(:call, nil, :b))) | ||
@@ -273,3 +274,3 @@ assert_parse rb, pt | ||
| rb = "\"#\{a} b\"" | ||
| pt = s(:dstr, "", s(:evstr, s(:call, nil, :a, s(:arglist))), s(:str, " b")) | ||
| pt = s(:dstr, "", s(:evstr, s(:call, nil, :a)), s(:str, " b")) | ||
@@ -331,5 +332,5 @@ assert_parse rb, pt | ||
| lhs = s(:dstr, "Failed to download spec ", | ||
| s(:evstr, s(:call, nil, :spec_name, s(:arglist))), | ||
| s(:evstr, s(:call, nil, :spec_name)), | ||
| s(:str, " from "), | ||
| s(:evstr, s(:call, nil, :source_uri, s(:arglist))), | ||
| s(:evstr, s(:call, nil, :source_uri)), | ||
| s(:str, ":\n")) | ||
@@ -339,5 +340,5 @@ rhs = s(:dstr, "\t", | ||
| expected = s(:dstr, "Failed to download spec ", | ||
| s(:evstr, s(:call, nil, :spec_name, s(:arglist))), | ||
| s(:evstr, s(:call, nil, :spec_name)), | ||
| s(:str, " from "), | ||
| s(:evstr, s(:call, nil, :source_uri, s(:arglist))), | ||
| s(:evstr, s(:call, nil, :source_uri)), | ||
| s(:str, ":\n"), | ||
@@ -351,4 +352,4 @@ s(:str, "\t"), | ||
| def test_literal_concat_dstr_evstr | ||
| lhs, rhs = s(:dstr, "a"), s(:evstr, s(:call, nil, :b, s(:arglist))) | ||
| expected = s(:dstr, "a", s(:evstr, s(:call, nil, :b, s(:arglist)))) | ||
| lhs, rhs = s(:dstr, "a"), s(:evstr, s(:call, nil, :b)) | ||
| expected = s(:dstr, "a", s(:evstr, s(:call, nil, :b))) | ||
@@ -418,7 +419,7 @@ assert_equal expected, processor.literal_concat(lhs, rhs) | ||
| def test_logop_nested_mix | ||
| lhs = s(:or, s(:call, nil, :a, s(:arglist)), s(:call, nil, :b, s(:arglist))) | ||
| rhs = s(:and, s(:call, nil, :c, s(:arglist)), s(:call, nil, :d, s(:arglist))) | ||
| lhs = s(:or, s(:call, nil, :a), s(:call, nil, :b)) | ||
| rhs = s(:and, s(:call, nil, :c), s(:call, nil, :d)) | ||
| exp = s(:or, | ||
| s(:or, s(:call, nil, :a, s(:arglist)), s(:call, nil, :b, s(:arglist))), | ||
| s(:and, s(:call, nil, :c, s(:arglist)), s(:call, nil, :d, s(:arglist)))) | ||
| s(:or, s(:call, nil, :a), s(:call, nil, :b)), | ||
| s(:and, s(:call, nil, :c), s(:call, nil, :d))) | ||
@@ -433,3 +434,3 @@ lhs.paren = true | ||
| rb = "\"a #\{b}\"" | ||
| pt = s(:dstr, "a ", s(:evstr, s(:call, nil, :b, s(:arglist)))) | ||
| pt = s(:dstr, "a ", s(:evstr, s(:call, nil, :b))) | ||
@@ -467,3 +468,3 @@ assert_parse rb, pt | ||
| rb = "%Q[before [#\{nest}] after]" | ||
| pt = s(:dstr, "before [", s(:evstr, s(:call, nil, :nest, s(:arglist))), s(:str, "] after")) | ||
| pt = s(:dstr, "before [", s(:evstr, s(:call, nil, :nest)), s(:str, "] after")) | ||
@@ -522,3 +523,3 @@ assert_parse rb, pt | ||
| s(:lasgn, :a, s(:lit, 42)), | ||
| s(:call, nil, :p, s(:arglist, s(:lvar, :a)))) | ||
| s(:call, nil, :p, s(:lvar, :a))) | ||
@@ -542,5 +543,5 @@ assert_parse_line rb, pt, 1 | ||
| pt = s(:iter, | ||
| s(:call, nil, :f, s(:arglist)), | ||
| s(:call, nil, :f), | ||
| s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))), | ||
| s(:call, s(:lvar, :x), :+, s(:arglist, s(:lvar, :y)))) | ||
| s(:call, s(:lvar, :x), :+, s(:lvar, :y))) | ||
@@ -554,3 +555,3 @@ assert_parse_line rb, pt, 1 | ||
| def test_parse_line_defn_no_parens | ||
| pt = s(:defn, :f, s(:args), s(:scope, s(:block, s(:nil)))) | ||
| pt = s(:defn, :f, s(:args), s(:nil)) | ||
@@ -567,12 +568,9 @@ rb = "def f\nend" | ||
| pt = s(:defn, :x, s(:args, :y), | ||
| s(:scope, | ||
| s(:block, | ||
| s(:call, nil, :p, s(:arglist, s(:lvar, :y))), | ||
| s(:lasgn, :y, | ||
| s(:call, s(:lvar, :y), :*, s(:arglist, s(:lit, 2)))), | ||
| s(:return, s(:lvar, :y))))) | ||
| s(:call, nil, :p, s(:lvar, :y)), | ||
| s(:lasgn, :y, s(:call, s(:lvar, :y), :*, s(:lit, 2))), | ||
| s(:return, s(:lvar, :y))) | ||
| assert_parse_line rb, pt, 1 | ||
| body = result.scope.block | ||
| body = result | ||
| assert_equal 2, body.call.line, "call should have line number" | ||
@@ -587,5 +585,5 @@ assert_equal 3, body.lasgn.line, "lasgn should have line number" | ||
| pt = s(:iter, | ||
| s(:call, nil, :f, s(:arglist, s(:call, nil, :a, s(:arglist)))), | ||
| s(:call, nil, :f, s(:call, nil, :a)), | ||
| s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))), | ||
| s(:call, s(:lvar, :x), :+, s(:arglist, s(:lvar, :y)))) | ||
| s(:call, s(:lvar, :x), :+, s(:lvar, :y))) | ||
@@ -603,5 +601,5 @@ assert_parse_line rb, pt, 1 | ||
| pt = s(:iter, | ||
| s(:call, nil, :f, s(:arglist, s(:call, nil, :a, s(:arglist)))), | ||
| s(:call, nil, :f, s(:call, nil, :a)), | ||
| s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))), | ||
| s(:call, s(:lvar, :x), :+, s(:arglist, s(:lvar, :y)))) | ||
| s(:call, s(:lvar, :x), :+, s(:lvar, :y))) | ||
@@ -645,13 +643,10 @@ assert_parse_line rb, pt, 1 | ||
| pt = s(:defn, :blah, s(:args), | ||
| s(:scope, | ||
| s(:block, | ||
| s(:if, | ||
| s(:true), | ||
| s(:return, s(:lit, 42)), | ||
| nil)))) | ||
| s(:if, s(:true), | ||
| s(:return, s(:lit, 42)), | ||
| nil)) | ||
| assert_parse_line rb, pt, 1 | ||
| assert_equal 3, result.scope.block.if.return.line | ||
| assert_equal 3, result.scope.block.if.return.lit.line | ||
| assert_equal 3, result.if.return.line | ||
| assert_equal 3, result.if.return.lit.line | ||
| end | ||
@@ -662,3 +657,3 @@ | ||
| pt = s(:if, | ||
| s(:call, s(:call, nil, :var, s(:arglist)), :nil?, s(:arglist)), | ||
| s(:call, s(:call, nil, :var), :nil?), | ||
| s(:str, "bar"), | ||
@@ -674,3 +669,3 @@ s(:str, "foo")) | ||
| s(:not, | ||
| s(:call, s(:call, nil, :var, s(:arglist)), :nil?, s(:arglist))), | ||
| s(:call, s(:call, nil, :var), :nil?)), | ||
| s(:str, "foo"), | ||
@@ -687,3 +682,3 @@ s(:str, "bar")) | ||
| pt = s(:until, | ||
| s(:call, s(:call, nil, :var, s(:arglist)), :nil?, s(:arglist)), | ||
| s(:call, s(:call, nil, :var), :nil?), | ||
| s(:str, "foo"), true) | ||
@@ -698,3 +693,3 @@ | ||
| s(:not, | ||
| s(:call, s(:call, nil, :var, s(:arglist)), :nil?, s(:arglist))), | ||
| s(:call, s(:call, nil, :var), :nil?)), | ||
| s(:str, "foo"), true) | ||
@@ -711,3 +706,3 @@ | ||
| pt = s(:while, | ||
| s(:call, s(:call, nil, :var, s(:arglist)), :nil?, s(:arglist)), | ||
| s(:call, s(:call, nil, :var), :nil?), | ||
| s(:str, "foo"), true) | ||
@@ -722,3 +717,3 @@ | ||
| s(:not, | ||
| s(:call, s(:call, nil, :var, s(:arglist)), :nil?, s(:arglist))), | ||
| s(:call, s(:call, nil, :var), :nil?)), | ||
| s(:str, "foo"), true) | ||
@@ -731,1 +726,60 @@ | ||
| end | ||
| class TestRuby18Parser < RubyParserTestCase | ||
| include TestRubyParser | ||
| def setup | ||
| super | ||
| self.processor = Ruby18Parser.new | ||
| end | ||
| def test_flip2_env_lvar | ||
| rb = "if a..b then end" | ||
| pt = s(:if, s(:flip2, s(:call, nil, :a), s(:call, nil, :b)), nil, nil) | ||
| assert_parse rb, pt | ||
| top_env = processor.env.env.first | ||
| assert_kind_of Hash, top_env | ||
| flip = top_env.find { |k,v| k =~ /^flip/ } | ||
| assert flip | ||
| assert_equal :lvar, flip.last | ||
| end | ||
| end | ||
| class TestRuby19Parser < RubyParserTestCase | ||
| include TestRubyParser | ||
| def setup | ||
| super | ||
| self.processor = Ruby19Parser.new | ||
| end | ||
| # HACK: need to figure out the desired structure and get this working | ||
| # def test_wtf | ||
| # # lambda -> f_larglist lambda_body | ||
| # # f_larglist -> f_args opt_bv_decl | ||
| # # opt_bv_decl | ||
| # # bv_decls | ||
| # # bvar | ||
| # | ||
| # rb = "->(a, b=nil) { p [a, b] }" | ||
| # pt = s(:iter, | ||
| # s(:call, nil, :lambda), | ||
| # s(:args, :a, :b, | ||
| # s(:block, s(:lasgn, :b, s(nil)))), | ||
| # s(:call, nil, :p, s(:array, s(:lvar, :a), s(:lvar, :b)))) | ||
| # | ||
| # assert_parse rb, pt | ||
| # | ||
| # rb = "->(a; b) { p [a, b] }" | ||
| # | ||
| # assert_parse rb, pt | ||
| # end | ||
| end | ||
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display