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.

@@ -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'