rogue_parser 1.0.1

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.
@@ -0,0 +1,1656 @@
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 tAWORDS_BEG tSTRING_DBEG tSTRING_DVAR tSTRING_END
19
+ tLAST_TOKEN
20
+
21
+ prechigh
22
+ right tBANG tTILDE tUPLUS
23
+ right tPOW
24
+ right tUMINUS_NUM tUMINUS
25
+ left tSTAR2 tDIVIDE tPERCENT
26
+ left tPLUS tMINUS
27
+ left tLSHFT tRSHFT
28
+ left tAMPER2
29
+ left tPIPE tCARET
30
+ left tGT tGEQ tLT tLEQ
31
+ nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH
32
+ left tANDOP
33
+ left tOROP
34
+ nonassoc tDOT2 tDOT3
35
+ right '?' ':'
36
+ left kRESCUE_MOD
37
+ right '=' tOP_ASGN
38
+ nonassoc kDEFINED
39
+ right kNOT
40
+ left kOR kAND
41
+ nonassoc kIF_MOD kUNLESS_MOD kWHILE_MOD kUNTIL_MOD
42
+ nonassoc tLBRACE_ARG
43
+ nonassoc tLOWEST
44
+ preclow
45
+
46
+ rule
47
+
48
+ program : {
49
+ self.lexer.lex_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.lex_state = :expr_fname } fitem {
84
+ result = s(:alias, val[1], val[3])
85
+ }
86
+ | kALIAS tGVAR tGVAR {
87
+ result = s(:valias, val[1].to_sym, val[2].to_sym)
88
+ }
89
+ | kALIAS tGVAR tBACK_REF {
90
+ result = s(:valias, val[1].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].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].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], val[4])
262
+ self.env.unextend;
263
+ }
264
+
265
+ command : operation command_args =tLOWEST {
266
+ result = new_fcall(val[0].to_sym, val[1])
267
+ }
268
+ | operation command_args cmd_brace_block {
269
+ result = new_fcall(val[0].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].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].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].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.lex_state = :expr_end
430
+ result = val[0];
431
+ }
432
+
433
+ | reswords {
434
+ lexer.lex_state = :expr_end
435
+ result = val[0];
436
+ }
437
+
438
+ fitem : fname { result = s(:lit, val[0].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.lex_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].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].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].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].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.node_type == :lit and v2.node_type == :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.node_type == :lit and v2.node_type == :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.lex_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.lex_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
+ | awords
803
+ | var_ref
804
+ | backref
805
+ | tFID {
806
+ result = s(:fcall, val[0].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.lex_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].to_sym)
827
+ }
828
+ | tCOLON3 tCONSTANT {
829
+ result = s(:colon3, val[1].to_sym)
830
+ }
831
+ | primary_value '[' aref_args tRBRACK {
832
+ if val[0].node_type == :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].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.node_type == :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
+ self.comments.push self.lexer.comments
964
+ if (self.in_def || self.in_single > 0) then
965
+ yyerror("class definition in method body");
966
+ end
967
+ self.env.extend
968
+ } bodystmt kEND {
969
+ scope = s(:scope, val[4]).compact
970
+ result = s(:class, val[1].last.to_sym, val[2], scope)
971
+ result.comments = self.comments.pop
972
+ self.env.unextend
973
+ }
974
+ | kCLASS tLSHFT expr {
975
+ result = self.in_def
976
+ self.in_def = false
977
+ } term {
978
+ result = self.in_single
979
+ self.in_single = 0
980
+ self.env.extend;
981
+ } bodystmt kEND {
982
+ scope = s(:scope, val[6]).compact
983
+ result = s(:sclass, val[2], scope)
984
+ self.env.unextend;
985
+ self.in_def = val[3]
986
+ self.in_single = val[5]
987
+ }
988
+ | kMODULE cpath {
989
+ self.comments.push self.lexer.comments
990
+ yyerror("module definition in method body") if
991
+ self.in_def or self.in_single > 0
992
+
993
+ self.env.extend;
994
+ } bodystmt kEND {
995
+ body = val[3] ? s(:scope, val[3]) : s(:scope)
996
+ result = s(:module, val[1].last.to_sym, body)
997
+ result.comments = self.comments.pop
998
+ self.env.unextend;
999
+ }
1000
+ | kDEF fname {
1001
+ self.comments.push self.lexer.comments
1002
+ self.in_def = true
1003
+ self.env.extend
1004
+ } f_arglist bodystmt kEND {
1005
+ name, args, body = val[1], val[3], val[4] # TODO: refactor
1006
+ name = name.to_sym
1007
+ body ||= s(:nil)
1008
+
1009
+ block_arg = args.block_arg(:remove)
1010
+ body = self.block_append(args, body, body && body[0] == :block)
1011
+ body.insert 2, block_arg if block_arg
1012
+ result = s(:defn, name, s(:scope, body))
1013
+ result.comments = self.comments.pop
1014
+
1015
+ self.env.unextend
1016
+ self.in_def = false
1017
+ }
1018
+ | kDEF singleton dot_or_colon { # 0-2, 3
1019
+ self.comments.push self.lexer.comments
1020
+ lexer.lex_state = :expr_fname
1021
+ } fname { # 4, 5
1022
+ self.in_single += 1
1023
+ self.env.extend;
1024
+ lexer.lex_state = :expr_end # force for args
1025
+ } f_arglist bodystmt kEND { # 6-8
1026
+ recv, name, args, body = val[1], val[4], val[6], val[7]
1027
+
1028
+ block_arg = args.block_arg(:remove)
1029
+ body = self.block_append(args, body, body && body[0] == :block)
1030
+ body.insert 2, block_arg if block_arg
1031
+
1032
+ result = s(:defs, recv, name.to_sym, s(:scope, body))
1033
+ result.comments = self.comments.pop
1034
+
1035
+ self.env.unextend;
1036
+ self.in_single -= 1
1037
+ }
1038
+ | kBREAK {
1039
+ result = s(:break)
1040
+ }
1041
+ | kNEXT {
1042
+ result = s(:next)
1043
+ }
1044
+ | kREDO {
1045
+ result = s(:redo)
1046
+ }
1047
+ | kRETRY {
1048
+ result = s(:retry)
1049
+ }
1050
+
1051
+ primary_value : primary {
1052
+ result = value_expr(val[0])
1053
+ }
1054
+
1055
+ then : term
1056
+ | ":"
1057
+ | kTHEN
1058
+ | term kTHEN
1059
+
1060
+ do : term
1061
+ | ":"
1062
+ | kDO_COND
1063
+
1064
+ if_tail : opt_else
1065
+ | kELSIF expr_value then compstmt if_tail {
1066
+ result = s(:if, val[1], val[3], val[4]);
1067
+ }
1068
+
1069
+ opt_else : none
1070
+ | kELSE compstmt {
1071
+ result = val[1];
1072
+ }
1073
+
1074
+ block_var : lhs
1075
+ | mlhs { val[0].delete_at 1 if val[0][1].nil? } # HACK
1076
+
1077
+ opt_block_var : none
1078
+ | tPIPE tPIPE {
1079
+ result = 0
1080
+ }
1081
+ | tOROP {
1082
+ result = 0
1083
+ }
1084
+ | tPIPE block_var tPIPE {
1085
+ result = val[1];
1086
+ }
1087
+
1088
+ do_block : kDO_BLOCK {
1089
+ self.env.extend :dynamic
1090
+ } opt_block_var { result = self.env.dynamic.keys }
1091
+ compstmt kEND {
1092
+
1093
+ vars = val[2]
1094
+ body = val[4]
1095
+
1096
+ result = s(:iter)
1097
+ result << vars
1098
+ result << val[1] if val[1]
1099
+ result << body if body
1100
+
1101
+ self.env.unextend;
1102
+ }
1103
+
1104
+ block_call : command do_block {
1105
+ raise SyntaxError, "Both block arg and actual block given." if
1106
+ val[0] && val[0][0] == :blockpass
1107
+
1108
+ result = val[1]
1109
+ result.insert 1, val[0]
1110
+ }
1111
+ | block_call tDOT operation2 opt_paren_args {
1112
+ result = s(:call, val[0], val[2]);
1113
+ result << val[3] if val[3]
1114
+ }
1115
+ | block_call tCOLON2 operation2 opt_paren_args {
1116
+ result = s(:call, val[0], val[2]);
1117
+ result << val[3] if val[3]
1118
+ }
1119
+
1120
+ method_call : operation paren_args {
1121
+ result = new_fcall(val[0].to_sym, val[1])
1122
+ }
1123
+ | primary_value tDOT operation2 opt_paren_args {
1124
+ result = new_call(val[0], val[2].to_sym, val[3])
1125
+ }
1126
+ | primary_value tCOLON2 operation2 paren_args {
1127
+ result = new_call(val[0], val[2].to_sym, val[3])
1128
+ }
1129
+ | primary_value tCOLON2 operation3 {
1130
+ result = new_call(val[0], val[2].to_sym)
1131
+ }
1132
+ | kSUPER paren_args {
1133
+ result = self.new_super(val[1]);
1134
+ }
1135
+ | kSUPER {
1136
+ result = s(:zsuper)
1137
+ }
1138
+
1139
+ brace_block : tLCURLY {
1140
+ self.env.extend :dynamic
1141
+ } opt_block_var { result = self.env.dynamic.keys }
1142
+ compstmt tRCURLY { # REFACTOR
1143
+ args = val[2]
1144
+ body = val[4]
1145
+ result = s(:iter)
1146
+ result << args
1147
+ result << body if body
1148
+ self.env.unextend
1149
+ }
1150
+ | kDO {
1151
+ self.env.extend :dynamic
1152
+ } opt_block_var { result = self.env.dynamic.keys }
1153
+ compstmt kEND {
1154
+ args = val[2]
1155
+ body = val[4]
1156
+ result = s(:iter)
1157
+ result << args
1158
+ result << body if body
1159
+ self.env.unextend
1160
+ }
1161
+
1162
+ case_body : kWHEN when_args then compstmt cases {
1163
+ result = s(:when, val[1], val[3])
1164
+ result << val[4] if val[4]
1165
+ }
1166
+
1167
+ when_args : args
1168
+ | args ',' tSTAR arg_value {
1169
+ result = self.list_append(val[0], s(:when, val[3], nil))
1170
+ }
1171
+ | tSTAR arg_value {
1172
+ result = s(:array, s(:when, val[1], nil));
1173
+ }
1174
+
1175
+ cases : opt_else | case_body
1176
+
1177
+ opt_rescue : kRESCUE exc_list exc_var then compstmt opt_rescue {
1178
+ result = s(:resbody, val[1])
1179
+ if val[2] then
1180
+ val[2] = node_assign(val[2], s(:gvar, :"$!"))
1181
+
1182
+ strip = val[4] && val[4][0] == :block
1183
+ val[4] = block_append(val[2], val[4])
1184
+ val[4].push(*val[4].pop[1..-1]) if strip # HACK removes nested block from block_append
1185
+ end
1186
+
1187
+ result << val[4] if val[4]
1188
+ result << val[5] if val[5]
1189
+ }
1190
+ | {result = nil;}
1191
+
1192
+ exc_list : arg_value {
1193
+ result = s(:array, val[0]);
1194
+ }
1195
+ | mrhs
1196
+ | none
1197
+
1198
+ exc_var : tASSOC lhs {
1199
+ result = val[1];
1200
+ }
1201
+ | none
1202
+
1203
+ opt_ensure : kENSURE compstmt {
1204
+ if (val[1] != nil) then
1205
+ result = val[1];
1206
+ else
1207
+ result = s(:nil)
1208
+ end
1209
+ }
1210
+ | none
1211
+
1212
+ literal : numeric { result = s(:lit, val[0]) }
1213
+ | symbol { result = s(:lit, val[0]) }
1214
+ | dsym
1215
+
1216
+ strings : string {
1217
+ val[0] = s(:dstr, val[0].value) if val[0][0] == :evstr
1218
+ result = val[0];
1219
+ }
1220
+
1221
+ string : string1
1222
+ | string string1 {
1223
+ result = self.literal_concat(val[0], val[1]);
1224
+ }
1225
+
1226
+ string1 : tSTRING_BEG string_contents tSTRING_END {
1227
+ result = val[1];
1228
+ }
1229
+
1230
+ xstring : tXSTRING_BEG xstring_contents tSTRING_END {
1231
+ node = val[1]
1232
+
1233
+ unless node then
1234
+ node = s(:xstr, '')
1235
+ else
1236
+ case node[0]
1237
+ when :str
1238
+ node[0] = :xstr
1239
+ when :dstr
1240
+ node[0] = :dxstr
1241
+ else
1242
+ node = s(:dxstr, '', node)
1243
+ end
1244
+ end
1245
+
1246
+ result = node
1247
+ }
1248
+
1249
+ regexp : tREGEXP_BEG xstring_contents tREGEXP_END {
1250
+ node = val[1] || s(:str, '')
1251
+ options = val[2]
1252
+
1253
+ o, k = 0, nil
1254
+ options.split(//).each do |c| # FIX: this has a better home
1255
+ v = {
1256
+ 'x' => Regexp::EXTENDED,
1257
+ 'i' => Regexp::IGNORECASE,
1258
+ 'm' => Regexp::MULTILINE,
1259
+ 'o' => Regexp::ONCE,
1260
+ 'n' => Regexp::ENC_NONE,
1261
+ 'e' => Regexp::ENC_EUC,
1262
+ 's' => Regexp::ENC_SJIS,
1263
+ 'u' => Regexp::ENC_UTF8,
1264
+ }[c]
1265
+ raise "unknown regexp option: #{c}" unless v
1266
+ o += v
1267
+ k = c if c =~ /[esu]/
1268
+ end
1269
+
1270
+ case node[0]
1271
+ when :str then
1272
+ node[0] = :lit
1273
+ node[1] = if k then
1274
+ Regexp.new(node[1], o, k)
1275
+ else
1276
+ Regexp.new(node[1], o)
1277
+ end
1278
+ when :dstr then
1279
+ if options =~ /o/ then
1280
+ node[0] = :dregx_once
1281
+ else
1282
+ node[0] = :dregx
1283
+ end
1284
+ node << o if o and o != 0
1285
+ else
1286
+ node = s(:dregx, '', node);
1287
+ node[0] = :dregx_once if options =~ /o/
1288
+ node << o if o and o != 0
1289
+ end
1290
+
1291
+ result = node
1292
+ }
1293
+
1294
+ words : tWORDS_BEG ' ' tSTRING_END {
1295
+ result = s(:zarray);
1296
+ }
1297
+ | tWORDS_BEG word_list tSTRING_END {
1298
+ result = val[1];
1299
+ }
1300
+
1301
+ word_list : {
1302
+ result = s(:array)
1303
+ }
1304
+ | word_list word ' ' {
1305
+ word = val[1][0] == :evstr ? s(:dstr, '', val[1]) : val[1]
1306
+ result = val[0] << word
1307
+ }
1308
+
1309
+ word : string_content
1310
+ | word string_content {
1311
+ result = self.literal_concat(val[0], val[1]);
1312
+ }
1313
+
1314
+ awords : tAWORDS_BEG ' ' tSTRING_END {
1315
+ result = s(:zarray)
1316
+ }
1317
+ | tAWORDS_BEG qword_list tSTRING_END {
1318
+ result = val[1]
1319
+ }
1320
+
1321
+ qword_list : {
1322
+ result = s(:array)
1323
+ }
1324
+ | qword_list tSTRING_CONTENT ' ' {
1325
+ result = val[0] << val[1]
1326
+ }
1327
+
1328
+ string_contents: { result = s(:str, "") }
1329
+ | string_contents string_content {
1330
+ result = literal_concat(val[0], val[1])
1331
+ }
1332
+
1333
+ xstring_contents: { result = nil }
1334
+ | xstring_contents string_content {
1335
+ result = literal_concat(val[0], val[1])
1336
+ }
1337
+
1338
+ string_content : tSTRING_CONTENT
1339
+ | tSTRING_DVAR {
1340
+ result = lexer.lex_strterm;
1341
+ lexer.lex_strterm = nil
1342
+ lexer.lex_state = :expr_beg
1343
+ } string_dvar {
1344
+ lexer.lex_strterm = val[1]
1345
+ result = s(:evstr, val[2]);
1346
+ }
1347
+ | tSTRING_DBEG {
1348
+ result = lexer.lex_strterm;
1349
+ lexer.lex_strterm = nil
1350
+ lexer.lex_state = :expr_beg
1351
+ lexer.cond.push false
1352
+ lexer.cmdarg.push false
1353
+ } compstmt tRCURLY {
1354
+ lexer.lex_strterm = val[1]
1355
+ lexer.cond.lexpop
1356
+ lexer.cmdarg.lexpop
1357
+ case val[2][0]
1358
+ when :str, :dstr, :evstr then
1359
+ result = val[2]
1360
+ else
1361
+ result = s(:evstr, val[2])
1362
+ end
1363
+ }
1364
+
1365
+ string_dvar : tGVAR {
1366
+ result = s(:gvar, val[0].to_sym);
1367
+ }
1368
+ | tIVAR {
1369
+ result = s(:ivar, val[0].to_sym);
1370
+ }
1371
+ | tCVAR {
1372
+ result = s(:cvar, val[0].to_sym);
1373
+ }
1374
+ | backref
1375
+
1376
+
1377
+ symbol : tSYMBEG sym {
1378
+ lexer.lex_state = :expr_end
1379
+ result = val[1].to_sym
1380
+ }
1381
+
1382
+ sym : fname | tIVAR | tGVAR | tCVAR
1383
+
1384
+ dsym : tSYMBEG xstring_contents tSTRING_END {
1385
+ lexer.lex_state = :expr_end
1386
+ result = val[1]
1387
+
1388
+ yyerror("empty symbol literal") if result.nil? or result.empty?
1389
+
1390
+ case result[0]
1391
+ when :dstr then
1392
+ result[0] = :dsym
1393
+ when :str then
1394
+ result = s(:lit, result.last.intern)
1395
+ else
1396
+ result = s(:dsym, '', result)
1397
+ end
1398
+
1399
+ }
1400
+
1401
+ numeric : tINTEGER
1402
+ | tFLOAT
1403
+ | tUMINUS_NUM tINTEGER =tLOWEST {
1404
+ result = -val[1] # TODO: pt_testcase
1405
+ }
1406
+ | tUMINUS_NUM tFLOAT =tLOWEST {
1407
+ result = -val[1] # TODO: pt_testcase
1408
+ }
1409
+
1410
+ variable : tIDENTIFIER
1411
+ | tIVAR
1412
+ | tGVAR
1413
+ | tCONSTANT
1414
+ | tCVAR
1415
+ | kNIL {
1416
+ result = s(:nil)
1417
+ }
1418
+ | kSELF {
1419
+ result = s(:self)
1420
+ }
1421
+ | kTRUE {
1422
+ result = s(:true)
1423
+ }
1424
+ | kFALSE {
1425
+ result = s(:false)
1426
+ }
1427
+ | k__FILE__ {
1428
+ result = :"__FILE__"
1429
+ }
1430
+ | k__LINE__ {
1431
+ result = :"__LINE__"
1432
+ }
1433
+
1434
+ var_ref : variable {
1435
+ result = self.gettable(val[0])
1436
+ }
1437
+
1438
+ var_lhs : variable {
1439
+ result = self.assignable(val[0]);
1440
+ }
1441
+
1442
+ backref : tNTH_REF | tBACK_REF
1443
+
1444
+ superclass : term {
1445
+ result = nil;
1446
+ }
1447
+ | tLT {
1448
+ lexer.lex_state = :expr_beg
1449
+ } expr_value term {
1450
+ result = val[2];
1451
+ }
1452
+ | error term {
1453
+ yyerrok;
1454
+ result = nil;
1455
+ }
1456
+
1457
+ f_arglist : tLPAREN2 f_args opt_nl tRPAREN {
1458
+ result = val[1];
1459
+ lexer.lex_state = :expr_beg
1460
+ }
1461
+ | f_args term {
1462
+ result = val[0];
1463
+ }
1464
+
1465
+ f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg {
1466
+ result = val[0]
1467
+ if val[2] then
1468
+ val[2][1..-1].each do |lasgn| # FIX clean sexp iter
1469
+ raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
1470
+ result << lasgn[1]
1471
+ end
1472
+ end
1473
+ result << val[4] if val[4]
1474
+ result << val[2] if val[2]
1475
+ result << val[5] if val[5]
1476
+ }
1477
+ | f_arg ',' f_optarg opt_f_block_arg {
1478
+ result = val[0]
1479
+ if val[2] then
1480
+ val[2][1..-1].each do |lasgn| # FIX clean sexp iter
1481
+ raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
1482
+ result << lasgn[1]
1483
+ end
1484
+ end
1485
+ result << val[2] if val[2]
1486
+ result << val[3] if val[3]
1487
+ }
1488
+ | f_arg ',' f_rest_arg opt_f_block_arg {
1489
+ result = val[0]
1490
+ result << val[2] if val[2]
1491
+ result << val[3] if val[3]
1492
+ }
1493
+ | f_arg opt_f_block_arg {
1494
+ result = val[0]
1495
+ result << val[1] if val[1]
1496
+ }
1497
+ | f_optarg ',' f_rest_arg opt_f_block_arg {
1498
+ result = s(:args)
1499
+ if val[0] then
1500
+ val[0][1..-1].each do |lasgn| # FIX clean sexp iter
1501
+ raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
1502
+ result << lasgn[1]
1503
+ end
1504
+ end
1505
+
1506
+ result << val[2] if val[2]
1507
+ result << val[0] if val[0]
1508
+ result << val[3] if val[3]
1509
+ }
1510
+ | f_optarg opt_f_block_arg {
1511
+ result = s(:args)
1512
+ if val[0] then
1513
+ val[0][1..-1].each do |lasgn| # FIX clean sexp iter
1514
+ raise "wtf? #{lasgn.inspect}" unless lasgn[0] == :lasgn
1515
+ result << lasgn[1]
1516
+ end
1517
+ end
1518
+
1519
+ result << val[0] if val[0]
1520
+ result << val[1] if val[1]
1521
+ }
1522
+ | f_rest_arg opt_f_block_arg {
1523
+ result = s(:args, val[0], val[1]).compact
1524
+ }
1525
+ | f_block_arg {
1526
+ result = s(:args, val[0]).compact
1527
+ }
1528
+ | {
1529
+ result = s(:args)
1530
+ }
1531
+
1532
+ f_norm_arg : tCONSTANT {
1533
+ yyerror("formal argument cannot be a constant");
1534
+ }
1535
+ | tIVAR {
1536
+ yyerror("formal argument cannot be an instance variable");
1537
+ }
1538
+ | tCVAR {
1539
+ yyerror("formal argument cannot be a class variable");
1540
+ }
1541
+ | tIDENTIFIER {
1542
+ identifier = val[0].to_sym
1543
+ self.env[identifier] = :lvar
1544
+
1545
+ result = val[0];
1546
+ }
1547
+
1548
+ f_arg : f_norm_arg {
1549
+ result = s(:args)
1550
+ result << val[0].to_sym
1551
+ }
1552
+ | f_arg ',' f_norm_arg {
1553
+ val[0] << val[2].to_sym
1554
+ result = val[0]
1555
+ }
1556
+
1557
+ f_opt : tIDENTIFIER '=' arg_value {
1558
+ result = self.assignable(val[0], val[2]);
1559
+ # TODO: detect duplicate names
1560
+ }
1561
+
1562
+ f_optarg : f_opt {
1563
+ result = s(:block, val[0])
1564
+ }
1565
+ | f_optarg ',' f_opt {
1566
+ result = self.append_to_block(val[0], val[2]);
1567
+ }
1568
+
1569
+ restarg_mark : tSTAR2 | tSTAR
1570
+
1571
+ f_rest_arg : restarg_mark tIDENTIFIER { # TODO: differs from parse.y - needs tests
1572
+ name = val[1].to_sym
1573
+ self.assignable(name)
1574
+ result = :"*#{name}"
1575
+ }
1576
+ | restarg_mark {
1577
+ name = :"*"
1578
+ self.env[name] = self.env.dynamic? ? :dvar : :lvar # FIX
1579
+ result = name
1580
+ }
1581
+
1582
+ blkarg_mark : tAMPER2 | tAMPER
1583
+
1584
+ f_block_arg : blkarg_mark tIDENTIFIER {
1585
+ identifier = val[1].to_sym
1586
+
1587
+ self.env[identifier] = self.env.dynamic? ? :dvar : :lvar
1588
+ result = s(:block_arg, identifier.to_sym)
1589
+ }
1590
+
1591
+ opt_f_block_arg: ',' f_block_arg {
1592
+ result = val[1];
1593
+ }
1594
+ | {
1595
+ result = nil;
1596
+ }
1597
+
1598
+ singleton : var_ref
1599
+ | tLPAREN2 {
1600
+ lexer.lex_state = :expr_beg
1601
+ } expr opt_nl tRPAREN {
1602
+ if (val[2].instanceof ILiteralNode) then
1603
+ yyerror("Can't define single method for literals.");
1604
+ end
1605
+ result = val[2];
1606
+ }
1607
+
1608
+ assoc_list : none { # [!nil]
1609
+ result = s(:array)
1610
+ }
1611
+ | assocs trailer { # [!nil]
1612
+ result = val[0];
1613
+ }
1614
+ | args trailer {
1615
+ size = val[0].size
1616
+ if (size % 2 != 1) then # != 1 because of leading :array
1617
+ yyerror("Odd number (#{size}) list for Hash. #{val[0].inspect}");
1618
+ end
1619
+ result = val[0];
1620
+ }
1621
+
1622
+ assocs : assoc
1623
+ | assocs ',' assoc {
1624
+ list = val[0].dup
1625
+ more = val[2][1..-1]
1626
+ list.push(*more) unless more.empty?
1627
+ result = list
1628
+ }
1629
+
1630
+ assoc : arg_value tASSOC arg_value {
1631
+ result = s(:array, val[0], val[2])
1632
+ }
1633
+
1634
+ operation : tIDENTIFIER | tCONSTANT | tFID
1635
+ operation2 : tIDENTIFIER | tCONSTANT | tFID | op
1636
+ operation3 : tIDENTIFIER | tFID | op
1637
+ dot_or_colon : tDOT | tCOLON2
1638
+ opt_terms : | terms
1639
+ opt_nl : | "\n"
1640
+ trailer : | "\n" | ','
1641
+
1642
+ term : ';' { yyerrok }
1643
+ | "\n"
1644
+
1645
+ terms : term
1646
+ | terms ';' { yyerrok }
1647
+
1648
+ none : { result = nil }
1649
+
1650
+ none_block_pass: { result = nil }
1651
+
1652
+ end
1653
+
1654
+ ---- inner
1655
+
1656
+ require 'ruby_lexer'