ruby_parser
Advanced tools
+13
-0
@@ -0,1 +1,14 @@ | ||
| === 2.2.0 / 2011-08-23 | ||
| * 2 minor enhancements: | ||
| * Moved Keyword, Environment, and StackState inside of RubyParser | ||
| * Added proper dsym and dsym->sym support. | ||
| * 3 bug fixes: | ||
| * Added extra (failing) tests for call/iter line number checking (quix) | ||
| * Fixed line numbers for certain call/iter edge cases | ||
| * Fixed parsing of: alias :"<<" :">>". | ||
| === 2.1.0 / 2011-08-15 | ||
@@ -2,0 +15,0 @@ |
@@ -220,4 +220,4 @@ class RubyLexer | ||
| def initialize | ||
| self.cond = StackState.new(:cond) | ||
| self.cmdarg = StackState.new(:cmdarg) | ||
| self.cond = RubyParser::StackState.new(:cond) | ||
| self.cmdarg = RubyParser::StackState.new(:cmdarg) | ||
| self.nest = 0 | ||
@@ -391,3 +391,2 @@ @comments = [] | ||
| return :tSTRING_CONTENT | ||
@@ -1250,3 +1249,3 @@ end | ||
| # See if it is a reserved word. | ||
| keyword = Keyword.keyword token | ||
| keyword = RubyParser::Keyword.keyword token | ||
@@ -1253,0 +1252,0 @@ if keyword then |
+151
-151
@@ -126,3 +126,3 @@ require 'stringio' | ||
| class RubyParser < Racc::Parser | ||
| VERSION = '2.1.0' unless constants.include? "VERSION" # SIGH | ||
| VERSION = '2.2.0' unless constants.include? "VERSION" # SIGH | ||
@@ -828,183 +828,183 @@ attr_accessor :lexer, :in_def, :in_single, :file | ||
| end | ||
| end | ||
| class Keyword | ||
| class KWtable | ||
| attr_accessor :name, :state, :id0, :id1 | ||
| def initialize(name, id=[], state=nil) | ||
| @name = name | ||
| @id0, @id1 = id | ||
| @state = state | ||
| class Keyword | ||
| class KWtable | ||
| attr_accessor :name, :state, :id0, :id1 | ||
| def initialize(name, id=[], state=nil) | ||
| @name = name | ||
| @id0, @id1 = id | ||
| @state = state | ||
| end | ||
| end | ||
| end | ||
| ## | ||
| # :stopdoc: | ||
| # | ||
| # :expr_beg = ignore newline, +/- is a sign. | ||
| # :expr_end = newline significant, +/- is a operator. | ||
| # :expr_arg = newline significant, +/- is a operator. | ||
| # :expr_cmdarg = newline significant, +/- is a operator. | ||
| # :expr_endarg = newline significant, +/- is a operator. | ||
| # :expr_mid = newline significant, +/- is a operator. | ||
| # :expr_fname = ignore newline, no reserved words. | ||
| # :expr_dot = right after . or ::, no reserved words. | ||
| # :expr_class = immediate after class, no here document. | ||
| ## | ||
| # :stopdoc: | ||
| # | ||
| # :expr_beg = ignore newline, +/- is a sign. | ||
| # :expr_end = newline significant, +/- is a operator. | ||
| # :expr_arg = newline significant, +/- is a operator. | ||
| # :expr_cmdarg = newline significant, +/- is a operator. | ||
| # :expr_endarg = newline significant, +/- is a operator. | ||
| # :expr_mid = newline significant, +/- is a operator. | ||
| # :expr_fname = ignore newline, no reserved words. | ||
| # :expr_dot = right after . or ::, no reserved words. | ||
| # :expr_class = immediate after class, no here document. | ||
| wordlist = [ | ||
| ["end", [:kEND, :kEND ], :expr_end ], | ||
| ["else", [:kELSE, :kELSE ], :expr_beg ], | ||
| ["case", [:kCASE, :kCASE ], :expr_beg ], | ||
| ["ensure", [:kENSURE, :kENSURE ], :expr_beg ], | ||
| ["module", [:kMODULE, :kMODULE ], :expr_beg ], | ||
| ["elsif", [:kELSIF, :kELSIF ], :expr_beg ], | ||
| ["def", [:kDEF, :kDEF ], :expr_fname ], | ||
| ["rescue", [:kRESCUE, :kRESCUE_MOD ], :expr_mid ], | ||
| ["not", [:kNOT, :kNOT ], :expr_beg ], | ||
| ["then", [:kTHEN, :kTHEN ], :expr_beg ], | ||
| ["yield", [:kYIELD, :kYIELD ], :expr_arg ], | ||
| ["for", [:kFOR, :kFOR ], :expr_beg ], | ||
| ["self", [:kSELF, :kSELF ], :expr_end ], | ||
| ["false", [:kFALSE, :kFALSE ], :expr_end ], | ||
| ["retry", [:kRETRY, :kRETRY ], :expr_end ], | ||
| ["return", [:kRETURN, :kRETURN ], :expr_mid ], | ||
| ["true", [:kTRUE, :kTRUE ], :expr_end ], | ||
| ["if", [:kIF, :kIF_MOD ], :expr_beg ], | ||
| ["defined?", [:kDEFINED, :kDEFINED ], :expr_arg ], | ||
| ["super", [:kSUPER, :kSUPER ], :expr_arg ], | ||
| ["undef", [:kUNDEF, :kUNDEF ], :expr_fname ], | ||
| ["break", [:kBREAK, :kBREAK ], :expr_mid ], | ||
| ["in", [:kIN, :kIN ], :expr_beg ], | ||
| ["do", [:kDO, :kDO ], :expr_beg ], | ||
| ["nil", [:kNIL, :kNIL ], :expr_end ], | ||
| ["until", [:kUNTIL, :kUNTIL_MOD ], :expr_beg ], | ||
| ["unless", [:kUNLESS, :kUNLESS_MOD ], :expr_beg ], | ||
| ["or", [:kOR, :kOR ], :expr_beg ], | ||
| ["next", [:kNEXT, :kNEXT ], :expr_mid ], | ||
| ["when", [:kWHEN, :kWHEN ], :expr_beg ], | ||
| ["redo", [:kREDO, :kREDO ], :expr_end ], | ||
| ["and", [:kAND, :kAND ], :expr_beg ], | ||
| ["begin", [:kBEGIN, :kBEGIN ], :expr_beg ], | ||
| ["__LINE__", [:k__LINE__, :k__LINE__ ], :expr_end ], | ||
| ["class", [:kCLASS, :kCLASS ], :expr_class ], | ||
| ["__FILE__", [:k__FILE__, :k__FILE__ ], :expr_end ], | ||
| ["END", [:klEND, :klEND ], :expr_end ], | ||
| ["BEGIN", [:klBEGIN, :klBEGIN ], :expr_end ], | ||
| ["while", [:kWHILE, :kWHILE_MOD ], :expr_beg ], | ||
| ["alias", [:kALIAS, :kALIAS ], :expr_fname ], | ||
| ].map { |args| KWtable.new(*args) } | ||
| wordlist = [ | ||
| ["end", [:kEND, :kEND ], :expr_end ], | ||
| ["else", [:kELSE, :kELSE ], :expr_beg ], | ||
| ["case", [:kCASE, :kCASE ], :expr_beg ], | ||
| ["ensure", [:kENSURE, :kENSURE ], :expr_beg ], | ||
| ["module", [:kMODULE, :kMODULE ], :expr_beg ], | ||
| ["elsif", [:kELSIF, :kELSIF ], :expr_beg ], | ||
| ["def", [:kDEF, :kDEF ], :expr_fname ], | ||
| ["rescue", [:kRESCUE, :kRESCUE_MOD ], :expr_mid ], | ||
| ["not", [:kNOT, :kNOT ], :expr_beg ], | ||
| ["then", [:kTHEN, :kTHEN ], :expr_beg ], | ||
| ["yield", [:kYIELD, :kYIELD ], :expr_arg ], | ||
| ["for", [:kFOR, :kFOR ], :expr_beg ], | ||
| ["self", [:kSELF, :kSELF ], :expr_end ], | ||
| ["false", [:kFALSE, :kFALSE ], :expr_end ], | ||
| ["retry", [:kRETRY, :kRETRY ], :expr_end ], | ||
| ["return", [:kRETURN, :kRETURN ], :expr_mid ], | ||
| ["true", [:kTRUE, :kTRUE ], :expr_end ], | ||
| ["if", [:kIF, :kIF_MOD ], :expr_beg ], | ||
| ["defined?", [:kDEFINED, :kDEFINED ], :expr_arg ], | ||
| ["super", [:kSUPER, :kSUPER ], :expr_arg ], | ||
| ["undef", [:kUNDEF, :kUNDEF ], :expr_fname ], | ||
| ["break", [:kBREAK, :kBREAK ], :expr_mid ], | ||
| ["in", [:kIN, :kIN ], :expr_beg ], | ||
| ["do", [:kDO, :kDO ], :expr_beg ], | ||
| ["nil", [:kNIL, :kNIL ], :expr_end ], | ||
| ["until", [:kUNTIL, :kUNTIL_MOD ], :expr_beg ], | ||
| ["unless", [:kUNLESS, :kUNLESS_MOD ], :expr_beg ], | ||
| ["or", [:kOR, :kOR ], :expr_beg ], | ||
| ["next", [:kNEXT, :kNEXT ], :expr_mid ], | ||
| ["when", [:kWHEN, :kWHEN ], :expr_beg ], | ||
| ["redo", [:kREDO, :kREDO ], :expr_end ], | ||
| ["and", [:kAND, :kAND ], :expr_beg ], | ||
| ["begin", [:kBEGIN, :kBEGIN ], :expr_beg ], | ||
| ["__LINE__", [:k__LINE__, :k__LINE__ ], :expr_end ], | ||
| ["class", [:kCLASS, :kCLASS ], :expr_class ], | ||
| ["__FILE__", [:k__FILE__, :k__FILE__ ], :expr_end ], | ||
| ["END", [:klEND, :klEND ], :expr_end ], | ||
| ["BEGIN", [:klBEGIN, :klBEGIN ], :expr_end ], | ||
| ["while", [:kWHILE, :kWHILE_MOD ], :expr_beg ], | ||
| ["alias", [:kALIAS, :kALIAS ], :expr_fname ], | ||
| ].map { |args| KWtable.new(*args) } | ||
| # :startdoc: | ||
| # :startdoc: | ||
| WORDLIST = Hash[*wordlist.map { |o| [o.name, o] }.flatten] unless | ||
| defined? WORDLIST | ||
| WORDLIST = Hash[*wordlist.map { |o| [o.name, o] }.flatten] unless | ||
| defined? WORDLIST | ||
| def self.keyword str | ||
| WORDLIST[str] | ||
| def self.keyword str | ||
| WORDLIST[str] | ||
| end | ||
| end | ||
| end | ||
| class Environment | ||
| attr_reader :env, :dyn | ||
| class Environment | ||
| attr_reader :env, :dyn | ||
| def [] k | ||
| self.all[k] | ||
| end | ||
| def [] k | ||
| self.all[k] | ||
| end | ||
| def []= k, v | ||
| raise "no" if v == true | ||
| self.current[k] = v | ||
| end | ||
| def []= k, v | ||
| raise "no" if v == true | ||
| self.current[k] = v | ||
| end | ||
| def all | ||
| idx = @dyn.index(false) || 0 | ||
| @env[0..idx].reverse.inject { |env, scope| env.merge scope } | ||
| end | ||
| def all | ||
| idx = @dyn.index(false) || 0 | ||
| @env[0..idx].reverse.inject { |env, scope| env.merge scope } | ||
| end | ||
| def current | ||
| @env.first | ||
| end | ||
| def current | ||
| @env.first | ||
| end | ||
| def dynamic | ||
| idx = @dyn.index false | ||
| @env[0...idx].reverse.inject { |env, scope| env.merge scope } || {} | ||
| end | ||
| def dynamic | ||
| idx = @dyn.index false | ||
| @env[0...idx].reverse.inject { |env, scope| env.merge scope } || {} | ||
| end | ||
| def dynamic? | ||
| @dyn[0] != false | ||
| end | ||
| def dynamic? | ||
| @dyn[0] != false | ||
| end | ||
| def extend dyn = false | ||
| @dyn.unshift dyn | ||
| @env.unshift({}) | ||
| @use.unshift({}) | ||
| end | ||
| def extend dyn = false | ||
| @dyn.unshift dyn | ||
| @env.unshift({}) | ||
| @use.unshift({}) | ||
| end | ||
| def initialize dyn = false | ||
| @dyn = [] | ||
| @env = [] | ||
| @use = [] | ||
| self.reset | ||
| end | ||
| def initialize dyn = false | ||
| @dyn = [] | ||
| @env = [] | ||
| @use = [] | ||
| self.reset | ||
| end | ||
| def reset | ||
| @dyn.clear | ||
| @env.clear | ||
| @use.clear | ||
| self.extend | ||
| end | ||
| def reset | ||
| @dyn.clear | ||
| @env.clear | ||
| @use.clear | ||
| self.extend | ||
| end | ||
| def unextend | ||
| @dyn.shift | ||
| @env.shift | ||
| @use.shift | ||
| raise "You went too far unextending env" if @env.empty? | ||
| end | ||
| def unextend | ||
| @dyn.shift | ||
| @env.shift | ||
| @use.shift | ||
| raise "You went too far unextending env" if @env.empty? | ||
| end | ||
| def use id | ||
| @env.each_with_index do |env, i| | ||
| if env[id] then | ||
| @use[i][id] = true | ||
| def use id | ||
| @env.each_with_index do |env, i| | ||
| if env[id] then | ||
| @use[i][id] = true | ||
| end | ||
| end | ||
| end | ||
| end | ||
| def used? id | ||
| idx = @dyn.index false # REFACTOR | ||
| u = @use[0...idx].reverse.inject { |env, scope| env.merge scope } || {} | ||
| u[id] | ||
| def used? id | ||
| idx = @dyn.index false # REFACTOR | ||
| u = @use[0...idx].reverse.inject { |env, scope| env.merge scope } || {} | ||
| u[id] | ||
| end | ||
| end | ||
| end | ||
| class StackState | ||
| attr_reader :stack | ||
| class StackState | ||
| attr_reader :stack | ||
| def initialize(name) | ||
| @name = name | ||
| @stack = [false] | ||
| end | ||
| def initialize(name) | ||
| @name = name | ||
| @stack = [false] | ||
| end | ||
| def inspect | ||
| "StackState(#{@name}, #{@stack.inspect})" | ||
| end | ||
| def inspect | ||
| "StackState(#{@name}, #{@stack.inspect})" | ||
| end | ||
| def is_in_state | ||
| @stack.last | ||
| end | ||
| def is_in_state | ||
| @stack.last | ||
| end | ||
| def lexpop | ||
| raise if @stack.size == 0 | ||
| a = @stack.pop | ||
| b = @stack.pop | ||
| @stack.push(a || b) | ||
| end | ||
| def lexpop | ||
| raise if @stack.size == 0 | ||
| a = @stack.pop | ||
| b = @stack.pop | ||
| @stack.push(a || b) | ||
| end | ||
| def pop | ||
| r = @stack.pop | ||
| @stack.push false if @stack.size == 0 | ||
| r | ||
| end | ||
| def pop | ||
| r = @stack.pop | ||
| @stack.push false if @stack.size == 0 | ||
| r | ||
| end | ||
| def push val | ||
| @stack.push val | ||
| def push val | ||
| @stack.push val | ||
| end | ||
| end | ||
@@ -1011,0 +1011,0 @@ end |
@@ -6,4 +6,9 @@ require 'rubygems' | ||
| class TestStackState < MiniTest::Unit::TestCase | ||
| attr_reader :s | ||
| def setup | ||
| @s = RubyParser::StackState.new :test | ||
| end | ||
| def test_stack_state | ||
| s = StackState.new :test | ||
| s.push true | ||
@@ -16,3 +21,2 @@ s.push false | ||
| def test_is_in_state | ||
| s = StackState.new :test | ||
| assert_equal false, s.is_in_state | ||
@@ -28,3 +32,2 @@ s.push false | ||
| def test_lexpop | ||
| s = StackState.new :test | ||
| assert_equal [false], s.stack | ||
@@ -39,3 +42,2 @@ s.push true | ||
| def test_pop | ||
| s = StackState.new :test | ||
| assert_equal [false], s.stack | ||
@@ -49,3 +51,2 @@ s.push true | ||
| def test_push | ||
| s = StackState.new :test | ||
| assert_equal [false], s.stack | ||
@@ -64,3 +65,3 @@ s.push true | ||
| def setup | ||
| @env = Environment.new | ||
| @env = RubyParser::Environment.new | ||
| @env[:blah] = 42 | ||
@@ -67,0 +68,0 @@ assert_equal 42, @env[:blah] |
| #!/usr/local/bin/ruby | ||
| ENV['VERBOSE'] = "1" | ||
| require 'rubygems' | ||
@@ -375,2 +377,10 @@ require 'minitest/autorun' | ||
| def test_dsym_to_sym | ||
| assert_equal(s(:alias, s(:lit, :<<), s(:lit, :>>)), | ||
| @processor.parse('alias :<< :>>')) | ||
| assert_equal(s(:alias, s(:lit, :<<), s(:lit, :>>)), | ||
| @processor.parse('alias :"<<" :">>"')) | ||
| end | ||
| def test_regexp | ||
@@ -467,2 +477,57 @@ regexps = { | ||
| def test_position_info_call_no_args | ||
| rb = "f do |x, y|\n x + y\nend" | ||
| pt = s(:iter, | ||
| s(:call, nil, :f, s(:arglist)), | ||
| s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))), | ||
| s(:call, s(:lvar, :x), :+, s(:arglist, s(:lvar, :y)))) | ||
| result = @processor.parse(rb) | ||
| assert_equal pt, result | ||
| assert_equal 1, result[1].line, "call should have line number" | ||
| assert_equal 1, result.line, "iter should have line number" | ||
| assert_equal 1, result[2].line, "masgn should have line number" | ||
| assert_equal 2, result[3].line, "call should have line number" | ||
| end | ||
| def test_position_info_call_parens | ||
| rb = "f(a) do |x, y|\n x + y\nend" | ||
| pt = s(:iter, | ||
| s(:call, nil, :f, s(:arglist, s(:call, nil, :a, s(:arglist)))), | ||
| s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))), | ||
| s(:call, s(:lvar, :x), :+, s(:arglist, s(:lvar, :y)))) | ||
| result = @processor.parse(rb) | ||
| assert_equal pt, result | ||
| assert_equal 1, result[1].line, "call should have line number" | ||
| assert_equal 1, result.line, "iter should have line number" | ||
| assert_equal 1, result[2].line, "masgn should have line number" | ||
| assert_equal 2, result[3].line, "call should have line number" | ||
| # flunk "not yet" | ||
| end | ||
| def test_position_info_call_no_parens | ||
| rb = "f a do |x, y|\n x + y\nend" | ||
| pt = s(:iter, | ||
| s(:call, nil, :f, s(:arglist, s(:call, nil, :a, s(:arglist)))), | ||
| s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))), | ||
| s(:call, s(:lvar, :x), :+, s(:arglist, s(:lvar, :y)))) | ||
| result = @processor.parse(rb) | ||
| assert_equal pt, result | ||
| assert_equal 1, result.line, "iter should have line number" | ||
| assert_equal 1, result[1].line, "call should have line number" | ||
| assert_equal 1, result[2].line, "masgn should have line number" | ||
| assert_equal 2, result[3].line, "call should have line number" | ||
| end | ||
| def test_position_info_defn | ||
@@ -469,0 +534,0 @@ rb = "def x(y)\n p(y)\n y *= 2\n return y;\nend" # TODO: remove () & ; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet