ruby_parser 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ruby_parser might be problematic. Click here for more details.
- data/.autotest +21 -0
- data/History.txt +5 -0
- data/Manifest.txt +9 -0
- data/README.txt +64 -0
- data/Rakefile +56 -0
- data/lib/ruby_lexer.rb +2751 -0
- data/lib/ruby_parser.rb +5987 -0
- data/lib/ruby_parser.y +1648 -0
- data/test/test_ruby_lexer.rb +398 -0
- data/test/test_ruby_parser.rb +326 -0
- metadata +83 -0
data/lib/ruby_parser.y
ADDED
@@ -0,0 +1,1648 @@
|
|
1
|
+
# -*- racc -*-
|
2
|
+
|
3
|
+
class RubyParser
|
4
|
+
|
5
|
+
token kCLASS kMODULE kDEF kUNDEF kBEGIN kRESCUE kENSURE kEND kIF kUNLESS
|
6
|
+
kTHEN kELSIF kELSE kCASE kWHEN kWHILE kUNTIL kFOR kBREAK kNEXT
|
7
|
+
kREDO kRETRY kIN kDO kDO_COND kDO_BLOCK kRETURN kYIELD kSUPER
|
8
|
+
kSELF kNIL kTRUE kFALSE kAND kOR kNOT kIF_MOD kUNLESS_MOD kWHILE_MOD
|
9
|
+
kUNTIL_MOD kRESCUE_MOD kALIAS kDEFINED klBEGIN klEND k__LINE__
|
10
|
+
k__FILE__ tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tNTH_REF
|
11
|
+
tBACK_REF tSTRING_CONTENT tINTEGER tFLOAT tREGEXP_END tUPLUS
|
12
|
+
tUMINUS tUMINUS_NUM tPOW tCMP tEQ tEQQ tNEQ tGEQ tLEQ tANDOP
|
13
|
+
tOROP tMATCH tNMATCH tDOT tDOT2 tDOT3 tAREF tASET tLSHFT tRSHFT
|
14
|
+
tCOLON2 tCOLON3 tOP_ASGN tASSOC tLPAREN tLPAREN2 tRPAREN tLPAREN_ARG
|
15
|
+
tLBRACK tRBRACK tLBRACE tLBRACE_ARG tSTAR tSTAR2 tAMPER tAMPER2
|
16
|
+
tTILDE tPERCENT tDIVIDE tPLUS tMINUS tLT tGT tPIPE tBANG tCARET
|
17
|
+
tLCURLY tRCURLY tBACK_REF2 tSYMBEG tSTRING_BEG tXSTRING_BEG tREGEXP_BEG
|
18
|
+
tWORDS_BEG tQWORDS_BEG tSTRING_DBEG tSTRING_DVAR tSTRING_END
|
19
|
+
tLAST_TOKEN
|
20
|
+
|
21
|
+
preclow
|
22
|
+
nonassoc tLOWEST
|
23
|
+
nonassoc tLBRACE_ARG
|
24
|
+
nonassoc kIF_MOD kUNLESS_MOD kWHILE_MOD kUNTIL_MOD
|
25
|
+
left kOR kAND
|
26
|
+
right kNOT
|
27
|
+
nonassoc kDEFINED
|
28
|
+
right '=' tOP_ASGN
|
29
|
+
left kRESCUE_MOD
|
30
|
+
right '?' ':'
|
31
|
+
nonassoc tDOT2 tDOT3
|
32
|
+
left tOROP
|
33
|
+
left tANDOP
|
34
|
+
nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH
|
35
|
+
left tGT tGEQ tLT tLEQ
|
36
|
+
left tPIPE tCARET
|
37
|
+
left tAMPER2
|
38
|
+
left tLSHFT tRSHFT
|
39
|
+
left tPLUS tMINUS
|
40
|
+
left tSTAR2 tDIVIDE tPERCENT
|
41
|
+
right tUMINUS_NUM tUMINUS
|
42
|
+
right tPOW
|
43
|
+
right tBANG tTILDE tUPLUS
|
44
|
+
prechigh
|
45
|
+
|
46
|
+
rule
|
47
|
+
|
48
|
+
program : {
|
49
|
+
self.lexer.state = :expr_beg
|
50
|
+
} compstmt {
|
51
|
+
result = val[1]
|
52
|
+
}
|
53
|
+
|
54
|
+
bodystmt : compstmt opt_rescue opt_else opt_ensure {
|
55
|
+
result = val[0]
|
56
|
+
|
57
|
+
if val[1] then
|
58
|
+
result = s(:rescue)
|
59
|
+
result << val[0] if val[0]
|
60
|
+
result << val[1] if val[1]
|
61
|
+
result << val[2] if val[2]
|
62
|
+
elsif not val[2].nil? then
|
63
|
+
warning("else without rescue is useless")
|
64
|
+
result = block_append(result, val[2])
|
65
|
+
end
|
66
|
+
|
67
|
+
result = s(:ensure, result, val[3]).compact if val[3]
|
68
|
+
}
|
69
|
+
|
70
|
+
compstmt : stmts opt_terms {
|
71
|
+
result = void_stmts(val[0])
|
72
|
+
}
|
73
|
+
|
74
|
+
stmts : none
|
75
|
+
| stmt # TODO: wrap in newline node
|
76
|
+
| stmts terms stmt {
|
77
|
+
result = self.block_append(val[0], val[2])
|
78
|
+
}
|
79
|
+
| error stmt {
|
80
|
+
result = val[1];
|
81
|
+
}
|
82
|
+
|
83
|
+
stmt : kALIAS fitem { lexer.state = :expr_fname } fitem {
|
84
|
+
result = s(:alias, val[1], val[3])
|
85
|
+
}
|
86
|
+
| kALIAS tGVAR tGVAR {
|
87
|
+
result = s(:valias, val[1].value.to_sym, val[2].value.to_sym)
|
88
|
+
}
|
89
|
+
| kALIAS tGVAR tBACK_REF {
|
90
|
+
result = s(:valias, val[1].value.to_sym, :"$#{val[2].last}")
|
91
|
+
}
|
92
|
+
| kALIAS tGVAR tNTH_REF {
|
93
|
+
yyerror("can't make alias for the number variables");
|
94
|
+
}
|
95
|
+
| kUNDEF undef_list {
|
96
|
+
result = val[1]
|
97
|
+
}
|
98
|
+
| stmt kIF_MOD expr_value {
|
99
|
+
val[2] = cond val[2]
|
100
|
+
if val[2][0] == :not then
|
101
|
+
result = s(:if, val[2].last, nil, val[0])
|
102
|
+
else
|
103
|
+
result = s(:if, val[2], val[0], nil)
|
104
|
+
end
|
105
|
+
}
|
106
|
+
| stmt kUNLESS_MOD expr_value {
|
107
|
+
val[2] = cond val[2]
|
108
|
+
if val[2][0] == :not then
|
109
|
+
result = s(:if, val[2].last, val[0], nil)
|
110
|
+
else
|
111
|
+
result = s(:if, val[2], nil, val[0])
|
112
|
+
end
|
113
|
+
}
|
114
|
+
| stmt kWHILE_MOD expr_value {
|
115
|
+
block, pre = val[0], true
|
116
|
+
block, pre = block.last, false if block[0] == :begin
|
117
|
+
|
118
|
+
val[2] = cond val[2]
|
119
|
+
if val[2][0] == :not then
|
120
|
+
result = s(:until, val[2].last, block, pre)
|
121
|
+
else
|
122
|
+
result = s(:while, val[2], block, pre)
|
123
|
+
end
|
124
|
+
}
|
125
|
+
| stmt kUNTIL_MOD expr_value { # REFACTOR
|
126
|
+
block, pre = val[0], true
|
127
|
+
block, pre = block.last, false if block[0] == :begin
|
128
|
+
|
129
|
+
val[2] = cond val[2]
|
130
|
+
if val[2][0] == :not then
|
131
|
+
result = s(:while, val[2].last, block, pre)
|
132
|
+
else
|
133
|
+
result = s(:until, val[2], block, pre)
|
134
|
+
end
|
135
|
+
}
|
136
|
+
| stmt kRESCUE_MOD stmt {
|
137
|
+
result = s(:rescue, val[0], s(:resbody, nil, val[2]))
|
138
|
+
}
|
139
|
+
| klBEGIN {
|
140
|
+
if (self.in_def || self.in_single > 0) then
|
141
|
+
# yyerror("BEGIN in method"); HACK
|
142
|
+
end
|
143
|
+
self.env.extend;
|
144
|
+
} tLCURLY compstmt tRCURLY {
|
145
|
+
result = s(:iter, s(:preexe), nil)
|
146
|
+
result << val[3] if val[3]
|
147
|
+
result = nil # TODO: since it isn't supposed to go in the AST
|
148
|
+
}
|
149
|
+
| klEND tLCURLY compstmt tRCURLY {
|
150
|
+
if (self.in_def || self.in_single > 0) then
|
151
|
+
# yyerror("END in method; use at_exit"); HACK
|
152
|
+
end
|
153
|
+
result = s(:iter, s(:postexe), nil)
|
154
|
+
result << val[2] if val[2]
|
155
|
+
}
|
156
|
+
| lhs '=' command_call {
|
157
|
+
result = self.node_assign(val[0], val[2])
|
158
|
+
}
|
159
|
+
| mlhs '=' command_call {
|
160
|
+
val[2] = value_expr(val[2])
|
161
|
+
result = val[0] << if val[0][1] then
|
162
|
+
s(:to_ary, val[2])
|
163
|
+
else
|
164
|
+
val[0].delete_at 1 # remove the nil
|
165
|
+
s(:array, val[2])
|
166
|
+
end
|
167
|
+
}
|
168
|
+
| var_lhs tOP_ASGN command_call {
|
169
|
+
name = val[0].last
|
170
|
+
asgn_op = val[1].value.to_sym
|
171
|
+
val[2] = value_expr(val[2])
|
172
|
+
|
173
|
+
case asgn_op
|
174
|
+
when :"||" then
|
175
|
+
val[0][2] = (val[2]);
|
176
|
+
result = s(:op_asgn_or, self.gettable(name), val[0])
|
177
|
+
when :"&&" then
|
178
|
+
val[0][2] = (val[2]);
|
179
|
+
result = s(:op_asgn_and, self.gettable(name), val[0])
|
180
|
+
else
|
181
|
+
result = val[0]
|
182
|
+
result << s(:call, self.gettable(name), asgn_op, s(:array, val[2]))
|
183
|
+
end
|
184
|
+
}
|
185
|
+
| primary_value '[' aref_args tRBRACK tOP_ASGN command_call {
|
186
|
+
result = s(:op_asgn1, val[0], val[2], val[4].value.to_sym, val[5]);
|
187
|
+
}
|
188
|
+
| primary_value tDOT tIDENTIFIER tOP_ASGN command_call {
|
189
|
+
result = s(:op_asgn, val[0], val[4], val[2].value, val[3].value);
|
190
|
+
}
|
191
|
+
| primary_value tDOT tCONSTANT tOP_ASGN command_call {
|
192
|
+
result = s(:op_asgn, val[0], val[4], val[2].value, val[3].value);
|
193
|
+
}
|
194
|
+
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call {
|
195
|
+
result = s(:op_asgn, val[0], val[4], val[2].value, val[3].value);
|
196
|
+
}
|
197
|
+
| backref tOP_ASGN command_call {
|
198
|
+
self.backref_assign_error(val[0]);
|
199
|
+
}
|
200
|
+
| lhs '=' mrhs {
|
201
|
+
result = self.node_assign(val[0], s(:svalue, val[2]))
|
202
|
+
}
|
203
|
+
| mlhs '=' arg_value {
|
204
|
+
result = val[0] << if val[0][1] then
|
205
|
+
s(:to_ary, val[2])
|
206
|
+
else
|
207
|
+
val[0].delete_at 1 if val[0][1].nil?
|
208
|
+
s(:array, val[2])
|
209
|
+
end
|
210
|
+
}
|
211
|
+
| mlhs '=' mrhs {
|
212
|
+
val[0].delete_at 1 if val[0][1].nil?
|
213
|
+
result = val[0] << val[2]
|
214
|
+
}
|
215
|
+
| expr
|
216
|
+
|
217
|
+
|
218
|
+
expr : command_call
|
219
|
+
| expr kAND expr {
|
220
|
+
result = logop(:and, val[0], val[2])
|
221
|
+
}
|
222
|
+
| expr kOR expr {
|
223
|
+
result = logop(:or, val[0], val[2])
|
224
|
+
}
|
225
|
+
| kNOT expr {
|
226
|
+
result = s(:not, val[1])
|
227
|
+
}
|
228
|
+
| tBANG command_call {
|
229
|
+
result = s(:not, val[1])
|
230
|
+
}
|
231
|
+
| arg
|
232
|
+
|
233
|
+
expr_value : expr {
|
234
|
+
result = value_expr(val[0])
|
235
|
+
}
|
236
|
+
|
237
|
+
command_call : command
|
238
|
+
| block_command
|
239
|
+
| kRETURN call_args {
|
240
|
+
result = s(:return, ret_args(val[1]))
|
241
|
+
}
|
242
|
+
| kBREAK call_args {
|
243
|
+
result = s(:break, ret_args(val[1]))
|
244
|
+
}
|
245
|
+
| kNEXT call_args {
|
246
|
+
result = s(:next, ret_args(val[1]))
|
247
|
+
}
|
248
|
+
|
249
|
+
block_command : block_call
|
250
|
+
| block_call tDOT operation2 command_args {
|
251
|
+
result = s(:call, val[0], val[2], val[3]);
|
252
|
+
}
|
253
|
+
| block_call tCOLON2 operation2 command_args {
|
254
|
+
result = s(:call, val[0], val[2], val[3]);
|
255
|
+
}
|
256
|
+
|
257
|
+
cmd_brace_block : tLBRACE_ARG {
|
258
|
+
self.env.extend :dynamic
|
259
|
+
} opt_block_var { result = self.env.dynamic.keys }
|
260
|
+
compstmt tRCURLY {
|
261
|
+
result = s(:iter, val[2], dyna_init(val[4], val[3]))
|
262
|
+
self.env.unextend;
|
263
|
+
}
|
264
|
+
|
265
|
+
command : operation command_args = tLOWEST {
|
266
|
+
result = new_fcall(val[0].value.to_sym, val[1])
|
267
|
+
}
|
268
|
+
| operation command_args cmd_brace_block {
|
269
|
+
result = new_fcall(val[0].value.to_sym, val[1])
|
270
|
+
if val[2] then
|
271
|
+
if result[0] == :block_pass then
|
272
|
+
raise "both block arg and actual block given"
|
273
|
+
end
|
274
|
+
val[2] << result
|
275
|
+
result = val[2]
|
276
|
+
end
|
277
|
+
}
|
278
|
+
| primary_value tDOT operation2 command_args = tLOWEST {
|
279
|
+
result = new_call(val[0], val[2].to_sym, val[3])
|
280
|
+
}
|
281
|
+
| primary_value tDOT operation2 command_args cmd_brace_block {
|
282
|
+
result = new_call(val[0], val[2].to_sym, val[3])
|
283
|
+
}
|
284
|
+
| primary_value tCOLON2 operation2 command_args = tLOWEST {
|
285
|
+
result = new_call(val[0], val[2].to_sym, val[3])
|
286
|
+
}
|
287
|
+
| primary_value tCOLON2 operation2 command_args cmd_brace_block {
|
288
|
+
result = new_call(val[0], val[2].to_sym, val[3])
|
289
|
+
if val[4] then
|
290
|
+
if result[0] == :block_pass then # REFACTOR
|
291
|
+
raise "both block arg and actual block given"
|
292
|
+
end
|
293
|
+
val[2] << result
|
294
|
+
result = val[2]
|
295
|
+
end
|
296
|
+
}
|
297
|
+
| kSUPER command_args {
|
298
|
+
result = self.new_super(val[1]);
|
299
|
+
}
|
300
|
+
| kYIELD command_args {
|
301
|
+
result = self.new_yield(val[1]);
|
302
|
+
}
|
303
|
+
|
304
|
+
mlhs : mlhs_basic
|
305
|
+
| tLPAREN mlhs_entry tRPAREN {
|
306
|
+
result = val[1];
|
307
|
+
}
|
308
|
+
|
309
|
+
mlhs_entry : mlhs_basic
|
310
|
+
| tLPAREN mlhs_entry tRPAREN {
|
311
|
+
result = s(:masgn, s(:array, val[1]));
|
312
|
+
}
|
313
|
+
|
314
|
+
mlhs_basic : mlhs_head {
|
315
|
+
result = s(:masgn, val[0]);
|
316
|
+
}
|
317
|
+
| mlhs_head mlhs_item {
|
318
|
+
result = s(:masgn, val[0] << val[1].compact);
|
319
|
+
}
|
320
|
+
| mlhs_head tSTAR mlhs_node {
|
321
|
+
result = s(:masgn, val[0], val[2]);
|
322
|
+
}
|
323
|
+
| mlhs_head tSTAR {
|
324
|
+
result = s(:masgn, val[0], s(:splat))
|
325
|
+
}
|
326
|
+
| tSTAR mlhs_node {
|
327
|
+
result = s(:masgn, nil, val[1]);
|
328
|
+
}
|
329
|
+
| tSTAR {
|
330
|
+
result = s(:masgn, nil, s(:splat))
|
331
|
+
}
|
332
|
+
|
333
|
+
mlhs_item : mlhs_node
|
334
|
+
| tLPAREN mlhs_entry tRPAREN {
|
335
|
+
result = val[1];
|
336
|
+
}
|
337
|
+
|
338
|
+
mlhs_head : mlhs_item ',' {
|
339
|
+
result = s(:array, val[0])
|
340
|
+
}
|
341
|
+
| mlhs_head mlhs_item ',' {
|
342
|
+
result = val[0] << val[1].compact
|
343
|
+
}
|
344
|
+
|
345
|
+
mlhs_node : variable {
|
346
|
+
result = self.assignable(val[0])
|
347
|
+
}
|
348
|
+
| primary_value '[' aref_args tRBRACK {
|
349
|
+
result = self.aryset(val[0], val[2]);
|
350
|
+
}
|
351
|
+
| primary_value tDOT tIDENTIFIER {
|
352
|
+
result = s(:attrasgn, val[0], :"#{val[2].value}=");
|
353
|
+
}
|
354
|
+
| primary_value tCOLON2 tIDENTIFIER {
|
355
|
+
result = s(:attrasgn, val[0], :"#{val[2].value}=");
|
356
|
+
}
|
357
|
+
| primary_value tDOT tCONSTANT {
|
358
|
+
result = s(:attrasgn, val[0], :"#{val[2].value}=");
|
359
|
+
}
|
360
|
+
| primary_value tCOLON2 tCONSTANT {
|
361
|
+
if (self.in_def || self.in_single > 0) then
|
362
|
+
yyerror("dynamic constant assignment");
|
363
|
+
end
|
364
|
+
|
365
|
+
result = s(:constdecl, nil,
|
366
|
+
s(:colon2, val[0], val[2].value), nil)
|
367
|
+
}
|
368
|
+
| tCOLON3 tCONSTANT {
|
369
|
+
if (self.in_def || self.in_single > 0) then
|
370
|
+
yyerror("dynamic constant assignment");
|
371
|
+
end
|
372
|
+
|
373
|
+
result = s(:const, nil, s(:colon3, val[1].value.to_sym))
|
374
|
+
}
|
375
|
+
| backref {
|
376
|
+
self.backref_assign_error(val[0]);
|
377
|
+
}
|
378
|
+
|
379
|
+
lhs : variable {
|
380
|
+
result = self.assignable(val[0])
|
381
|
+
}
|
382
|
+
| primary_value '[' aref_args tRBRACK {
|
383
|
+
result = self.aryset(val[0], val[2]);
|
384
|
+
}
|
385
|
+
| primary_value tDOT tIDENTIFIER {
|
386
|
+
result = s(:attrasgn, val[0], :"#{val[2].value}=");
|
387
|
+
}
|
388
|
+
| primary_value tCOLON2 tIDENTIFIER {
|
389
|
+
result = s(:attrasgn, val[0], :"#{val[2].value}=");
|
390
|
+
}
|
391
|
+
| primary_value tDOT tCONSTANT {
|
392
|
+
result = s(:attrasgn, val[0], :"#{val[2].value}=");
|
393
|
+
}
|
394
|
+
| primary_value tCOLON2 tCONSTANT {
|
395
|
+
if (self.in_def || self.in_single > 0) then
|
396
|
+
yyerror("dynamic constant assignment");
|
397
|
+
end
|
398
|
+
|
399
|
+
result = s(:constdecl, nil, s(:colon2, val[0], val[2].value), nil);
|
400
|
+
}
|
401
|
+
| tCOLON3 tCONSTANT {
|
402
|
+
if (self.in_def || self.in_single > 0) then
|
403
|
+
yyerror("dynamic constant assignment");
|
404
|
+
end
|
405
|
+
|
406
|
+
result = s(:const, nil, s(:colon3, val[1].value.to_sym))
|
407
|
+
}
|
408
|
+
| backref {
|
409
|
+
self.backref_assign_error(val[0]);
|
410
|
+
}
|
411
|
+
|
412
|
+
cname : tIDENTIFIER {
|
413
|
+
yyerror("class/module name must be CONSTANT");
|
414
|
+
}
|
415
|
+
| tCONSTANT
|
416
|
+
|
417
|
+
cpath : tCOLON3 cname {
|
418
|
+
result = s(:colon3, val[1].value.to_sym)
|
419
|
+
}
|
420
|
+
| cname {
|
421
|
+
result = s(:colon2, nil, val[0].value);
|
422
|
+
}
|
423
|
+
| primary_value tCOLON2 cname {
|
424
|
+
result = s(:colon2, val[0], val[2].value);
|
425
|
+
}
|
426
|
+
|
427
|
+
fname : tIDENTIFIER | tCONSTANT | tFID
|
428
|
+
| op {
|
429
|
+
lexer.state = :expr_end
|
430
|
+
result = val[0];
|
431
|
+
}
|
432
|
+
|
433
|
+
| reswords {
|
434
|
+
lexer.state = :expr_end
|
435
|
+
result = val[0];
|
436
|
+
}
|
437
|
+
|
438
|
+
fitem : fname { result = s(:lit, val[0].value.to_sym) } # TODO: cruby has fsym and dsym
|
439
|
+
| symbol { result = s(:lit, val[0]) }
|
440
|
+
|
441
|
+
undef_list : fitem {
|
442
|
+
result = s(:undef, val[0])
|
443
|
+
}
|
444
|
+
| undef_list ',' {
|
445
|
+
lexer.state = :expr_fname
|
446
|
+
} fitem {
|
447
|
+
result = self.block_append(val[0], s(:undef, val[3]))
|
448
|
+
}
|
449
|
+
|
450
|
+
op : tPIPE | tCARET | tAMPER2 | tCMP | tEQ | tEQQ | tMATCH
|
451
|
+
| tGT | tGEQ | tLT | tLEQ | tLSHFT | tRSHFT | tPLUS
|
452
|
+
| tMINUS | tSTAR2 | tSTAR | tDIVIDE | tPERCENT | tPOW | tTILDE
|
453
|
+
| tUPLUS | tUMINUS | tAREF | tASET | tBACK_REF2
|
454
|
+
|
455
|
+
reswords : k__LINE__ | k__FILE__ | klBEGIN | klEND | kALIAS | kAND
|
456
|
+
| kBEGIN | kBREAK | kCASE | kCLASS | kDEF | kDEFINED
|
457
|
+
| kDO | kELSE | kELSIF | kEND | kENSURE | kFALSE
|
458
|
+
| kFOR | kIN | kMODULE | kNEXT | kNIL | kNOT
|
459
|
+
| kOR | kREDO | kRESCUE | kRETRY | kRETURN | kSELF
|
460
|
+
| kSUPER | kTHEN | kTRUE | kUNDEF | kWHEN | kYIELD
|
461
|
+
| kIF_MOD | kUNLESS_MOD | kWHILE_MOD | kUNTIL_MOD | kRESCUE_MOD
|
462
|
+
|
463
|
+
arg : lhs '=' arg {
|
464
|
+
result = self.node_assign(val[0], val[2])
|
465
|
+
}
|
466
|
+
| lhs '=' arg kRESCUE_MOD arg {
|
467
|
+
result = self.node_assign(val[0],
|
468
|
+
s(:rescue, val[2], s(:resbody, nil, val[4])))
|
469
|
+
}
|
470
|
+
| var_lhs tOP_ASGN arg {
|
471
|
+
name = val[0].value
|
472
|
+
asgn_op = val[1].value.to_sym
|
473
|
+
|
474
|
+
val[2] = remove_begin(val[2])
|
475
|
+
|
476
|
+
case asgn_op
|
477
|
+
when :"||" then
|
478
|
+
val[0] << val[2]
|
479
|
+
result = s(:op_asgn_or, self.gettable(name), val[0]);
|
480
|
+
when :"&&" then
|
481
|
+
val[0] << val[2]
|
482
|
+
result = s(:op_asgn_and, self.gettable(name), val[0]);
|
483
|
+
else
|
484
|
+
val[0][2] = s(:call, self.gettable(name), asgn_op, s(:array, val[2]))
|
485
|
+
result = val[0];
|
486
|
+
end
|
487
|
+
}
|
488
|
+
| primary_value '[' aref_args tRBRACK tOP_ASGN arg {
|
489
|
+
result = s(:op_asgn1, val[0], val[2], val[4].value.to_sym, val[5]);
|
490
|
+
}
|
491
|
+
| primary_value tDOT tIDENTIFIER tOP_ASGN arg {
|
492
|
+
result = s(:op_asgn2, val[0], :"#{val[2].value}=", val[3].value.to_sym, val[4]);
|
493
|
+
}
|
494
|
+
| primary_value tDOT tCONSTANT tOP_ASGN arg {
|
495
|
+
result = s(:op_asgn2, val[0], :"#{val[2].value}=", val[3].value.to_sym, val[4])
|
496
|
+
}
|
497
|
+
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg {
|
498
|
+
result = s(:op_asgn, val[0], val[4], val[2].value, val[3].value);
|
499
|
+
}
|
500
|
+
| primary_value tCOLON2 tCONSTANT tOP_ASGN arg {
|
501
|
+
yyerror("constant re-assignment");
|
502
|
+
}
|
503
|
+
| tCOLON3 tCONSTANT tOP_ASGN arg {
|
504
|
+
yyerror("constant re-assignment");
|
505
|
+
}
|
506
|
+
| backref tOP_ASGN arg {
|
507
|
+
self.backref_assign_error(val[0]);
|
508
|
+
}
|
509
|
+
| arg tDOT2 arg {
|
510
|
+
v1, v2 = val[0], val[2]
|
511
|
+
if v1.first == :lit and v2.first == :lit and Fixnum === v1.last and Fixnum === v2.last then
|
512
|
+
result = s(:lit, (v1.last)..(v2.last))
|
513
|
+
else
|
514
|
+
result = s(:dot2, v1, v2)
|
515
|
+
end
|
516
|
+
}
|
517
|
+
| arg tDOT3 arg {
|
518
|
+
v1, v2 = val[0], val[2]
|
519
|
+
if v1.first == :lit and v2.first == :lit and Fixnum === v1.last and Fixnum === v2.last then
|
520
|
+
result = s(:lit, (v1.last)...(v2.last))
|
521
|
+
else
|
522
|
+
result = s(:dot3, v1, v2)
|
523
|
+
end
|
524
|
+
}
|
525
|
+
| arg tPLUS arg {
|
526
|
+
result = s(:call, val[0], :+, s(:array, val[2]))
|
527
|
+
}
|
528
|
+
| arg tMINUS arg {
|
529
|
+
result = s(:call, val[0], :-, s(:array, val[2]))
|
530
|
+
}
|
531
|
+
| arg tSTAR2 arg {
|
532
|
+
result = s(:call, val[0], :*, s(:array, val[2]))
|
533
|
+
}
|
534
|
+
| arg tDIVIDE arg {
|
535
|
+
result = s(:call, val[0], :"/", s(:array, val[2]))
|
536
|
+
}
|
537
|
+
| arg tPERCENT arg {
|
538
|
+
result = s(:call, val[0], :%, s(:array, val[2]))
|
539
|
+
}
|
540
|
+
| arg tPOW arg {
|
541
|
+
result = s(:call, val[0], :**, s(:array, val[2]))
|
542
|
+
}
|
543
|
+
| tUMINUS_NUM tINTEGER tPOW arg {
|
544
|
+
result = s(:call, s(:call, s(:lit, val[1]), :"**", s(:array, val[3])), :"-@");
|
545
|
+
}
|
546
|
+
| tUMINUS_NUM tFLOAT tPOW arg {
|
547
|
+
result = s(:call, s(:call, s(:lit, val[1]), :"**", s(:array, val[3])), :"-@");
|
548
|
+
}
|
549
|
+
| tUPLUS arg {
|
550
|
+
if val[1][0] == :lit then
|
551
|
+
result = val[1]
|
552
|
+
else
|
553
|
+
result = s(:call, val[1], :"+@")
|
554
|
+
end
|
555
|
+
}
|
556
|
+
| tUMINUS arg {
|
557
|
+
result = s(:call, val[1], :"-@");
|
558
|
+
}
|
559
|
+
| arg tPIPE arg {
|
560
|
+
result = s(:call, val[0], :"|", s(:array, val[2]));
|
561
|
+
}
|
562
|
+
| arg tCARET arg {
|
563
|
+
result = s(:call, val[0], :"^", s(:array, val[2]));
|
564
|
+
}
|
565
|
+
| arg tAMPER2 arg {
|
566
|
+
result = s(:call, val[0], :"&", s(:array, val[2]));
|
567
|
+
}
|
568
|
+
| arg tCMP arg {
|
569
|
+
result = s(:call, val[0], :"<=>", s(:array, val[2]));
|
570
|
+
}
|
571
|
+
| arg tGT arg {
|
572
|
+
result = s(:call, val[0], :">", s(:array, val[2]));
|
573
|
+
}
|
574
|
+
| arg tGEQ arg {
|
575
|
+
result = s(:call, val[0], :">=", s(:array, val[2]));
|
576
|
+
}
|
577
|
+
| arg tLT arg {
|
578
|
+
result = s(:call, val[0], :"<", s(:array, val[2]));
|
579
|
+
}
|
580
|
+
| arg tLEQ arg {
|
581
|
+
result = s(:call, val[0], :"<=", s(:array, val[2]));
|
582
|
+
}
|
583
|
+
| arg tEQ arg {
|
584
|
+
result = s(:call, val[0], :"==", s(:array, val[2]));
|
585
|
+
}
|
586
|
+
| arg tEQQ arg {
|
587
|
+
result = s(:call, val[0], :"===", s(:array, val[2]));
|
588
|
+
}
|
589
|
+
| arg tNEQ arg {
|
590
|
+
val[0] = value_expr val[0] # TODO: port call_op and clean these
|
591
|
+
val[2] = value_expr val[2]
|
592
|
+
result = s(:not, s(:call, val[0], :"==", s(:array, val[2])));
|
593
|
+
}
|
594
|
+
| arg tMATCH arg {
|
595
|
+
result = self.get_match_node(val[0], val[2])
|
596
|
+
}
|
597
|
+
| arg tNMATCH arg {
|
598
|
+
result = s(:not, self.get_match_node(val[0], val[2]))
|
599
|
+
}
|
600
|
+
| tBANG arg {
|
601
|
+
result = s(:not, val[1])
|
602
|
+
}
|
603
|
+
| tTILDE arg {
|
604
|
+
val[2] = value_expr val[2]
|
605
|
+
result = s(:call, val[1], :"~");
|
606
|
+
}
|
607
|
+
| arg tLSHFT arg {
|
608
|
+
val[0] = value_expr val[0]
|
609
|
+
val[2] = value_expr val[2]
|
610
|
+
result = s(:call, val[0], :"<<", s(:array, val[2])) # " stupid emacs
|
611
|
+
}
|
612
|
+
| arg tRSHFT arg {
|
613
|
+
val[0] = value_expr val[0]
|
614
|
+
val[2] = value_expr val[2]
|
615
|
+
result = s(:call, val[0], :">>", s(:array, val[2]))
|
616
|
+
}
|
617
|
+
| arg tANDOP arg {
|
618
|
+
result = logop(:and, val[0], val[2])
|
619
|
+
}
|
620
|
+
| arg tOROP arg {
|
621
|
+
result = logop(:or, val[0], val[2])
|
622
|
+
}
|
623
|
+
| kDEFINED opt_nl arg {
|
624
|
+
result = s(:defined, val[2]);
|
625
|
+
}
|
626
|
+
| arg '?' arg ':' arg {
|
627
|
+
result = s(:if, val[0], val[2], val[4]);
|
628
|
+
}
|
629
|
+
| primary
|
630
|
+
|
631
|
+
arg_value : arg {
|
632
|
+
result = value_expr(val[0])
|
633
|
+
}
|
634
|
+
|
635
|
+
aref_args : none
|
636
|
+
| command opt_nl {
|
637
|
+
warning("parenthesize argument(s) for future version");
|
638
|
+
result = s(:array, val[0]);
|
639
|
+
}
|
640
|
+
| args trailer {
|
641
|
+
result = val[0];
|
642
|
+
}
|
643
|
+
| args ',' tSTAR arg opt_nl {
|
644
|
+
result = self.arg_concat(val[0], val[3])
|
645
|
+
}
|
646
|
+
| assocs trailer {
|
647
|
+
result = s(:array, s(:hash, *val[0].values))
|
648
|
+
}
|
649
|
+
| tSTAR arg opt_nl {
|
650
|
+
result = s(:splat, val[1])
|
651
|
+
result.paren = true
|
652
|
+
}
|
653
|
+
|
654
|
+
paren_args : tLPAREN2 none tRPAREN {
|
655
|
+
result = val[1]
|
656
|
+
}
|
657
|
+
| tLPAREN2 call_args opt_nl tRPAREN {
|
658
|
+
result = val[1];
|
659
|
+
}
|
660
|
+
| tLPAREN2 block_call opt_nl tRPAREN {
|
661
|
+
warning("parenthesize argument(s) for future version");
|
662
|
+
result = s(:array, val[1]);
|
663
|
+
}
|
664
|
+
| tLPAREN2 args ',' block_call opt_nl tRPAREN {
|
665
|
+
warning("parenthesize argument(s) for future version");
|
666
|
+
result = val[1].add(val[3]);
|
667
|
+
}
|
668
|
+
|
669
|
+
opt_paren_args: none | paren_args
|
670
|
+
|
671
|
+
call_args : command {
|
672
|
+
warning("parenthesize argument(s) for future version");
|
673
|
+
result = s(:array, val[0])
|
674
|
+
}
|
675
|
+
| args opt_block_arg {
|
676
|
+
result = self.arg_blk_pass(val[0], val[1]);
|
677
|
+
}
|
678
|
+
| args ',' tSTAR arg_value opt_block_arg {
|
679
|
+
result = self.arg_concat(val[0], val[3]);
|
680
|
+
result = self.arg_blk_pass(result, val[4]);
|
681
|
+
}
|
682
|
+
| assocs opt_block_arg {
|
683
|
+
result = s(:array, s(:hash, *val[0].values))
|
684
|
+
result = self.arg_blk_pass(result, val[1]);
|
685
|
+
}
|
686
|
+
| assocs ',' tSTAR arg_value opt_block_arg {
|
687
|
+
result = self.arg_concat(s(:array, s(:hash, *val[0].values)), val[3])
|
688
|
+
result = self.arg_blk_pass(result, val[4]);
|
689
|
+
}
|
690
|
+
| args ',' assocs opt_block_arg {
|
691
|
+
result = val[0] << s(:hash, *val[2].values)
|
692
|
+
result = self.arg_blk_pass(result, val[3]);
|
693
|
+
}
|
694
|
+
| args ',' assocs ',' tSTAR arg opt_block_arg {
|
695
|
+
val[0] << s(:hash, *val[2].values)
|
696
|
+
result = self.arg_concat(val[0], val[5])
|
697
|
+
result = self.arg_blk_pass(result, val[6]);
|
698
|
+
}
|
699
|
+
| tSTAR arg_value opt_block_arg {
|
700
|
+
result = self.arg_blk_pass(s(:splat, val[1]), val[2])
|
701
|
+
}
|
702
|
+
| block_arg
|
703
|
+
|
704
|
+
call_args2 : arg_value ',' args opt_block_arg {
|
705
|
+
result = self.arg_blk_pass(s(:array, val[0], val[2]), val[3])
|
706
|
+
}
|
707
|
+
| arg_value ',' block_arg {
|
708
|
+
result = self.arg_blk_pass(val[0], val[2]);
|
709
|
+
}
|
710
|
+
| arg_value ',' tSTAR arg_value opt_block_arg {
|
711
|
+
result = self.arg_concat(s(:array, val[0]), val[3]);
|
712
|
+
result = self.arg_blk_pass(result, val[4]);
|
713
|
+
}
|
714
|
+
| arg_value ',' args ',' tSTAR arg_value opt_block_arg {
|
715
|
+
result = self.arg_concat(s(:array, val[0], s(:hash, *val[2].values)), val[5])
|
716
|
+
result = self.arg_blk_pass(result, val[6]);
|
717
|
+
}
|
718
|
+
| assocs opt_block_arg {
|
719
|
+
result = s(:array, s(:hash, *val[0].values));
|
720
|
+
result = self.arg_blk_pass(result, val[1]);
|
721
|
+
}
|
722
|
+
| assocs ',' tSTAR arg_value opt_block_arg {
|
723
|
+
result = s(:array, s(:hash, *val[0].values), val[3])
|
724
|
+
result = self.arg_blk_pass(result, val[4])
|
725
|
+
}
|
726
|
+
| arg_value ',' assocs opt_block_arg {
|
727
|
+
result = s(:array, val[0], s(:hash, *val[2].values))
|
728
|
+
result = self.arg_blk_pass(result, val[3])
|
729
|
+
}
|
730
|
+
| arg_value ',' args ',' assocs opt_block_arg {
|
731
|
+
result = s(:array, val[0]).add_all(val[2]).add(s(:hash, *val[4].values));
|
732
|
+
result = self.arg_blk_pass(result, val[5]);
|
733
|
+
}
|
734
|
+
| arg_value ',' assocs ',' tSTAR arg_value opt_block_arg {
|
735
|
+
result = self.arg_concat(s(:array, val[0]).add(s(:hash, *val[2].values)), val[5]);
|
736
|
+
result = self.arg_blk_pass(result, val[6]);
|
737
|
+
}
|
738
|
+
| arg_value ',' args ',' assocs ',' tSTAR arg_value opt_block_arg {
|
739
|
+
result = self.arg_concat(s(:array, val[0]).add_all(val[2]).add(s(:hash, *val[4].values)), val[7]);
|
740
|
+
result = self.arg_blk_pass(result, val[8]);
|
741
|
+
}
|
742
|
+
| tSTAR arg_value opt_block_arg {
|
743
|
+
result = self.arg_blk_pass(s(:splat, val[1]), val[2]);
|
744
|
+
}
|
745
|
+
| block_arg
|
746
|
+
|
747
|
+
command_args : {
|
748
|
+
result = lexer.cmdarg.stack.dup
|
749
|
+
lexer.cmdarg.push true
|
750
|
+
} open_args {
|
751
|
+
lexer.cmdarg.stack.replace val[0]
|
752
|
+
result = val[1]
|
753
|
+
}
|
754
|
+
|
755
|
+
open_args : call_args
|
756
|
+
| tLPAREN_ARG {
|
757
|
+
lexer.state = :expr_endarg
|
758
|
+
} tRPAREN {
|
759
|
+
warning("don't put space before argument parentheses");
|
760
|
+
result = nil;
|
761
|
+
}
|
762
|
+
| tLPAREN_ARG call_args2 {
|
763
|
+
lexer.state = :expr_endarg
|
764
|
+
} tRPAREN {
|
765
|
+
warning("don't put space before argument parentheses");
|
766
|
+
result = val[1];
|
767
|
+
}
|
768
|
+
|
769
|
+
block_arg : tAMPER arg_value {
|
770
|
+
result = s(:block_pass, val[1]);
|
771
|
+
}
|
772
|
+
|
773
|
+
opt_block_arg : ',' block_arg {
|
774
|
+
result = val[1];
|
775
|
+
}
|
776
|
+
| none_block_pass
|
777
|
+
|
778
|
+
args : arg_value {
|
779
|
+
result = s(:array, val[0])
|
780
|
+
}
|
781
|
+
| args ',' arg_value {
|
782
|
+
result = val[0] << val[2]
|
783
|
+
# result = self.list_append(val[0], val[2]) # TODO? breaks stuff
|
784
|
+
}
|
785
|
+
|
786
|
+
mrhs : args ',' arg_value {
|
787
|
+
result = val[0] << val[2]
|
788
|
+
# result = self.list_append(val[0], val[2]) # TODO? breaks stuff
|
789
|
+
}
|
790
|
+
| args ',' tSTAR arg_value {
|
791
|
+
result = self.arg_concat(val[0], val[3])
|
792
|
+
}
|
793
|
+
| tSTAR arg_value {
|
794
|
+
result = s(:splat, val[1])
|
795
|
+
}
|
796
|
+
|
797
|
+
primary : literal
|
798
|
+
| strings
|
799
|
+
| xstring
|
800
|
+
| regexp
|
801
|
+
| words
|
802
|
+
| qwords
|
803
|
+
| var_ref
|
804
|
+
| backref
|
805
|
+
| tFID {
|
806
|
+
result = s(:fcall, val[0].value.to_sym)
|
807
|
+
}
|
808
|
+
| kBEGIN bodystmt kEND {
|
809
|
+
unless val[1] then
|
810
|
+
result = s(:nil)
|
811
|
+
else
|
812
|
+
result = s(:begin, val[1])
|
813
|
+
end
|
814
|
+
}
|
815
|
+
| tLPAREN_ARG expr {
|
816
|
+
lexer.state = :expr_endarg
|
817
|
+
} opt_nl tRPAREN {
|
818
|
+
warning("(...) interpreted as grouped expression");
|
819
|
+
result = val[1];
|
820
|
+
}
|
821
|
+
| tLPAREN compstmt tRPAREN {
|
822
|
+
result = val[1];
|
823
|
+
result.paren = true
|
824
|
+
}
|
825
|
+
| primary_value tCOLON2 tCONSTANT {
|
826
|
+
result = s(:colon2, val[0], val[2].value.to_sym)
|
827
|
+
}
|
828
|
+
| tCOLON3 tCONSTANT {
|
829
|
+
result = s(:colon3, val[1].value.to_sym)
|
830
|
+
}
|
831
|
+
| primary_value '[' aref_args tRBRACK {
|
832
|
+
if val[0].first == :self then
|
833
|
+
result = s(:fcall, :"[]")
|
834
|
+
else
|
835
|
+
result = s(:call, val[0], :"[]")
|
836
|
+
end
|
837
|
+
result << val[2] if val[2]
|
838
|
+
}
|
839
|
+
| tLBRACK aref_args tRBRACK {
|
840
|
+
result = val[1] || s(:zarray)
|
841
|
+
}
|
842
|
+
| tLBRACE assoc_list tRCURLY {
|
843
|
+
result = s(:hash, *val[1].values)
|
844
|
+
}
|
845
|
+
| kRETURN {
|
846
|
+
result = s(:return)
|
847
|
+
}
|
848
|
+
| kYIELD tLPAREN2 call_args tRPAREN {
|
849
|
+
result = self.new_yield(val[2]);
|
850
|
+
}
|
851
|
+
| kYIELD tLPAREN2 tRPAREN {
|
852
|
+
result = s(:yield)
|
853
|
+
}
|
854
|
+
| kYIELD {
|
855
|
+
result = s(:yield)
|
856
|
+
}
|
857
|
+
| kDEFINED opt_nl tLPAREN2 expr tRPAREN {
|
858
|
+
result = s(:defined, val[3]);
|
859
|
+
}
|
860
|
+
| operation brace_block {
|
861
|
+
name = val[0].value.to_sym
|
862
|
+
iter = val[1]
|
863
|
+
# iter[2] = iter[2][1] if iter[2][0] == :block and iter[2].size == 2 # HACK
|
864
|
+
iter.insert 1, s(:fcall, name)
|
865
|
+
result = iter
|
866
|
+
}
|
867
|
+
| method_call
|
868
|
+
| method_call brace_block {
|
869
|
+
call = val[0]
|
870
|
+
iter = val[1]
|
871
|
+
# iter[2] = iter[2][1] if iter[2][0] == :block and iter[2].size == 2 # HACK
|
872
|
+
iter.insert 1, call
|
873
|
+
result = iter
|
874
|
+
}
|
875
|
+
| kIF expr_value then compstmt if_tail kEND {
|
876
|
+
val[1] = cond val[1]
|
877
|
+
if val[1][0] == :not then
|
878
|
+
result = s(:if, val[1].last, val[4], val[3])
|
879
|
+
else
|
880
|
+
result = s(:if, val[1], val[3], val[4])
|
881
|
+
end
|
882
|
+
}
|
883
|
+
| kUNLESS expr_value then compstmt opt_else kEND {
|
884
|
+
val[1] = cond val[1]
|
885
|
+
if val[1][0] == :not then
|
886
|
+
result = s(:if, val[1].last, val[3], val[4])
|
887
|
+
else
|
888
|
+
result = s(:if, val[1], val[4], val[3])
|
889
|
+
end
|
890
|
+
}
|
891
|
+
| kWHILE {
|
892
|
+
lexer.cond.push true
|
893
|
+
} expr_value do {
|
894
|
+
lexer.cond.pop
|
895
|
+
} compstmt kEND {
|
896
|
+
block = val[5]
|
897
|
+
val[2] = cond val[2]
|
898
|
+
if val[2][0] == :not then
|
899
|
+
result = s(:until, val[2].last, block, true);
|
900
|
+
else
|
901
|
+
result = s(:while, val[2], block, true);
|
902
|
+
end
|
903
|
+
}
|
904
|
+
| kUNTIL {
|
905
|
+
lexer.cond.push true
|
906
|
+
} expr_value do {
|
907
|
+
lexer.cond.pop
|
908
|
+
} compstmt kEND {
|
909
|
+
block = val[5]
|
910
|
+
val[2] = cond val[2]
|
911
|
+
if val[2][0] == :not then
|
912
|
+
result = s(:while, val[2].last, block, true);
|
913
|
+
else
|
914
|
+
result = s(:until, val[2], block, true);
|
915
|
+
end
|
916
|
+
}
|
917
|
+
| kCASE expr_value opt_terms case_body kEND {
|
918
|
+
result = s(:case, val[1]);
|
919
|
+
|
920
|
+
body = val[3]
|
921
|
+
while body and body.first == :when
|
922
|
+
result << body
|
923
|
+
body = body.delete_at 3
|
924
|
+
end
|
925
|
+
|
926
|
+
els = body
|
927
|
+
|
928
|
+
if els and els != s(:block) then
|
929
|
+
result << els
|
930
|
+
else
|
931
|
+
result << nil
|
932
|
+
end
|
933
|
+
}
|
934
|
+
| kCASE opt_terms case_body kEND {
|
935
|
+
result = s(:case, nil); # REFACTOR
|
936
|
+
|
937
|
+
body = val[2]
|
938
|
+
while body and body.first == :when
|
939
|
+
result << body
|
940
|
+
body = body.delete_at 3
|
941
|
+
end
|
942
|
+
|
943
|
+
els = body
|
944
|
+
|
945
|
+
if els and els != s(:block) then
|
946
|
+
result << els
|
947
|
+
else
|
948
|
+
result << nil
|
949
|
+
end
|
950
|
+
}
|
951
|
+
| kCASE opt_terms kELSE compstmt kEND { # TODO: need a test
|
952
|
+
result = s(:case, nil, val[3])
|
953
|
+
}
|
954
|
+
| kFOR block_var kIN {
|
955
|
+
lexer.cond.push true
|
956
|
+
} expr_value do {
|
957
|
+
lexer.cond.pop;
|
958
|
+
} compstmt kEND {
|
959
|
+
result = s(:for, val[4], val[1])
|
960
|
+
result << val[7] if val[7]
|
961
|
+
}
|
962
|
+
| kCLASS cpath superclass {
|
963
|
+
if (self.in_def || self.in_single > 0) then
|
964
|
+
yyerror("class definition in method body");
|
965
|
+
end
|
966
|
+
self.env.extend
|
967
|
+
} bodystmt kEND {
|
968
|
+
scope = s(:scope, val[4]).compact
|
969
|
+
result = s(:class, val[1].last.to_sym, val[2], scope)
|
970
|
+
self.env.unextend
|
971
|
+
}
|
972
|
+
| kCLASS tLSHFT expr {
|
973
|
+
result = self.in_def
|
974
|
+
self.in_def = false
|
975
|
+
} term {
|
976
|
+
result = self.in_single
|
977
|
+
self.in_single = 0
|
978
|
+
self.env.extend;
|
979
|
+
} bodystmt kEND {
|
980
|
+
scope = s(:scope, val[6]).compact
|
981
|
+
result = s(:sclass, val[2], scope)
|
982
|
+
self.env.unextend;
|
983
|
+
self.in_def = val[3]
|
984
|
+
self.in_single = val[5]
|
985
|
+
}
|
986
|
+
| kMODULE cpath {
|
987
|
+
yyerror("module definition in method body") if
|
988
|
+
self.in_def or self.in_single > 0
|
989
|
+
|
990
|
+
self.env.extend;
|
991
|
+
} bodystmt kEND {
|
992
|
+
body = val[3] ? s(:scope, val[3]) : s(:scope)
|
993
|
+
result = s(:module, val[1].last.to_sym, body)
|
994
|
+
self.env.unextend;
|
995
|
+
}
|
996
|
+
| kDEF fname {
|
997
|
+
self.in_def = true
|
998
|
+
self.env.extend
|
999
|
+
} f_arglist bodystmt kEND {
|
1000
|
+
name, args, body = val[1], val[3], val[4] # TODO: refactor
|
1001
|
+
name = name.value.to_sym
|
1002
|
+
body ||= s(:nil)
|
1003
|
+
|
1004
|
+
block_arg = args.block_arg(:remove)
|
1005
|
+
body = self.block_append(args, body, body && body[0] == :block)
|
1006
|
+
body.insert 2, block_arg if block_arg
|
1007
|
+
result = s(:defn, name, s(:scope, body))
|
1008
|
+
|
1009
|
+
self.env.unextend
|
1010
|
+
self.in_def = false
|
1011
|
+
}
|
1012
|
+
| kDEF singleton dot_or_colon { # 0-2, 3
|
1013
|
+
lexer.state = :expr_fname
|
1014
|
+
} fname { # 4, 5
|
1015
|
+
self.in_single += 1
|
1016
|
+
self.env.extend;
|
1017
|
+
lexer.state = :expr_end # force for args
|
1018
|
+
} f_arglist bodystmt kEND { # 6-8
|
1019
|
+
recv, name, args, body = val[1], val[4], val[6], val[7]
|
1020
|
+
|
1021
|
+
block_arg = args.block_arg(:remove)
|
1022
|
+
body = self.block_append(args, body, body && body[0] == :block)
|
1023
|
+
body.insert 2, block_arg if block_arg
|
1024
|
+
|
1025
|
+
result = s(:defs, recv, name.value.to_sym, s(:scope, body))
|
1026
|
+
|
1027
|
+
self.env.unextend;
|
1028
|
+
self.in_single -= 1
|
1029
|
+
}
|
1030
|
+
| kBREAK {
|
1031
|
+
result = s(:break)
|
1032
|
+
}
|
1033
|
+
| kNEXT {
|
1034
|
+
result = s(:next)
|
1035
|
+
}
|
1036
|
+
| kREDO {
|
1037
|
+
result = s(:redo)
|
1038
|
+
}
|
1039
|
+
| kRETRY {
|
1040
|
+
result = s(:retry)
|
1041
|
+
}
|
1042
|
+
|
1043
|
+
primary_value : primary {
|
1044
|
+
result = value_expr(val[0])
|
1045
|
+
}
|
1046
|
+
|
1047
|
+
then : term
|
1048
|
+
| ":"
|
1049
|
+
| kTHEN
|
1050
|
+
| term kTHEN
|
1051
|
+
|
1052
|
+
do : term
|
1053
|
+
| ":"
|
1054
|
+
| kDO_COND
|
1055
|
+
|
1056
|
+
if_tail : opt_else
|
1057
|
+
| kELSIF expr_value then compstmt if_tail {
|
1058
|
+
result = s(:if, val[1], val[3], val[4]);
|
1059
|
+
}
|
1060
|
+
|
1061
|
+
opt_else : none
|
1062
|
+
| kELSE compstmt {
|
1063
|
+
result = val[1];
|
1064
|
+
}
|
1065
|
+
|
1066
|
+
block_var : lhs
|
1067
|
+
| mlhs { val[0].delete_at 1 if val[0][1].nil? } # HACK
|
1068
|
+
|
1069
|
+
opt_block_var : none
|
1070
|
+
| tPIPE tPIPE {
|
1071
|
+
result = 0
|
1072
|
+
}
|
1073
|
+
| tOROP {
|
1074
|
+
result = 0
|
1075
|
+
}
|
1076
|
+
| tPIPE block_var tPIPE {
|
1077
|
+
result = val[1];
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
do_block : kDO_BLOCK {
|
1081
|
+
self.env.extend :dynamic
|
1082
|
+
} opt_block_var { result = self.env.dynamic.keys }
|
1083
|
+
compstmt kEND {
|
1084
|
+
|
1085
|
+
vars = val[2]
|
1086
|
+
body = self.dyna_init(val[4], val[3])
|
1087
|
+
|
1088
|
+
result = s(:iter)
|
1089
|
+
result << vars
|
1090
|
+
result << val[1] if val[1]
|
1091
|
+
result << body if body
|
1092
|
+
|
1093
|
+
self.env.unextend;
|
1094
|
+
}
|
1095
|
+
|
1096
|
+
block_call : command do_block {
|
1097
|
+
raise SyntaxError, "Both block arg and actual block given." if
|
1098
|
+
val[0] && val[0][0] == :blockpass
|
1099
|
+
|
1100
|
+
result = val[1]
|
1101
|
+
result.insert 1, val[0]
|
1102
|
+
}
|
1103
|
+
| block_call tDOT operation2 opt_paren_args {
|
1104
|
+
result = s(:call, val[0], val[2]);
|
1105
|
+
result << val[3] if val[3]
|
1106
|
+
}
|
1107
|
+
| block_call tCOLON2 operation2 opt_paren_args {
|
1108
|
+
result = s(:call, val[0], val[2]);
|
1109
|
+
result << val[3] if val[3]
|
1110
|
+
}
|
1111
|
+
|
1112
|
+
method_call : operation paren_args {
|
1113
|
+
result = new_fcall(val[0].value.to_sym, val[1])
|
1114
|
+
}
|
1115
|
+
| primary_value tDOT operation2 opt_paren_args {
|
1116
|
+
result = new_call(val[0], val[2].value.to_sym, val[3])
|
1117
|
+
}
|
1118
|
+
| primary_value tCOLON2 operation2 paren_args {
|
1119
|
+
result = new_call(val[0], val[2].value.to_sym, val[3])
|
1120
|
+
}
|
1121
|
+
| primary_value tCOLON2 operation3 {
|
1122
|
+
result = new_call(val[0], val[2].value.to_sym)
|
1123
|
+
}
|
1124
|
+
| kSUPER paren_args {
|
1125
|
+
result = self.new_super(val[1]);
|
1126
|
+
}
|
1127
|
+
| kSUPER {
|
1128
|
+
result = s(:zsuper)
|
1129
|
+
}
|
1130
|
+
|
1131
|
+
brace_block : tLCURLY {
|
1132
|
+
self.env.extend :dynamic
|
1133
|
+
} opt_block_var { result = self.env.dynamic.keys }
|
1134
|
+
compstmt tRCURLY { # REFACTOR
|
1135
|
+
args = val[2]
|
1136
|
+
body = self.dyna_init(val[4], val[3])
|
1137
|
+
result = s(:iter)
|
1138
|
+
result << args
|
1139
|
+
result << body if body
|
1140
|
+
self.env.unextend
|
1141
|
+
}
|
1142
|
+
| kDO {
|
1143
|
+
self.env.extend :dynamic
|
1144
|
+
} opt_block_var { result = self.env.dynamic.keys }
|
1145
|
+
compstmt kEND {
|
1146
|
+
args = val[2]
|
1147
|
+
body = self.dyna_init(val[4], val[3])
|
1148
|
+
result = s(:iter)
|
1149
|
+
result << args
|
1150
|
+
result << body if body
|
1151
|
+
self.env.unextend
|
1152
|
+
}
|
1153
|
+
|
1154
|
+
case_body : kWHEN when_args then compstmt cases {
|
1155
|
+
result = s(:when, val[1], val[3])
|
1156
|
+
result << val[4] if val[4]
|
1157
|
+
}
|
1158
|
+
|
1159
|
+
when_args : args
|
1160
|
+
| args ',' tSTAR arg_value {
|
1161
|
+
result = self.list_append(val[0], s(:when, val[3], nil))
|
1162
|
+
}
|
1163
|
+
| tSTAR arg_value {
|
1164
|
+
result = s(:array, s(:when, val[1], nil));
|
1165
|
+
}
|
1166
|
+
|
1167
|
+
cases : opt_else | case_body
|
1168
|
+
|
1169
|
+
opt_rescue : kRESCUE exc_list exc_var then compstmt opt_rescue {
|
1170
|
+
result = s(:resbody, val[1])
|
1171
|
+
if val[2] then
|
1172
|
+
val[2] = node_assign(val[2], s(:gvar, :"$!"))
|
1173
|
+
|
1174
|
+
strip = val[4] && val[4][0] == :block
|
1175
|
+
val[4] = block_append(val[2], val[4])
|
1176
|
+
val[4].push(*val[4].pop[1..-1]) if strip # HACK removes nested block from block_append
|
1177
|
+
end
|
1178
|
+
|
1179
|
+
result << val[4] if val[4]
|
1180
|
+
result << val[5] if val[5]
|
1181
|
+
}
|
1182
|
+
| {result = nil;}
|
1183
|
+
|
1184
|
+
exc_list : arg_value {
|
1185
|
+
result = s(:array, val[0]);
|
1186
|
+
}
|
1187
|
+
| mrhs
|
1188
|
+
| none
|
1189
|
+
|
1190
|
+
exc_var : tASSOC lhs {
|
1191
|
+
result = val[1];
|
1192
|
+
}
|
1193
|
+
| none
|
1194
|
+
|
1195
|
+
opt_ensure : kENSURE compstmt {
|
1196
|
+
if (val[1] != nil) then
|
1197
|
+
result = val[1];
|
1198
|
+
else
|
1199
|
+
result = s(:nil)
|
1200
|
+
end
|
1201
|
+
}
|
1202
|
+
| none
|
1203
|
+
|
1204
|
+
literal : numeric { result = s(:lit, val[0]) }
|
1205
|
+
| symbol { result = s(:lit, val[0]) }
|
1206
|
+
| dsym
|
1207
|
+
|
1208
|
+
strings : string {
|
1209
|
+
val[0] = s(:dstr, val[0].value) if val[0][0] == :evstr
|
1210
|
+
result = val[0];
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
string : string1
|
1214
|
+
| string string1 {
|
1215
|
+
result = self.literal_concat(val[0], val[1]);
|
1216
|
+
}
|
1217
|
+
|
1218
|
+
string1 : tSTRING_BEG string_contents tSTRING_END {
|
1219
|
+
result = val[1];
|
1220
|
+
}
|
1221
|
+
|
1222
|
+
xstring : tXSTRING_BEG xstring_contents tSTRING_END {
|
1223
|
+
node = val[1]
|
1224
|
+
|
1225
|
+
unless node then
|
1226
|
+
node = s(:xstr, '')
|
1227
|
+
else
|
1228
|
+
case node[0]
|
1229
|
+
when :str
|
1230
|
+
node[0] = :xstr
|
1231
|
+
when :dstr
|
1232
|
+
node[0] = :dxstr
|
1233
|
+
else
|
1234
|
+
node = s(:dxstr, '', node)
|
1235
|
+
end
|
1236
|
+
end
|
1237
|
+
|
1238
|
+
result = node
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
regexp : tREGEXP_BEG xstring_contents tREGEXP_END {
|
1242
|
+
node = val[1] || s(:str, '')
|
1243
|
+
options = val[2]
|
1244
|
+
|
1245
|
+
o, k = 0, nil
|
1246
|
+
options.split(//).each do |c| # FIX: this has a better home
|
1247
|
+
v = {
|
1248
|
+
'x' => Regexp::EXTENDED,
|
1249
|
+
'i' => Regexp::IGNORECASE,
|
1250
|
+
'm' => Regexp::MULTILINE,
|
1251
|
+
'n' => 16,
|
1252
|
+
'e' => 32,
|
1253
|
+
's' => 48, # TODO: really?!?
|
1254
|
+
'u' => 64,
|
1255
|
+
'o' => 0, # ignore for now
|
1256
|
+
}[c]
|
1257
|
+
raise "unknown regexp option: #{c}" unless v
|
1258
|
+
o += v
|
1259
|
+
k = c if c =~ /[nesu]/
|
1260
|
+
end
|
1261
|
+
|
1262
|
+
case node[0]
|
1263
|
+
when :str then
|
1264
|
+
node[0] = :lit
|
1265
|
+
node[1] = if k then
|
1266
|
+
Regexp.new(node[1], o, k)
|
1267
|
+
else
|
1268
|
+
Regexp.new(node[1], o)
|
1269
|
+
end
|
1270
|
+
when :dstr then
|
1271
|
+
if options =~ /o/ then
|
1272
|
+
node[0] = :dregx_once
|
1273
|
+
else
|
1274
|
+
node[0] = :dregx
|
1275
|
+
end
|
1276
|
+
node << o if o and o != 0
|
1277
|
+
else
|
1278
|
+
node = s(:dregx, '', node);
|
1279
|
+
node[0] = :dregx_once if options =~ /o/
|
1280
|
+
node << o if o and o != 0
|
1281
|
+
end
|
1282
|
+
|
1283
|
+
result = node
|
1284
|
+
}
|
1285
|
+
|
1286
|
+
words : tWORDS_BEG ' ' tSTRING_END {
|
1287
|
+
result = s(:zarray);
|
1288
|
+
}
|
1289
|
+
| tWORDS_BEG word_list tSTRING_END {
|
1290
|
+
result = val[1];
|
1291
|
+
}
|
1292
|
+
|
1293
|
+
word_list : {
|
1294
|
+
result = s(:array)
|
1295
|
+
}
|
1296
|
+
| word_list word ' ' {
|
1297
|
+
word = val[1][0] == :evstr ? s(:dstr, '', val[1]) : val[1]
|
1298
|
+
result = val[0] << word
|
1299
|
+
}
|
1300
|
+
|
1301
|
+
word : string_content
|
1302
|
+
| word string_content {
|
1303
|
+
result = self.literal_concat(val[0], val[1]);
|
1304
|
+
}
|
1305
|
+
|
1306
|
+
qwords : tQWORDS_BEG ' ' tSTRING_END {
|
1307
|
+
result = s(:zarray)
|
1308
|
+
}
|
1309
|
+
| tQWORDS_BEG qword_list tSTRING_END {
|
1310
|
+
result = val[1]
|
1311
|
+
}
|
1312
|
+
|
1313
|
+
qword_list : {
|
1314
|
+
result = s(:array)
|
1315
|
+
}
|
1316
|
+
| qword_list tSTRING_CONTENT ' ' {
|
1317
|
+
result = val[0] << val[1]
|
1318
|
+
}
|
1319
|
+
|
1320
|
+
string_contents: { result = s(:str, "") }
|
1321
|
+
| string_contents string_content {
|
1322
|
+
result = literal_concat(val[0], val[1])
|
1323
|
+
}
|
1324
|
+
|
1325
|
+
xstring_contents: { result = nil }
|
1326
|
+
| xstring_contents string_content {
|
1327
|
+
result = literal_concat(val[0], val[1])
|
1328
|
+
}
|
1329
|
+
|
1330
|
+
string_content : tSTRING_CONTENT
|
1331
|
+
| tSTRING_DVAR {
|
1332
|
+
result = lexer.str_term;
|
1333
|
+
lexer.str_term = nil
|
1334
|
+
lexer.state = :expr_beg
|
1335
|
+
} string_dvar {
|
1336
|
+
lexer.str_term = val[1]
|
1337
|
+
result = s(:evstr, val[2]);
|
1338
|
+
}
|
1339
|
+
| tSTRING_DBEG {
|
1340
|
+
result = lexer.str_term;
|
1341
|
+
lexer.str_term = nil
|
1342
|
+
lexer.state = :expr_beg
|
1343
|
+
lexer.cond.push false
|
1344
|
+
lexer.cmdarg.push false
|
1345
|
+
} compstmt tRCURLY {
|
1346
|
+
lexer.str_term = val[1]
|
1347
|
+
lexer.cond.lexpop
|
1348
|
+
lexer.cmdarg.lexpop
|
1349
|
+
case val[2][0]
|
1350
|
+
when :str, :dstr, :evstr then
|
1351
|
+
result = val[2]
|
1352
|
+
else
|
1353
|
+
result = s(:evstr, val[2])
|
1354
|
+
end
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
string_dvar : tGVAR {
|
1358
|
+
result = s(:gvar, val[0].value.to_sym);
|
1359
|
+
}
|
1360
|
+
| tIVAR {
|
1361
|
+
result = s(:ivar, val[0].value.to_sym);
|
1362
|
+
}
|
1363
|
+
| tCVAR {
|
1364
|
+
result = s(:cvar, val[0].value.to_sym);
|
1365
|
+
}
|
1366
|
+
| backref
|
1367
|
+
|
1368
|
+
|
1369
|
+
symbol : tSYMBEG sym {
|
1370
|
+
lexer.state = :expr_end
|
1371
|
+
result = val[1].value.to_sym
|
1372
|
+
}
|
1373
|
+
|
1374
|
+
sym : fname | tIVAR | tGVAR | tCVAR
|
1375
|
+
|
1376
|
+
dsym : tSYMBEG xstring_contents tSTRING_END {
|
1377
|
+
lexer.state = :expr_end
|
1378
|
+
result = val[1]
|
1379
|
+
|
1380
|
+
yyerror("empty symbol literal") if result.nil? or result.empty?
|
1381
|
+
|
1382
|
+
case result[0]
|
1383
|
+
when :dstr then
|
1384
|
+
result[0] = :dsym
|
1385
|
+
when :str then
|
1386
|
+
result = s(:lit, result.last.intern)
|
1387
|
+
else
|
1388
|
+
result = s(:dsym, '', result)
|
1389
|
+
end
|
1390
|
+
|
1391
|
+
}
|
1392
|
+
|
1393
|
+
numeric : tINTEGER
|
1394
|
+
| tFLOAT
|
1395
|
+
| tUMINUS_NUM tINTEGER = tLOWEST {
|
1396
|
+
result = -val[1] # TODO: pt_testcase
|
1397
|
+
}
|
1398
|
+
| tUMINUS_NUM tFLOAT = tLOWEST {
|
1399
|
+
result = -val[1] # TODO: pt_testcase
|
1400
|
+
}
|
1401
|
+
|
1402
|
+
variable : tIDENTIFIER
|
1403
|
+
| tIVAR
|
1404
|
+
| tGVAR
|
1405
|
+
| tCONSTANT
|
1406
|
+
| tCVAR
|
1407
|
+
| kNIL {
|
1408
|
+
result = s(:nil)
|
1409
|
+
}
|
1410
|
+
| kSELF {
|
1411
|
+
result = s(:self)
|
1412
|
+
}
|
1413
|
+
| kTRUE {
|
1414
|
+
result = s(:true)
|
1415
|
+
}
|
1416
|
+
| kFALSE {
|
1417
|
+
result = s(:false)
|
1418
|
+
}
|
1419
|
+
| k__FILE__ {
|
1420
|
+
result = :"__FILE__"
|
1421
|
+
}
|
1422
|
+
| k__LINE__ {
|
1423
|
+
result = :"__LINE__"
|
1424
|
+
}
|
1425
|
+
|
1426
|
+
var_ref : variable {
|
1427
|
+
result = self.gettable(val[0])
|
1428
|
+
}
|
1429
|
+
|
1430
|
+
var_lhs : variable {
|
1431
|
+
result = self.assignable(val[0]);
|
1432
|
+
}
|
1433
|
+
|
1434
|
+
backref : tNTH_REF | tBACK_REF
|
1435
|
+
|
1436
|
+
superclass : term {
|
1437
|
+
result = nil;
|
1438
|
+
}
|
1439
|
+
| tLT {
|
1440
|
+
lexer.state = :expr_beg
|
1441
|
+
} expr_value term {
|
1442
|
+
result = val[2];
|
1443
|
+
}
|
1444
|
+
| error term {
|
1445
|
+
yyerrok;
|
1446
|
+
result = nil;
|
1447
|
+
}
|
1448
|
+
|
1449
|
+
f_arglist : tLPAREN2 f_args opt_nl tRPAREN {
|
1450
|
+
result = val[1];
|
1451
|
+
lexer.state = :expr_beg
|
1452
|
+
}
|
1453
|
+
| f_args term {
|
1454
|
+
result = val[0];
|
1455
|
+
}
|
1456
|
+
|
1457
|
+
f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg {
|
1458
|
+
result = val[0]
|
1459
|
+
if val[2] then
|
1460
|
+
val[2][1..-1].each do |lasgn| # FIX clean sexp iter
|
1461
|
+
raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
|
1462
|
+
result << lasgn[1]
|
1463
|
+
end
|
1464
|
+
end
|
1465
|
+
result << val[4] if val[4]
|
1466
|
+
result << val[2] if val[2]
|
1467
|
+
result << val[5] if val[5]
|
1468
|
+
}
|
1469
|
+
| f_arg ',' f_optarg opt_f_block_arg {
|
1470
|
+
result = val[0]
|
1471
|
+
if val[2] then
|
1472
|
+
val[2][1..-1].each do |lasgn| # FIX clean sexp iter
|
1473
|
+
raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
|
1474
|
+
result << lasgn[1]
|
1475
|
+
end
|
1476
|
+
end
|
1477
|
+
result << val[2] if val[2]
|
1478
|
+
result << val[3] if val[3]
|
1479
|
+
}
|
1480
|
+
| f_arg ',' f_rest_arg opt_f_block_arg {
|
1481
|
+
result = val[0]
|
1482
|
+
result << val[2] if val[2]
|
1483
|
+
result << val[3] if val[3]
|
1484
|
+
}
|
1485
|
+
| f_arg opt_f_block_arg {
|
1486
|
+
result = val[0]
|
1487
|
+
result << val[1] if val[1]
|
1488
|
+
}
|
1489
|
+
| f_optarg ',' f_rest_arg opt_f_block_arg {
|
1490
|
+
result = s(:args)
|
1491
|
+
if val[0] then
|
1492
|
+
val[0][1..-1].each do |lasgn| # FIX clean sexp iter
|
1493
|
+
raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
|
1494
|
+
result << lasgn[1]
|
1495
|
+
end
|
1496
|
+
end
|
1497
|
+
|
1498
|
+
result << val[2] if val[2]
|
1499
|
+
result << val[0] if val[0]
|
1500
|
+
result << val[3] if val[3]
|
1501
|
+
}
|
1502
|
+
| f_optarg opt_f_block_arg {
|
1503
|
+
result = s(:args)
|
1504
|
+
if val[0] then
|
1505
|
+
val[0][1..-1].each do |lasgn| # FIX clean sexp iter
|
1506
|
+
raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
|
1507
|
+
result << lasgn[1]
|
1508
|
+
end
|
1509
|
+
end
|
1510
|
+
|
1511
|
+
result << val[0] if val[0]
|
1512
|
+
result << val[1] if val[1]
|
1513
|
+
}
|
1514
|
+
| f_rest_arg opt_f_block_arg {
|
1515
|
+
result = s(:args, val[0], val[1]).compact
|
1516
|
+
}
|
1517
|
+
| f_block_arg {
|
1518
|
+
result = s(:args, val[0]).compact
|
1519
|
+
}
|
1520
|
+
| {
|
1521
|
+
result = s(:args)
|
1522
|
+
}
|
1523
|
+
|
1524
|
+
f_norm_arg : tCONSTANT {
|
1525
|
+
yyerror("formal argument cannot be a constant");
|
1526
|
+
}
|
1527
|
+
| tIVAR {
|
1528
|
+
yyerror("formal argument cannot be an instance variable");
|
1529
|
+
}
|
1530
|
+
| tCVAR {
|
1531
|
+
yyerror("formal argument cannot be a class variable");
|
1532
|
+
}
|
1533
|
+
| tIDENTIFIER {
|
1534
|
+
identifier = val[0].value.to_sym
|
1535
|
+
self.env[identifier] = :lvar
|
1536
|
+
|
1537
|
+
result = val[0];
|
1538
|
+
}
|
1539
|
+
|
1540
|
+
f_arg : f_norm_arg {
|
1541
|
+
result = s(:args)
|
1542
|
+
result << val[0].value.to_sym
|
1543
|
+
}
|
1544
|
+
| f_arg ',' f_norm_arg {
|
1545
|
+
val[0] << val[2].value.to_sym
|
1546
|
+
result = val[0]
|
1547
|
+
}
|
1548
|
+
|
1549
|
+
f_opt : tIDENTIFIER '=' arg_value {
|
1550
|
+
result = self.assignable(val[0], val[2]);
|
1551
|
+
# TODO: detect duplicate names
|
1552
|
+
}
|
1553
|
+
|
1554
|
+
f_optarg : f_opt {
|
1555
|
+
result = s(:block, val[0])
|
1556
|
+
}
|
1557
|
+
| f_optarg ',' f_opt {
|
1558
|
+
result = self.append_to_block(val[0], val[2]);
|
1559
|
+
}
|
1560
|
+
|
1561
|
+
restarg_mark : tSTAR2 | tSTAR
|
1562
|
+
|
1563
|
+
f_rest_arg : restarg_mark tIDENTIFIER { # TODO: differs from parse.y - needs tests
|
1564
|
+
name = val[1].value.to_sym
|
1565
|
+
self.assignable(name)
|
1566
|
+
result = :"*#{name}"
|
1567
|
+
}
|
1568
|
+
| restarg_mark {
|
1569
|
+
name = :"*"
|
1570
|
+
self.env[name] = self.env.dynamic? ? :dvar : :lvar # FIX
|
1571
|
+
result = name
|
1572
|
+
}
|
1573
|
+
|
1574
|
+
blkarg_mark : tAMPER2 | tAMPER
|
1575
|
+
|
1576
|
+
f_block_arg : blkarg_mark tIDENTIFIER {
|
1577
|
+
identifier = val[1].value.to_sym
|
1578
|
+
|
1579
|
+
self.env[identifier] = self.env.dynamic? ? :dvar : :lvar
|
1580
|
+
result = s(:block_arg, identifier.to_sym)
|
1581
|
+
}
|
1582
|
+
|
1583
|
+
opt_f_block_arg: ',' f_block_arg {
|
1584
|
+
result = val[1];
|
1585
|
+
}
|
1586
|
+
| {
|
1587
|
+
result = nil;
|
1588
|
+
}
|
1589
|
+
|
1590
|
+
singleton : var_ref
|
1591
|
+
| tLPAREN2 {
|
1592
|
+
lexer.state = :expr_beg
|
1593
|
+
} expr opt_nl tRPAREN {
|
1594
|
+
if (val[2].instanceof ILiteralNode) then
|
1595
|
+
yyerror("Can't define single method for literals.");
|
1596
|
+
end
|
1597
|
+
result = val[2];
|
1598
|
+
}
|
1599
|
+
|
1600
|
+
assoc_list : none { # [!nil]
|
1601
|
+
result = s(:array)
|
1602
|
+
}
|
1603
|
+
| assocs trailer { # [!nil]
|
1604
|
+
result = val[0];
|
1605
|
+
}
|
1606
|
+
| args trailer {
|
1607
|
+
size = val[0].size
|
1608
|
+
if (size % 2 != 1) then # != 1 because of leading :array
|
1609
|
+
yyerror("Odd number (#{size}) list for Hash. #{val[0].inspect}");
|
1610
|
+
end
|
1611
|
+
result = val[0];
|
1612
|
+
}
|
1613
|
+
|
1614
|
+
assocs : assoc
|
1615
|
+
| assocs ',' assoc {
|
1616
|
+
list = val[0].dup
|
1617
|
+
more = val[2][1..-1]
|
1618
|
+
list.push(*more) unless more.empty?
|
1619
|
+
result = list
|
1620
|
+
}
|
1621
|
+
|
1622
|
+
assoc : arg_value tASSOC arg_value {
|
1623
|
+
result = s(:array, val[0], val[2])
|
1624
|
+
}
|
1625
|
+
|
1626
|
+
operation : tIDENTIFIER | tCONSTANT | tFID
|
1627
|
+
operation2 : tIDENTIFIER | tCONSTANT | tFID | op
|
1628
|
+
operation3 : tIDENTIFIER | tFID | op
|
1629
|
+
dot_or_colon : tDOT | tCOLON2
|
1630
|
+
opt_terms : | terms
|
1631
|
+
opt_nl : | "\n"
|
1632
|
+
trailer : | "\n" | ','
|
1633
|
+
|
1634
|
+
term : ';' { yyerrok }
|
1635
|
+
| "\n"
|
1636
|
+
|
1637
|
+
terms : term
|
1638
|
+
| terms ';' { yyerrok }
|
1639
|
+
|
1640
|
+
none : { result = nil }
|
1641
|
+
|
1642
|
+
none_block_pass: { result = nil }
|
1643
|
+
|
1644
|
+
end
|
1645
|
+
|
1646
|
+
---- inner
|
1647
|
+
|
1648
|
+
require 'ruby_lexer'
|