parser 2.0.0.beta5 → 2.0.0.beta6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/README.md +3 -4
- data/doc/AST_FORMAT.md +37 -8
- data/lib/parser/ast/processor.rb +20 -68
- data/lib/parser/builders/default.rb +71 -25
- data/lib/parser/lexer.rl +4 -4
- data/lib/parser/ruby18.y +8 -5
- data/lib/parser/ruby19.y +11 -8
- data/lib/parser/ruby20.y +11 -8
- data/lib/parser/ruby21.y +11 -8
- data/lib/parser/runner/ruby_parse.rb +5 -9
- data/lib/parser/source/comment/associator.rb +2 -0
- data/lib/parser/version.rb +1 -1
- data/parser.gemspec +1 -1
- data/test/test_lexer.rb +8 -0
- data/test/test_parser.rb +204 -92
- data/test/test_source_comment_associator.rb +23 -5
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff9e3b7f7bacab0b950939c52f7df525def64ecc
|
4
|
+
data.tar.gz: 79f7bfdc451009618f190696b9d01ab9fb2a66d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20a42c7ac8a381a0eff6cdd2cca9a9dc74e1b8eea8463e8b12fa910c97e5d666402db364cd9cdd1d57c7ddb17ef148dc38d171a6be5d078f62acaa78a777ba21
|
7
|
+
data.tar.gz: 975bf3b4ebe25e4d34e2a6b5a28cd4447ec91b1b4f5b29bed0b025a29e5a5a42b15c72d73b0b54aeeaffabdcc0357d8edd8091ce4093f8b40be616a0851a317e
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,26 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
+
v2.0.0.beta6 (2013-06-17)
|
5
|
+
-------------------------
|
6
|
+
|
7
|
+
API modifications:
|
8
|
+
* Get rid of "synthesized (nil)". If it's not in source, it's not in AST (fixes #71). (Peter Zotov)
|
9
|
+
* lexer.rl, ruby{18,19,20,21}.y: source maps for interpolation (fixes #27). (Peter Zotov)
|
10
|
+
|
11
|
+
Features implemented:
|
12
|
+
* ruby{18,19,20,21}.y, builders/default: lvar-injecting match (closes #69). (Peter Zotov)
|
13
|
+
* builders/default: implicit matches (refs #69). (Peter Zotov)
|
14
|
+
* builders/default: flip-flops (refs #69). (Peter Zotov)
|
15
|
+
|
16
|
+
Bugs fixed:
|
17
|
+
* lexer.rl: fix an off-by-1 error in heredoc parsing. (Peter Zotov)
|
18
|
+
* lexer.rl: don't fail on "alias $a $b\n# comment\nalias $c $d". (Peter Zotov)
|
19
|
+
* builders/default: fix treatment of masgn in &&/|| (refs #69). (Peter Zotov)
|
20
|
+
* ruby-parse: make -L command line option work again. (Peter Zotov)
|
21
|
+
* ruby{18,19,20,21}.y: begin source map for "if foo\nthen bar end" (fixes #68). (Peter Zotov)
|
22
|
+
* Source::Comment::Associator: gracefully terminate when out of comments (fixes #67). (Peter Zotov)
|
23
|
+
|
4
24
|
v2.0.0.beta5 (2013-06-08)
|
5
25
|
-------------------------
|
6
26
|
|
data/README.md
CHANGED
@@ -31,14 +31,14 @@ p Parser::CurrentRuby.parse("2 + 2")
|
|
31
31
|
Access the AST's source map:
|
32
32
|
|
33
33
|
~~~ ruby
|
34
|
-
p Parser::CurrentRuby.parse("2 + 2").
|
34
|
+
p Parser::CurrentRuby.parse("2 + 2").loc
|
35
35
|
# #<Parser::Source::Map::Send:0x007fe0ca8a69b8
|
36
36
|
# @begin=nil,
|
37
37
|
# @end=nil,
|
38
38
|
# @expression=#<Source::Range (string) 0...5>,
|
39
39
|
# @selector=#<Source::Range (string) 2...3>>
|
40
40
|
|
41
|
-
p Parser::CurrentRuby.parse("2 + 2").
|
41
|
+
p Parser::CurrentRuby.parse("2 + 2").loc.selector.to_source
|
42
42
|
# "+"
|
43
43
|
~~~
|
44
44
|
|
@@ -104,7 +104,6 @@ $ ruby-parse -E -e "2+2"
|
|
104
104
|
* Improved [clang-like][] diagnostic messages with location information.
|
105
105
|
* Written in pure Ruby, runs on MRI 1.8.7 or >=1.9.2, JRuby and Rubinius in 1.8 and 1.9 mode.
|
106
106
|
* Only two runtime dependencies: the gems [ast][] and [slop][].
|
107
|
-
* RubyParser compatibility (WIP, no, not really yet).
|
108
107
|
* [Insane][insane-lexer] Ruby lexer rewritten from scratch in Ragel.
|
109
108
|
* 100% test coverage for Bison grammars (except error recovery).
|
110
109
|
* Readable, commented source code.
|
@@ -128,7 +127,7 @@ Documentation for parser is available online on [rdoc.info](http://rdoc.info/git
|
|
128
127
|
|
129
128
|
## Acknowledgements
|
130
129
|
|
131
|
-
The lexer testsuite
|
130
|
+
The lexer testsuite is derived from [ruby_parser](http://github.com/seattlerb/ruby_parser).
|
132
131
|
|
133
132
|
The Bison parser rules are derived from [Ruby MRI](http://github.com/ruby/ruby) parse.y.
|
134
133
|
|
data/doc/AST_FORMAT.md
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
AST and Source Location RFC
|
2
2
|
===========================
|
3
3
|
|
4
|
-
## Open questions:
|
5
|
-
|
6
|
-
* Should we handle these cases at all? They do not have special syntax associated.
|
7
|
-
1. How to handle lvar-injecting match (`if /(?<a>foo)/ =~ bar`)?
|
8
|
-
1. How to handle magic match (`foo if /bar/`)?
|
9
|
-
1. How to handle sed-like flip-flop?
|
10
|
-
1. How to handle awk-like flip-flop?
|
11
|
-
|
12
4
|
## Literals
|
13
5
|
|
14
6
|
### Singletons
|
@@ -1441,3 +1433,40 @@ Format:
|
|
1441
1433
|
~~~~~~~~~~~~~~~~~~ expression
|
1442
1434
|
~~~
|
1443
1435
|
|
1436
|
+
## Miscellanea
|
1437
|
+
|
1438
|
+
### Flip-flops
|
1439
|
+
|
1440
|
+
Format:
|
1441
|
+
|
1442
|
+
~~~
|
1443
|
+
(iflipflop (lvar :a) (lvar :b))
|
1444
|
+
"if a..b; end"
|
1445
|
+
~~ operator
|
1446
|
+
~~~~ expression
|
1447
|
+
|
1448
|
+
(eflipflop (lvar :a) (lvar :b))
|
1449
|
+
"if a...b; end"
|
1450
|
+
~~~ operator
|
1451
|
+
~~~~~ expression
|
1452
|
+
~~~
|
1453
|
+
|
1454
|
+
### Implicit matches
|
1455
|
+
|
1456
|
+
Format:
|
1457
|
+
|
1458
|
+
~~~
|
1459
|
+
(match-current-line (regexp (str "a") (regopt)))
|
1460
|
+
"if /a/; end"
|
1461
|
+
~~~
|
1462
|
+
|
1463
|
+
### Local variable injecting matches
|
1464
|
+
|
1465
|
+
Format:
|
1466
|
+
|
1467
|
+
~~~
|
1468
|
+
(match-with-lvasgn (regexp (str "(?<match>bar)") (regopt)) (lvar :baz))
|
1469
|
+
"/(?<match>bar)/ =~ baz"
|
1470
|
+
~~ selector
|
1471
|
+
~~~~~~~~~~~~~~~~~~~~~~ expression
|
1472
|
+
~~~
|
data/lib/parser/ast/processor.rb
CHANGED
@@ -20,7 +20,7 @@ module Parser
|
|
20
20
|
def on_var(node)
|
21
21
|
name, = *node
|
22
22
|
|
23
|
-
node
|
23
|
+
node
|
24
24
|
end
|
25
25
|
|
26
26
|
def process_variable_node(node)
|
@@ -37,8 +37,9 @@ module Parser
|
|
37
37
|
def on_vasgn(node)
|
38
38
|
name, value_node = *node
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
node.updated(nil, [
|
41
|
+
name, process(value_node)
|
42
|
+
])
|
42
43
|
end
|
43
44
|
|
44
45
|
def process_var_asgn_node(node)
|
@@ -67,16 +68,17 @@ module Parser
|
|
67
68
|
def on_const(node)
|
68
69
|
scope_node, name = *node
|
69
70
|
|
70
|
-
|
71
|
-
|
71
|
+
node.updated(nil, [
|
72
|
+
process(scope_node), name
|
73
|
+
])
|
72
74
|
end
|
73
75
|
|
74
76
|
def on_casgn(node)
|
75
77
|
scope_node, name, value_node = *node
|
76
78
|
|
77
|
-
|
78
|
-
|
79
|
-
|
79
|
+
node.updated(nil, [
|
80
|
+
process(scope_node), name, process(value_node)
|
81
|
+
])
|
80
82
|
end
|
81
83
|
|
82
84
|
alias on_args process_regular_node
|
@@ -84,8 +86,9 @@ module Parser
|
|
84
86
|
def on_argument(node)
|
85
87
|
arg_name, value_node = *node
|
86
88
|
|
87
|
-
|
88
|
-
|
89
|
+
node.updated(nil, [
|
90
|
+
arg_name, process(value_node)
|
91
|
+
])
|
89
92
|
end
|
90
93
|
|
91
94
|
def process_argument_node(node)
|
@@ -104,18 +107,9 @@ module Parser
|
|
104
107
|
alias on_restarg_expr process_regular_node
|
105
108
|
alias on_blockarg_expr process_regular_node
|
106
109
|
|
107
|
-
alias on_module
|
108
|
-
|
109
|
-
|
110
|
-
name_node, superclass_node, body_node = *node
|
111
|
-
|
112
|
-
superclass_node = process(superclass_node) if superclass_node
|
113
|
-
node.updated(nil, [
|
114
|
-
name_node, superclass_node, process(body_node)
|
115
|
-
])
|
116
|
-
end
|
117
|
-
|
118
|
-
alias on_sclass process_regular_node
|
110
|
+
alias on_module process_regular_node
|
111
|
+
alias on_class process_regular_node
|
112
|
+
alias on_sclass process_regular_node
|
119
113
|
|
120
114
|
def on_def(node)
|
121
115
|
name, args_node, body_node = *node
|
@@ -166,55 +160,13 @@ module Parser
|
|
166
160
|
alias on_and process_regular_node
|
167
161
|
alias on_or process_regular_node
|
168
162
|
|
169
|
-
|
170
|
-
cond_node, if_true_node, if_false_node = *node
|
171
|
-
|
172
|
-
if_true_node = process(if_true_node) if if_true_node
|
173
|
-
if_false_node = process(if_false_node) if if_false_node
|
174
|
-
|
175
|
-
node.updated(nil, [
|
176
|
-
process(cond_node),
|
177
|
-
if_true_node, if_false_node
|
178
|
-
])
|
179
|
-
end
|
163
|
+
alias on_if process_regular_node
|
180
164
|
|
181
165
|
alias on_when process_regular_node
|
166
|
+
alias on_case process_regular_node
|
182
167
|
|
183
|
-
|
184
|
-
|
185
|
-
when_nodes, else_node = bodies[0..-2], bodies[-1]
|
186
|
-
|
187
|
-
cond_node = process(cond_node) if cond_node
|
188
|
-
else_node = process(else_node) if else_node
|
189
|
-
node.updated(nil, [
|
190
|
-
cond_node,
|
191
|
-
*(process_all(when_nodes) << else_node)
|
192
|
-
])
|
193
|
-
end
|
194
|
-
|
195
|
-
def on_resbody(node)
|
196
|
-
exc_list_node, exc_var_node, body_node = *node
|
197
|
-
|
198
|
-
exc_list_node = process(exc_list_node) if exc_list_node
|
199
|
-
exc_var_node = process(exc_var_node) if exc_var_node
|
200
|
-
|
201
|
-
node.updated(nil, [
|
202
|
-
exc_list_node, exc_var_node,
|
203
|
-
process(body_node)
|
204
|
-
])
|
205
|
-
end
|
206
|
-
|
207
|
-
def on_rescue(node)
|
208
|
-
body_node, *handlers = *node
|
209
|
-
handler_nodes, else_node = handlers[0..-2], handlers[-1]
|
210
|
-
|
211
|
-
else_node = process(else_node) if else_node
|
212
|
-
node.updated(nil, [
|
213
|
-
process(body_node),
|
214
|
-
*(process_all(handler_nodes) << else_node)
|
215
|
-
])
|
216
|
-
end
|
217
|
-
|
168
|
+
alias on_resbody process_regular_node
|
169
|
+
alias on_rescue process_regular_node
|
218
170
|
alias on_ensure process_regular_node
|
219
171
|
|
220
172
|
alias on_begin process_regular_node
|
@@ -616,6 +616,28 @@ module Parser
|
|
616
616
|
source_map)
|
617
617
|
end
|
618
618
|
|
619
|
+
def match_op(receiver, match_t, arg)
|
620
|
+
source_map = send_binary_op_map(receiver, match_t, arg)
|
621
|
+
|
622
|
+
if receiver.type == :regexp &&
|
623
|
+
receiver.children.count == 2 &&
|
624
|
+
receiver.children.first.type == :str
|
625
|
+
|
626
|
+
regexp_str, _regopt = *receiver
|
627
|
+
regexp_body, = *regexp_str
|
628
|
+
|
629
|
+
Regexp.new(regexp_body).names.each do |name|
|
630
|
+
@parser.static_env.declare(name)
|
631
|
+
end
|
632
|
+
|
633
|
+
n(:match_with_lvasgn, [ receiver, arg ],
|
634
|
+
source_map)
|
635
|
+
else
|
636
|
+
n(:send, [ receiver, :=~, arg ],
|
637
|
+
source_map)
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
619
641
|
def unary_op(op_t, receiver)
|
620
642
|
case value(op_t)
|
621
643
|
when '+', '-'
|
@@ -628,14 +650,17 @@ module Parser
|
|
628
650
|
send_unary_op_map(op_t, receiver))
|
629
651
|
end
|
630
652
|
|
631
|
-
def not_op(not_t, receiver=nil)
|
653
|
+
def not_op(not_t, begin_t=nil, receiver=nil, end_t=nil)
|
632
654
|
if @parser.version == 18
|
633
655
|
n(:not, [ receiver ],
|
634
656
|
unary_op_map(not_t, receiver))
|
635
657
|
else
|
636
658
|
if receiver.nil?
|
637
|
-
|
638
|
-
|
659
|
+
nil_node = n0(:begin, collection_map(begin_t, nil, end_t))
|
660
|
+
|
661
|
+
n(:send, [
|
662
|
+
nil_node, :'!'
|
663
|
+
], send_unary_op_map(not_t, nil_node))
|
639
664
|
else
|
640
665
|
n(:send, [ receiver, :'!' ],
|
641
666
|
send_unary_op_map(not_t, receiver))
|
@@ -650,7 +675,7 @@ module Parser
|
|
650
675
|
# Logical operations: and, or
|
651
676
|
|
652
677
|
def logical_op(type, lhs, op_t, rhs)
|
653
|
-
n(type, [
|
678
|
+
n(type, [ lhs, rhs ],
|
654
679
|
binary_op_map(lhs, op_t, rhs))
|
655
680
|
end
|
656
681
|
|
@@ -765,10 +790,10 @@ module Parser
|
|
765
790
|
|
766
791
|
def compstmt(statements)
|
767
792
|
case
|
793
|
+
when statements.none?
|
794
|
+
nil
|
768
795
|
when statements.one?
|
769
796
|
statements.first
|
770
|
-
when statements.none?
|
771
|
-
n0(:nil, expr_map(nil))
|
772
797
|
else
|
773
798
|
n(:begin, statements,
|
774
799
|
collection_map(nil, statements, nil))
|
@@ -776,11 +801,10 @@ module Parser
|
|
776
801
|
end
|
777
802
|
|
778
803
|
def begin(begin_t, body, end_t)
|
779
|
-
if body.nil?
|
780
|
-
# A nil expression
|
781
|
-
|
782
|
-
|
783
|
-
expr_map(loc(begin_t).join(loc(end_t))))
|
804
|
+
if body.nil?
|
805
|
+
# A nil expression: `()' or `begin end'.
|
806
|
+
n0(:begin,
|
807
|
+
collection_map(begin_t, nil, end_t))
|
784
808
|
elsif body.type == :mlhs ||
|
785
809
|
(body.type == :begin &&
|
786
810
|
body.loc.begin.nil? && body.loc.end.nil?)
|
@@ -794,6 +818,8 @@ module Parser
|
|
794
818
|
end
|
795
819
|
end
|
796
820
|
|
821
|
+
alias :begin_keyword :begin
|
822
|
+
|
797
823
|
private
|
798
824
|
|
799
825
|
#
|
@@ -801,14 +827,37 @@ module Parser
|
|
801
827
|
#
|
802
828
|
|
803
829
|
def check_condition(cond)
|
804
|
-
|
830
|
+
case cond.type
|
831
|
+
when :masgn
|
805
832
|
diagnostic :error, ERRORS[:masgn_as_condition],
|
806
833
|
cond.loc.expression
|
807
|
-
elsif cond.type == :begin
|
808
|
-
check_condition(cond.children.last)
|
809
|
-
end
|
810
834
|
|
811
|
-
|
835
|
+
when :begin
|
836
|
+
if cond.children.count == 1
|
837
|
+
check_condition(cond.children.last)
|
838
|
+
else
|
839
|
+
cond
|
840
|
+
end
|
841
|
+
|
842
|
+
when :and, :or, :irange, :erange
|
843
|
+
lhs, rhs = *cond
|
844
|
+
|
845
|
+
type = case cond.type
|
846
|
+
when :irange; :iflipflop
|
847
|
+
when :erange; :eflipflop
|
848
|
+
end
|
849
|
+
|
850
|
+
cond.updated(type, [
|
851
|
+
check_condition(lhs),
|
852
|
+
check_condition(rhs)
|
853
|
+
])
|
854
|
+
|
855
|
+
when :regexp
|
856
|
+
n(:match_current_line, [ cond ], nil)
|
857
|
+
|
858
|
+
else
|
859
|
+
cond
|
860
|
+
end
|
812
861
|
end
|
813
862
|
|
814
863
|
def check_duplicate_args(args, map={})
|
@@ -1074,7 +1123,7 @@ module Parser
|
|
1074
1123
|
|
1075
1124
|
if end_t
|
1076
1125
|
end_l = loc(end_t)
|
1077
|
-
elsif args.any? && !
|
1126
|
+
elsif args.any? && !args.last.nil?
|
1078
1127
|
end_l = args.last.loc.expression
|
1079
1128
|
elsif args.any? && args.count > 1
|
1080
1129
|
end_l = args[-2].loc.expression
|
@@ -1098,7 +1147,7 @@ module Parser
|
|
1098
1147
|
end_l = else_e.loc.expression
|
1099
1148
|
elsif loc(else_t)
|
1100
1149
|
end_l = loc(else_t)
|
1101
|
-
elsif body_e.loc.expression
|
1150
|
+
elsif body_e && body_e.loc.expression
|
1102
1151
|
end_l = body_e.loc.expression
|
1103
1152
|
elsif loc(begin_t)
|
1104
1153
|
end_l = loc(begin_t)
|
@@ -1125,7 +1174,8 @@ module Parser
|
|
1125
1174
|
def rescue_body_map(keyword_t, exc_list_e, assoc_t,
|
1126
1175
|
exc_var_e, then_t,
|
1127
1176
|
compstmt_e)
|
1128
|
-
end_l = compstmt_e.loc.expression
|
1177
|
+
end_l = compstmt_e.loc.expression if compstmt_e
|
1178
|
+
end_l = loc(then_t) if end_l.nil? && then_t
|
1129
1179
|
end_l = exc_var_e.loc.expression if end_l.nil? && exc_var_e
|
1130
1180
|
end_l = exc_list_e.loc.expression if end_l.nil? && exc_list_e
|
1131
1181
|
end_l = loc(keyword_t) if end_l.nil?
|
@@ -1136,7 +1186,7 @@ module Parser
|
|
1136
1186
|
|
1137
1187
|
def eh_keyword_map(compstmt_e, keyword_t, body_es,
|
1138
1188
|
else_t, else_e)
|
1139
|
-
if
|
1189
|
+
if compstmt_e.nil?
|
1140
1190
|
if keyword_t.nil?
|
1141
1191
|
begin_l = body_es.first.loc.expression
|
1142
1192
|
else
|
@@ -1148,7 +1198,7 @@ module Parser
|
|
1148
1198
|
|
1149
1199
|
if else_t
|
1150
1200
|
end_l = else_e.loc.expression
|
1151
|
-
elsif !
|
1201
|
+
elsif !body_es.last.nil?
|
1152
1202
|
end_l = body_es.last.loc.expression
|
1153
1203
|
else
|
1154
1204
|
end_l = loc(keyword_t)
|
@@ -1167,10 +1217,6 @@ module Parser
|
|
1167
1217
|
[:str, :dstr].include?(parts.first.type)
|
1168
1218
|
end
|
1169
1219
|
|
1170
|
-
def synthesized_nil?(node)
|
1171
|
-
node.type == :nil && node.loc.expression.nil?
|
1172
|
-
end
|
1173
|
-
|
1174
1220
|
def value(token)
|
1175
1221
|
token[0]
|
1176
1222
|
end
|