parser 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -7
  2. data/.gitignore +0 -1
  3. data/README.md +4 -2
  4. data/bin/{parse → ruby-parse} +2 -2
  5. data/bin/ruby-rewrite +6 -0
  6. data/{AST_FORMAT.md → doc/AST_FORMAT.md} +45 -29
  7. data/doc/CUSTOMIZATION.md +37 -0
  8. data/doc/INTERNALS.md +21 -0
  9. data/lib/parser.rb +14 -3
  10. data/lib/parser/ast/node.rb +6 -0
  11. data/lib/parser/ast/processor.rb +216 -0
  12. data/lib/parser/builders/default.rb +613 -215
  13. data/lib/parser/compatibility/slop.rb +12 -0
  14. data/lib/parser/lexer.rl +30 -10
  15. data/lib/parser/lexer/explanation.rb +1 -1
  16. data/lib/parser/lexer/literal.rb +5 -6
  17. data/lib/parser/ruby18.y +31 -24
  18. data/lib/parser/ruby19.y +26 -19
  19. data/lib/parser/ruby20.y +27 -20
  20. data/lib/parser/ruby21.y +27 -20
  21. data/lib/parser/runner.rb +198 -0
  22. data/lib/parser/runner/ruby_parse.rb +87 -0
  23. data/lib/parser/runner/ruby_rewrite.rb +13 -0
  24. data/lib/parser/source/buffer.rb +1 -0
  25. data/lib/parser/source/map.rb +20 -0
  26. data/lib/parser/source/map/block.rb +16 -0
  27. data/lib/parser/source/map/collection.rb +16 -0
  28. data/lib/parser/source/map/condition.rb +19 -0
  29. data/lib/parser/source/map/constant.rb +27 -0
  30. data/lib/parser/source/map/definition.rb +21 -0
  31. data/lib/parser/source/map/for.rb +17 -0
  32. data/lib/parser/source/map/keyword.rb +18 -0
  33. data/lib/parser/source/map/rescue_body.rb +19 -0
  34. data/lib/parser/source/map/send.rb +29 -0
  35. data/lib/parser/source/map/ternary.rb +16 -0
  36. data/lib/parser/source/map/variable.rb +26 -0
  37. data/lib/parser/source/range.rb +25 -24
  38. data/lib/parser/version.rb +3 -0
  39. data/parser.gemspec +4 -2
  40. data/test/parse_helper.rb +13 -10
  41. data/test/test_lexer.rb +32 -11
  42. data/test/test_parse_helper.rb +1 -0
  43. data/test/test_parser.rb +176 -128
  44. data/test/test_source_range.rb +18 -6
  45. metadata +161 -91
  46. data/bin/benchmark +0 -47
  47. data/bin/explain-parse +0 -14
  48. data/lib/parser/source/map/variable_assignment.rb +0 -15
@@ -0,0 +1,16 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Block < Map
5
+ attr_reader :begin
6
+ attr_reader :end
7
+
8
+ def initialize(begin_l, end_l, expression_l)
9
+ @begin, @end = begin_l, end_l
10
+
11
+ super(expression_l)
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Collection < Map
5
+ attr_reader :begin
6
+ attr_reader :end
7
+
8
+ def initialize(begin_l, end_l, expression_l)
9
+ @begin, @end = begin_l, end_l
10
+
11
+ super(expression_l)
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Condition < Map
5
+ attr_reader :keyword
6
+ attr_reader :begin
7
+ attr_reader :else
8
+ attr_reader :end
9
+
10
+ def initialize(keyword_l, begin_l, else_l, end_l, expression_l)
11
+ @keyword = keyword_l
12
+ @begin, @else, @end = begin_l, else_l, end_l
13
+
14
+ super(expression_l)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Constant < Map
5
+ attr_reader :double_colon
6
+ attr_reader :name
7
+ attr_reader :operator
8
+
9
+ def initialize(double_colon, name, expression)
10
+ @double_colon, @name = double_colon, name
11
+
12
+ super(expression)
13
+ end
14
+
15
+ def with_operator(operator_l)
16
+ with { |map| map.update_operator(operator_l) }
17
+ end
18
+
19
+ protected
20
+
21
+ def update_operator(operator_l)
22
+ @operator = operator_l
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Definition < Map
5
+ attr_reader :keyword
6
+ attr_reader :operator
7
+ attr_reader :name
8
+ attr_reader :end
9
+
10
+ def initialize(keyword_l, operator_l, name_l, end_l)
11
+ @keyword = keyword_l
12
+ @operator = operator_l
13
+ @name = name_l
14
+ @end = end_l
15
+
16
+ super(@keyword.join(@end))
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::For < Map
5
+ attr_reader :keyword, :in
6
+ attr_reader :begin, :end
7
+
8
+ def initialize(keyword_l, in_l, begin_l, end_l, expression_l)
9
+ @keyword, @in = keyword_l, in_l
10
+ @begin, @end = begin_l, end_l
11
+
12
+ super(expression_l)
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Keyword < Map
5
+ attr_reader :keyword
6
+ attr_reader :begin
7
+ attr_reader :end
8
+
9
+ def initialize(keyword_l, begin_l, end_l, expression_l)
10
+ @keyword = keyword_l
11
+ @begin, @end = begin_l, end_l
12
+
13
+ super(expression_l)
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::RescueBody < Map
5
+ attr_reader :keyword
6
+ attr_reader :assoc
7
+ attr_reader :begin
8
+
9
+ def initialize(keyword_l, assoc_l, begin_l, expression_l)
10
+ @keyword = keyword_l
11
+ @assoc = assoc_l
12
+ @begin = begin_l
13
+
14
+ super(expression_l)
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Send < Map
5
+ attr_reader :selector
6
+ attr_reader :operator
7
+ attr_reader :begin
8
+ attr_reader :end
9
+
10
+ def initialize(selector_l, begin_l, end_l, expression_l)
11
+ @selector = selector_l
12
+ @begin, @end = begin_l, end_l
13
+
14
+ super(expression_l)
15
+ end
16
+
17
+ def with_operator(operator_l)
18
+ with { |map| map.update_operator(operator_l) }
19
+ end
20
+
21
+ protected
22
+
23
+ def update_operator(operator_l)
24
+ @operator = operator_l
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Ternary < Map
5
+ attr_reader :question
6
+ attr_reader :colon
7
+
8
+ def initialize(question_l, colon_l, expression_l)
9
+ @question, @colon = question_l, colon_l
10
+
11
+ super(expression_l)
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,26 @@
1
+ module Parser
2
+ module Source
3
+
4
+ class Map::Variable < Map
5
+ attr_reader :name
6
+ attr_reader :operator
7
+
8
+ def initialize(name_l, expression_l=name_l)
9
+ @name = name_l
10
+
11
+ super(expression_l)
12
+ end
13
+
14
+ def with_operator(operator_l)
15
+ with { |map| map.update_operator(operator_l) }
16
+ end
17
+
18
+ protected
19
+
20
+ def update_operator(operator_l)
21
+ @operator = operator_l
22
+ end
23
+ end
24
+
25
+ end
26
+ end
@@ -3,39 +3,43 @@ module Parser
3
3
 
4
4
  class Range
5
5
  attr_reader :source_buffer
6
- attr_reader :begin, :end
6
+ attr_reader :begin_pos, :end_pos
7
7
 
8
- def initialize(source_buffer, begin_, end_)
9
- @source_buffer = source_buffer
10
- @begin, @end = begin_, end_
8
+ def initialize(source_buffer, begin_pos, end_pos)
9
+ @source_buffer = source_buffer
10
+ @begin_pos, @end_pos = begin_pos, end_pos
11
11
 
12
12
  freeze
13
13
  end
14
14
 
15
- def size
16
- @end - @begin + 1
15
+ def begin
16
+ Range.new(@source_buffer, @begin_pos, @begin_pos)
17
17
  end
18
18
 
19
- def line
20
- line, _ = @source_buffer.decompose_position(@begin)
19
+ def end
20
+ Range.new(@source_buffer, @end_pos, @end_pos)
21
+ end
21
22
 
22
- line
23
+ def size
24
+ @end_pos - @begin_pos + 1
23
25
  end
24
26
 
25
- def begin_column
26
- _, column = @source_buffer.decompose_position(@begin)
27
+ alias length size
27
28
 
28
- column
29
+ def line
30
+ line, _ = @source_buffer.decompose_position(@begin_pos)
31
+
32
+ line
29
33
  end
30
34
 
31
- def end_column
32
- _, column = @source_buffer.decompose_position(@end)
35
+ def column
36
+ _, column = @source_buffer.decompose_position(@begin_pos)
33
37
 
34
38
  column
35
39
  end
36
40
 
37
41
  def column_range
38
- begin_column..end_column
42
+ self.begin.column..self.end.column
39
43
  end
40
44
 
41
45
  def source_line
@@ -43,22 +47,19 @@ module Parser
43
47
  end
44
48
 
45
49
  def to_s
46
- line, column = @source_buffer.decompose_position(@begin)
50
+ line, column = @source_buffer.decompose_position(@begin_pos)
51
+
47
52
  [@source_buffer.name, line, column + 1].join(':')
48
53
  end
49
54
 
50
55
  def join(other)
51
- if other.source_buffer == @source_buffer
52
- Range.new(@source_buffer,
53
- [@begin, other.begin].min,
54
- [@end, other.end].max)
55
- else
56
- raise ArgumentError, "Cannot join SourceRanges for different SourceFiles"
57
- end
56
+ Range.new(@source_buffer,
57
+ [@begin_pos, other.begin_pos].min,
58
+ [@end_pos, other.end_pos].max)
58
59
  end
59
60
 
60
61
  def inspect
61
- "#<Source::Range #{@source_buffer.name} #{@begin}..#{@end}>"
62
+ "#<Source::Range #{@source_buffer.name} #{@begin_pos}..#{@end_pos}>"
62
63
  end
63
64
  end
64
65
 
@@ -0,0 +1,3 @@
1
+ module Parser
2
+ VERSION = '1.2.0'
3
+ end
data/parser.gemspec CHANGED
@@ -1,8 +1,9 @@
1
1
  # encoding: utf-8
2
+ require File.expand_path('../lib/parser/version', __FILE__)
2
3
 
3
4
  Gem::Specification.new do |spec|
4
5
  spec.name = 'parser'
5
- spec.version = '1.1.0'
6
+ spec.version = Parser::VERSION
6
7
  spec.authors = ['Peter Zotov']
7
8
  spec.email = ['whitequark@whitequark.org']
8
9
  spec.description = %q{A Ruby parser written in pure Ruby.}
@@ -17,11 +18,12 @@ Gem::Specification.new do |spec|
17
18
  lib/parser/ruby20.rb
18
19
  lib/parser/ruby21.rb
19
20
  )
20
- spec.executables = %w()
21
+ spec.executables = %w(ruby-parse ruby-rewrite)
21
22
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
23
  spec.require_paths = ['lib']
23
24
 
24
25
  spec.add_dependency 'ast', '~> 1.0'
26
+ spec.add_dependency 'slop', '~> 3.4'
25
27
 
26
28
  spec.add_development_dependency 'bundler', '~> 1.2'
27
29
  spec.add_development_dependency 'rake', '~> 0.9'
data/test/parse_helper.rb CHANGED
@@ -45,12 +45,12 @@ module ParseHelper
45
45
 
46
46
  def assert_source_range(begin_pos, end_pos, range, version, what)
47
47
  assert range.is_a?(Parser::Source::Range),
48
- "(#{version}) is_a?(Source::Range) for #{what}"
48
+ "(#{version}) #{range.inspect}.is_a?(Source::Range) for #{what}"
49
49
 
50
- assert_equal begin_pos, range.begin,
50
+ assert_equal begin_pos, range.begin_pos,
51
51
  "(#{version}) begin of #{what}"
52
52
 
53
- assert_equal end_pos, range.end,
53
+ assert_equal end_pos, range.end_pos,
54
54
  "(#{version}) end of #{what}"
55
55
  end
56
56
 
@@ -86,10 +86,8 @@ module ParseHelper
86
86
  raise "No entity with AST path #{ast_path} in #{parsed_ast.inspect}"
87
87
  end
88
88
 
89
- next # TODO skip location checking
90
-
91
89
  assert astlet.source_map.respond_to?(map_field),
92
- "(#{version}) source_map.respond_to?(#{map_field.inspect}) for:\n#{parsed_ast.inspect}"
90
+ "(#{version}) #{astlet.source_map.inspect}.respond_to?(#{map_field.inspect}) for:\n#{parsed_ast.inspect}"
93
91
 
94
92
  range = astlet.source_map.send(map_field)
95
93
 
@@ -135,8 +133,6 @@ module ParseHelper
135
133
  parse_source_map_descriptions(source_maps) \
136
134
  do |begin_pos, end_pos, map_field, ast_path, line|
137
135
 
138
- next # TODO skip location checking
139
-
140
136
  case map_field
141
137
  when 'location'
142
138
  assert_source_range begin_pos, end_pos,
@@ -162,7 +158,7 @@ module ParseHelper
162
158
  ^(?# $1 skip) ^(\s*)
163
159
  (?# $2 highlight) ([~\^]+)
164
160
  \s+
165
- (?# $3 source_map_field) ([a-z]+)
161
+ (?# $3 source_map_field) ([a-z_]+)
166
162
  (?# $5 ast_path) (\s+\(([a-z_.\/0-9]+)\))?
167
163
  $/
168
164
 
@@ -199,7 +195,14 @@ module ParseHelper
199
195
  path.inject(ast) do |astlet, path_component|
200
196
  # Split "dstr/2" to :dstr and 1
201
197
  type_str, index_str = path_component.split('/')
202
- type, index = type_str.to_sym, index_str.to_i - 1
198
+
199
+ type = type_str.to_sym
200
+
201
+ if index_str.nil?
202
+ index = 0
203
+ else
204
+ index = index_str.to_i - 1
205
+ end
203
206
 
204
207
  matching_children = \
205
208
  astlet.children.select do |child|
data/test/test_lexer.rb CHANGED
@@ -27,7 +27,7 @@ class TestLexer < MiniTest::Unit::TestCase
27
27
 
28
28
  def util_escape(expected, input)
29
29
  source_buffer = Parser::Source::Buffer.new('(util_escape)')
30
- source_buffer.source = "%Q[\\#{input}]"
30
+ source_buffer.source = "\"\\#{input}\""
31
31
 
32
32
  @lex.reset
33
33
  @lex.source_buffer = source_buffer
@@ -1277,6 +1277,9 @@ class TestLexer < MiniTest::Unit::TestCase
1277
1277
  util_bad_token "1_e1"
1278
1278
  util_bad_token "1_.1"
1279
1279
  util_bad_token "1__1"
1280
+
1281
+ util_bad_token "1end"
1282
+ util_bad_token "1.1end"
1280
1283
  end
1281
1284
 
1282
1285
  def test_plus_unary_number
@@ -1802,7 +1805,9 @@ class TestLexer < MiniTest::Unit::TestCase
1802
1805
 
1803
1806
  def test_string_double_nested_curlies
1804
1807
  util_lex_token('%{nest{one{two}one}nest}',
1805
- :tSTRING, "nest{one{two}one}nest")
1808
+ :tSTRING_BEG, '%{',
1809
+ :tSTRING_CONTENT, "nest{one{two}one}nest",
1810
+ :tSTRING_END, '}')
1806
1811
  end
1807
1812
 
1808
1813
  def test_string_double_no_interp
@@ -1820,7 +1825,9 @@ class TestLexer < MiniTest::Unit::TestCase
1820
1825
 
1821
1826
  def test_string_pct_Q
1822
1827
  util_lex_token("%Q[s1 s2]",
1823
- :tSTRING, "s1 s2")
1828
+ :tSTRING_BEG, '%Q[',
1829
+ :tSTRING_CONTENT, "s1 s2",
1830
+ :tSTRING_END, ']')
1824
1831
  end
1825
1832
 
1826
1833
  def test_string_pct_W
@@ -1873,12 +1880,16 @@ class TestLexer < MiniTest::Unit::TestCase
1873
1880
 
1874
1881
  def test_string_pct_angle
1875
1882
  util_lex_token("%<blah>",
1876
- :tSTRING, "blah")
1883
+ :tSTRING_BEG, '%<',
1884
+ :tSTRING_CONTENT, "blah",
1885
+ :tSTRING_END, '>')
1877
1886
  end
1878
1887
 
1879
- def test_string_pct_other
1888
+ def test_string_pct_pct
1880
1889
  util_lex_token("%%blah%",
1881
- :tSTRING, "blah")
1890
+ :tSTRING_BEG, '%',
1891
+ :tSTRING_CONTENT, "blah",
1892
+ :tSTRING_END, '%')
1882
1893
  end
1883
1894
 
1884
1895
  def test_string_pct_w
@@ -1968,12 +1979,16 @@ class TestLexer < MiniTest::Unit::TestCase
1968
1979
 
1969
1980
  def test_symbol_double
1970
1981
  util_lex_token(":\"symbol\"",
1971
- :tSYMBOL, "symbol")
1982
+ :tSYMBEG, ":\"",
1983
+ :tSTRING_CONTENT, "symbol",
1984
+ :tSTRING_END, "\"")
1972
1985
  end
1973
1986
 
1974
1987
  def test_symbol_single
1975
1988
  util_lex_token(":'symbol'",
1976
- :tSYMBOL, "symbol")
1989
+ :tSYMBEG, ":'",
1990
+ :tSTRING_CONTENT, "symbol",
1991
+ :tSTRING_END, "'")
1977
1992
  end
1978
1993
 
1979
1994
  def test_ternary
@@ -2120,11 +2135,15 @@ class TestLexer < MiniTest::Unit::TestCase
2120
2135
  def test_bug_expr_beg_percent
2121
2136
  @lex.state = :expr_beg
2122
2137
  util_lex_token("%=foo=",
2123
- :tSTRING, "foo")
2138
+ :tSTRING_BEG, "%=",
2139
+ :tSTRING_CONTENT, 'foo',
2140
+ :tSTRING_END, "=")
2124
2141
 
2125
2142
  @lex.state = :expr_beg
2126
2143
  util_lex_token("% = ",
2127
- :tSTRING, "=")
2144
+ :tSTRING_BEG, "% ",
2145
+ :tSTRING_CONTENT, '=',
2146
+ :tSTRING_END, ' ')
2128
2147
  end
2129
2148
 
2130
2149
  def test_bug_expr_beg_document
@@ -2162,7 +2181,9 @@ class TestLexer < MiniTest::Unit::TestCase
2162
2181
 
2163
2182
  @lex.state = :expr_arg
2164
2183
  util_lex_token(" %[1]",
2165
- :tSTRING, "1")
2184
+ :tSTRING_BEG, "%[",
2185
+ :tSTRING_CONTENT, '1',
2186
+ :tSTRING_END, ']')
2166
2187
 
2167
2188
  @lex.state = :expr_arg
2168
2189
  util_lex_token(" %=1=",