forked from sorbet/sorbet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
typedruby.ypp
3658 lines (3433 loc) · 127 KB
/
typedruby.ypp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%require "3.0"
%skeleton "lalr1.cc"
%token-table
%code requires {
#include <ruby_parser/builder.hh>
#include <ruby_parser/node.hh>
#include <ruby_parser/token.hh>
#include <ruby_parser/lexer.hh>
#include <ruby_parser/driver.hh>
#include <ruby_parser/state_stack.hh>
#include <iterator>
#include <utility>
#include <cstdlib>
using namespace ruby_parser;
using namespace std::string_literals;
#ifndef YY_NULLPTR
#define YY_NULLPTR nullptr
#endif
}
%param { ruby_parser::typedruby27& driver }
%parse-param { ruby_parser::SelfPtr self }
%define api.namespace {ruby_parser::bison::typedruby27}
%define api.prefix {typedruby27}
%define api.value.type { union parser_value }
%define api.token.constructor false
%define parse.assert
%define parse.error verbose
// mirrored in inc/ruby_parser/token.hh
// if any of these token values are changed here, the header must be updated
// as well.
%token <token>
eof 0 "end of file"
kCLASS 1001 "class"
kMODULE 1002 "module"
kDEF 1003 "def"
kUNDEF 1004 "undef"
kBEGIN 1005 "begin"
kRESCUE 1006 "rescue"
kENSURE 1007 "ensure"
kEND 1008 "end"
kIF 1009 "if"
kUNLESS 1010 "unless"
kTHEN 1011 "then"
kELSIF 1012 "elsif"
kELSE 1013 "else"
kCASE 1014 "case"
kWHEN 1015 "when"
kWHILE 1016 "while"
kUNTIL 1017 "until"
kFOR 1018 "for"
kBREAK 1019 "break"
kNEXT 1020 "next"
kREDO 1021 "redo"
kRETRY 1022 "retry"
kIN 1023 "in"
kDO 1024 "do"
kDO_COND 1025
kDO_BLOCK 1026
kDO_LAMBDA 1027
kRETURN 1028 "return"
kYIELD 1029 "yield"
kSUPER 1030 "super"
kSELF 1031 "self"
kNIL 1032 "nil"
kTRUE 1033 "true"
kFALSE 1034 "false"
kAND 1035 "and"
kOR 1036 "or"
kNOT 1037 "not"
kIF_MOD 1038
kUNLESS_MOD 1039
kWHILE_MOD 1040
kUNTIL_MOD 1041
kRESCUE_MOD 1042
kALIAS 1043 "alias"
kDEFINED 1044 "defined?"
klBEGIN 1045 "BEGIN"
klEND 1046 "END"
k__LINE__ 1047 "__LINE__"
k__FILE__ 1048 "__FILE__"
k__ENCODING__ 1049 "__ENCODING__"
tIDENTIFIER 1050
tFID 1051
tGVAR 1052
tIVAR 1053
tCONSTANT 1054
tLABEL 1055
tCVAR 1056
tNTH_REF 1057
tBACK_REF 1058
tSTRING_CONTENT 1059
tINTEGER 1060
tFLOAT 1061
tUPLUS 1062
tUMINUS 1063
tUNARY_NUM 1064
tPOW 1065
tCMP 1066 "<=>"
tEQ 1067 "=="
tEQQ 1068 "==="
tNEQ 1069 "!="
tEQL 1070 "="
tGEQ 1071 ">="
tLEQ 1072 "<="
tANDOP 1073 "&&"
tOROP 1074 "||"
tMATCH 1075 "=~"
tNMATCH 1076 "!~"
tDOT 1077 "."
tDOT2 1078 ".."
tDOT3 1079 "..."
tAREF 1080 "[]"
tASET 1081 "[]="
tLSHFT 1082 "<<"
tRSHFT 1083 ">>"
tCOLON2 1084 "::"
tCOLON3 1085
tOP_ASGN 1086
tASSOC 1087 "=>"
tLPAREN 1088 "("
tLPAREN2 1089
tRPAREN 1090 ")"
tLPAREN_ARG 1091
tLBRACK 1092 "["
tLBRACK2 1093
tRBRACK 1094 "]"
tLBRACE 1095 "{"
tLBRACE_ARG 1096
tSTAR 1097 "*"
tSTAR2 1098
tAMPER 1099 "&"
tAMPER2 1100
tTILDE 1101 "~"
tPERCENT 1102 "%"
tDIVIDE 1103 "/"
tDSTAR 1104 "**"
tPLUS 1105 "+"
tMINUS 1106 "-"
tLT 1107 "<"
tGT 1108 ">"
tPIPE 1109 "|"
tBANG 1110 "!"
tCARET 1111 "^"
tLCURLY 1112
tRCURLY 1113
tBACK_REF2 1114 "`"
tSYMBEG 1115
tSTRING_BEG 1116
tXSTRING_BEG 1117
tREGEXP_BEG 1118
tREGEXP_OPT 1119
tWORDS_BEG 1120
tQWORDS_BEG 1121
tSYMBOLS_BEG 1122
tQSYMBOLS_BEG 1123
tSTRING_DBEG 1124
tSTRING_DVAR 1125
tSTRING_END 1126
tSTRING_DEND 1127
tSTRING 1128
tSYMBOL 1129
tNL 1130
tEH 1131 "?"
tCOLON 1132 ":"
tCOMMA 1133 ","
tSPACE 1134
tSEMI 1135 ";"
tLAMBDA 1136 "->"
tLAMBEG 1137
tCHARACTER 1138
tRATIONAL 1139
tIMAGINARY 1140
tLABEL_END 1141
tANDDOT 1142 "&."
tRATIONAL_IMAGINARY 1143
tFLOAT_IMAGINARY 1144
tBDOT2 1145 // Used to avoid shift/reduce conflicts with productions using `tDOT2`
tBDOT3 1146 // Used to avoid shift/reduce conflicts with productions using `tDOT3`
;
%type <node>
arg
arg_rhs
arg_value
assoc
backref
block_arg
block_call
block_command
block_param_def
bodystmt
bvar
command
command_asgn
command_call
command_rhs
compstmt
cpath
defs_head
dsym
expr
expr_value
f_arg_item
f_arglist
f_block_kw
f_block_opt
f_kw
f_larglist
f_marg
f_opt
f_paren_args
f_opt_paren_args
f_rest_marg
fitem
for_var
keyword_variable
lhs
literal
method_call
mlhs
mlhs_inner
mlhs_item
mlhs_node
mrhs_arg
none
numeric
opt_block_param
p_alt
p_arg
p_as
p_const
p_expr
p_expr_basic
p_kw
p_kw_label
p_primitive
p_rest
p_top_expr_body
p_var_ref
p_value
p_variable
primary
primary_value
qsymbols
qwords
regexp
ssym
simple_numeric
singleton
stmt
stmt_or_begin
string1
string_content
string_dvar
strings
symbol
symbols
top_compstmt
top_stmt
user_variable
var_lhs
var_ref
words
xstring
rel_expr
%type <list>
aref_args
args
args_tail
assoc_list
assocs
block_args_tail
block_param
bv_decls
call_args
command_args
exc_list
f_arg
f_args
f_block_arg
f_block_kwarg
f_block_optarg
f_kwarg
f_kwrest
f_marg_list
f_margs
f_optarg
f_no_kwarg
f_rest_arg
list_none
mlhs_basic
mlhs_head
mlhs_post
mrhs
opt_args_tail
opt_block_arg
opt_block_args_tail
opt_bv_decl
opt_call_args
opt_f_block_arg
opt_rescue
p_args
p_args_head
p_args_post
p_args_tail
p_find
p_kwarg
p_kwargs
p_kwnorest
p_kwrest
p_top_expr
qsym_list
qword_list
regexp_contents
stmts
string
string_contents
symbol_list
top_stmts
undef_list
word
word_list
xstring_contents
%type <token>
args_forward
blkarg_mark
call_op
cname
def_name
do
dot_or_colon
f_arg_asgn
f_bad_arg
f_label
f_norm_arg
fcall
fname
kwrest_mark
op
operation
operation2
operation3
p_lparen
p_lbracket
rbrace
rbracket
restarg_mark
reswords
rparen
term
then
relop
k_return
%type <delimited_list>
defn_head
opt_paren_args
paren_args
%type <delimited_block>
brace_block
brace_body
cmd_brace_block
do_block
do_body
lambda
lambda_body
begin_block
%type <with_token>
exc_var
if_tail
opt_else
opt_ensure
superclass
expr_value_do
%type <case_body>
case_body
cases
p_case_body
p_cases
%nonassoc tLOWEST
%nonassoc tLBRACE_ARG
%nonassoc kIF_MOD kUNLESS_MOD kWHILE_MOD kUNTIL_MOD kIN
%left kOR kAND
%right kNOT
%nonassoc kDEFINED
%right tEQL tOP_ASGN
%left kRESCUE_MOD
%right tEH tCOLON
%nonassoc tDOT2 tDOT3 tBDOT2 tBDOT3
%left tOROP
%left tANDOP
%nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH
%left tGT tGEQ tLT tLEQ
%left tPIPE tCARET
%left tAMPER2
%left tLSHFT tRSHFT
%left tPLUS tMINUS
%left tSTAR2 tDIVIDE tPERCENT
%right tUNARY_NUM tUMINUS
%right tPOW
%right tBANG tTILDE tUPLUS
%code requires {
union parser_value {
ruby_parser::token *token;
ruby_parser::delimited_node_list *delimited_list;
ruby_parser::delimited_block *delimited_block;
ruby_parser::node_with_token *with_token;
ruby_parser::case_body *case_body;
ruby_parser::ForeignPtr node;
ruby_parser::node_list *list;
ruby_parser::state_stack *stack;
size_t size;
bool boolean;
};
}
%code {
namespace ruby_parser {
namespace bison {
namespace typedruby27 {
#define DIAGCHECK() do { \
if (driver.pending_error) { \
driver.pending_error = false; \
YYERROR; \
} \
} while(false);
void parser::error(const std::string &msg) {
std::string error_message = msg;
int token_type = static_cast<int>(driver.last_token->type());
const char* token_str_name = yytname_[yytranslate_(token_type)];
if (token_type == token_type::tBDOT2) {
// Because we have two tokens matching `..`, we can't set the token name as `..` directly.
// This hack allows to display the real token string instead of `tBDOT2` in parsing errors.
error_message = "\"..\"";
} else if (token_type == token_type::tBDOT3) {
// Because we have two tokens matching `...`, we can't set the token name as `...` directly.
// This hack allows to display the real token string instead of `tBDOT3` in parsing errors.
error_message = "\"...\"";
} else if (token_str_name != nullptr) {
error_message = token_str_name;
}
driver.diagnostics.emplace_back(
dlevel::ERROR, dclass::UnexpectedToken,
diagnostic::range(driver.lex.last_token_s, driver.lex.last_token_e),
error_message);
}
int yylex(parser::semantic_type *lval, ruby_parser::typedruby27 &driver) {
auto token = driver.lex.advance();
driver.last_token = token;
int token_type = static_cast<int>(token->type());
assert(token_type >= 0);
lval->token = token;
return token_type;
}
}}} // namespace
} // %code
%%
program: top_compstmt
{
driver.ast = $1;
}
top_compstmt: top_stmts opt_terms
{
$$ = driver.build.compstmt(self, $1);
}
top_stmts: // nothing
{
$$ = driver.alloc.node_list();
}
| top_stmt
{
$$ = driver.alloc.node_list($1);
}
| top_stmts terms top_stmt
{
$1->emplace_back($3);
$$ = $1;
}
| error top_stmt
{
$$ = driver.alloc.node_list($2);
}
top_stmt: stmt
| klBEGIN begin_block
{
auto &delimited_block = $2;
$$ = driver.build.preexe(self, $1, delimited_block->body, delimited_block->end);
}
begin_block: tLCURLY top_compstmt tRCURLY
{
$$ = driver.alloc.delimited_block($1, nullptr, $2, $3);
}
bodystmt: compstmt opt_rescue opt_else opt_ensure
{
auto &rescueBodies = $2;
auto &else_ = $3;
auto &ensure = $4;
if (rescueBodies->size() == 0 && else_ != nullptr) {
driver.diagnostics.emplace_back(
dlevel::ERROR,
dclass::UselessElse,
else_->tok
);
}
$$ = driver.build.beginBody(
self,
$1,
rescueBodies,
else_ ? else_->tok : nullptr,
else_ ? else_->nod : nullptr,
ensure ? ensure->tok : nullptr,
ensure ? ensure->nod : nullptr
);
}
compstmt: stmts opt_terms
{
$$ = driver.build.compstmt(self, $1);
}
stmts: // nothing
{
$$ = driver.alloc.node_list();
}
| stmt_or_begin
{
$$ = driver.alloc.node_list($1);
}
| stmts terms stmt_or_begin
{
$1->emplace_back($3);
$$ = $1;
}
| error
{
$$ = driver.alloc.node_list();
}
stmt_or_begin: stmt
| klBEGIN begin_block
{
driver.diagnostics.emplace_back(
dlevel::ERROR,
dclass::BeginInMethod,
$1
);
YYERROR;
}
stmt: kALIAS fitem
{
driver.lex.set_state_expr_fname();
}
fitem
{
$$ = driver.build.alias(self, $1, $2, $4);
}
| kALIAS tGVAR tGVAR
{
$$ = driver.build.alias(self, $1, driver.build.gvar(self, $2), driver.build.gvar(self, $3));
}
| kALIAS tGVAR tBACK_REF
{
$$ = driver.build.alias(self, $1, driver.build.gvar(self, $2), driver.build.backRef(self, $3));
}
| kALIAS tGVAR tNTH_REF
{
driver.diagnostics.emplace_back(dlevel::ERROR, dclass::NthRefAlias, $3);
YYERROR;
}
| kUNDEF undef_list
{
$$ = driver.build.undefMethod(self, $1, $2);
}
| stmt kIF_MOD expr_value
{
$$ = driver.build.conditionMod(self, $1, nullptr, $3);
}
| stmt kUNLESS_MOD expr_value
{
$$ = driver.build.conditionMod(self, nullptr, $1, $3);
}
| stmt kWHILE_MOD expr_value
{
$$ = driver.build.loop_while_mod(self, $1, $3);
}
| stmt kUNTIL_MOD expr_value
{
$$ = driver.build.loopUntil_mod(self, $1, $3);
}
| stmt kRESCUE_MOD stmt
{
ruby_parser::node_list rescue_body(
driver.build.rescue_body(self, $2, nullptr, nullptr, nullptr, nullptr, $3));
$$ = driver.build.beginBody(self, $1, &rescue_body, nullptr, nullptr, nullptr, nullptr);
}
| klEND tLCURLY compstmt tRCURLY
{
$$ = driver.build.postexe(self, $1, $3, $4);
}
| command_asgn
| mlhs tEQL command_call
{
$$ = driver.build.multi_assign(self, $1, $3);
}
| lhs tEQL mrhs
{
$$ = driver.build.assign(self, $1, $2, driver.build.array(self, nullptr, $3, nullptr));
}
| mlhs tEQL mrhs_arg kRESCUE_MOD stmt
{
ruby_parser::node_list rescue_body(
driver.build.rescue_body(self, $4, nullptr, nullptr, nullptr, nullptr, $5));
auto begin_body = driver.build.beginBody(self, $3, &rescue_body, nullptr, nullptr, nullptr, nullptr);
$$ = driver.build.multi_assign(self, $1, begin_body);
}
| mlhs tEQL mrhs_arg
{
$$ = driver.build.multi_assign(self, $1, $3);
}
| expr
command_asgn: lhs tEQL command_rhs
{
$$ = driver.build.assign(self, $1, $2, $3);
}
| var_lhs tOP_ASGN command_rhs
{
$$ = driver.build.op_assign(self, $1, $2, $3);
DIAGCHECK();
}
| primary_value tLBRACK2 opt_call_args rbracket tOP_ASGN command_rhs
{
$$ = driver.build.op_assign(self, driver.build.index(self, $1, $2, $3, $4), $5, $6);
DIAGCHECK();
}
| primary_value call_op tIDENTIFIER tOP_ASGN command_rhs
{
$$ = driver.build.op_assign(self, driver.build.call_method(self, $1, $2, $3, nullptr, nullptr, nullptr), $4, $5);
DIAGCHECK();
}
| primary_value call_op tCONSTANT tOP_ASGN command_rhs
{
$$ = driver.build.op_assign(self, driver.build.call_method(self, $1, $2, $3, nullptr, nullptr, nullptr), $4, $5);
DIAGCHECK();
}
| primary_value tCOLON2 tCONSTANT tOP_ASGN command_rhs
{
auto const_node = driver.build.constOpAssignable(self, driver.build.constFetch(self, $1, $2, $3));
$$ = driver.build.op_assign(self, const_node, $4, $5);
DIAGCHECK();
}
| primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_rhs
{
$$ = driver.build.op_assign(self, driver.build.call_method(self, $1, $2, $3, nullptr, nullptr, nullptr), $4, $5);
DIAGCHECK();
}
| backref tOP_ASGN command_rhs
{
$$ = driver.build.op_assign(self, $1, $2, $3);
DIAGCHECK();
}
command_rhs: command_call %prec tOP_ASGN
| command_call kRESCUE_MOD stmt
{
node_list rescue_body(
driver.build.rescue_body(self, $2, nullptr, nullptr, nullptr, nullptr, $3)
);
$$ = driver.build.beginBody(self, $1, &rescue_body, nullptr, nullptr, nullptr, nullptr);
}
| command_asgn
expr: command_call
| expr kAND expr
{
$$ = driver.build.logicalAnd(self, $1, $2, $3);
}
| expr kOR expr
{
$$ = driver.build.logicalOr(self, $1, $2, $3);
}
| kNOT opt_nl expr
{
$$ = driver.build.not_op(self, $1, nullptr, $3, nullptr);
}
| tBANG command_call
{
$$ = driver.build.not_op(self, $1, nullptr, $2, nullptr);
}
| arg tASSOC
{
driver.lex.set_state_expr_beg();
driver.lex.unset_command_start();
driver.pattern_variables.push();
$<boolean>$ = driver.lex.in_kwarg;
driver.lex.in_kwarg = true;
}
p_expr
{
driver.lex.in_kwarg = $<boolean>3;
$$ = driver.build.match_pattern(self, $1, $2, $4);
}
| arg kIN
{
driver.lex.set_state_expr_beg();
driver.lex.unset_command_start();
driver.pattern_variables.push();
$<boolean>$ = driver.lex.in_kwarg;
driver.lex.in_kwarg = true;
}
p_expr
{
driver.lex.in_kwarg = $<boolean>3;
$$ = driver.build.match_pattern_p(self, $1, $2, $4);
}
| arg %prec tLBRACE_ARG
expr_value: expr
expr_value_do: {
driver.lex.cond.push(true);
}
expr_value do
{
driver.lex.cond.pop();
$$ = driver.alloc.node_with_token($3, $2);
}
def_name: fname
{
driver.lex.extend_static();
driver.lex.cmdarg.push(false);
driver.lex.cond.push(false);
driver.current_arg_stack.push("");
$$ = $1;
}
defn_head: kDEF def_name
{
driver.lex.context.push(Context::State::DEF);
$$ = driver.alloc.delimited_node_list($1, driver.alloc.node_list(), $2);
}
defs_head: kDEF singleton dot_or_colon
{
driver.lex.set_state_expr_fname();
}
def_name
{
driver.lex.context.push(Context::State::DEFS);
$$ = driver.build.defsHead(self, $1, $2, $3, $5);
}
command_call: command
| block_command
block_command: block_call
| block_call dot_or_colon operation2 command_args
{
$$ = driver.build.call_method(self, $1, $2, $3, nullptr, $4, nullptr);
}
cmd_brace_block: tLBRACE_ARG
{
driver.lex.context.push(Context::State::BLOCK);
}
brace_body tRCURLY
{
auto &block = $3;
block->begin = $1;
block->end = $4;
$$ = block;
driver.lex.context.pop();
}
fcall: operation
command: fcall command_args %prec tLOWEST
{
$$ = driver.build.call_method(self, nullptr, nullptr, $1, nullptr, $2, nullptr);
}
| fcall command_args cmd_brace_block
{
auto method_call = driver.build.call_method(self, nullptr, nullptr, $1, nullptr, $2, nullptr);
auto &delimited_block = $3;
$$ = driver.build.block(self, method_call,
delimited_block->begin,
delimited_block->args,
delimited_block->body,
delimited_block->end);
DIAGCHECK();
}
| primary_value call_op operation2 command_args %prec tLOWEST
{
$$ = driver.build.call_method(self, $1, $2, $3, nullptr, $4, nullptr);
}
| primary_value call_op operation2 command_args cmd_brace_block
{
auto method_call = driver.build.call_method(self, $1, $2, $3, nullptr, $4, nullptr);
auto &delimited_block = $5;
$$ = driver.build.block(self, method_call,
delimited_block->begin,
delimited_block->args,
delimited_block->body,
delimited_block->end);
DIAGCHECK();
}
| primary_value tCOLON2 operation2 command_args %prec tLOWEST
{
$$ = driver.build.call_method(self, $1, $2, $3, nullptr, $4, nullptr);
}
| primary_value tCOLON2 operation2 command_args cmd_brace_block
{
auto method_call = driver.build.call_method(self, $1, $2, $3, nullptr, $4, nullptr);
auto &delimited_block = $5;
$$ = driver.build.block(self, method_call,
delimited_block->begin,
delimited_block->args,
delimited_block->body,
delimited_block->end);
DIAGCHECK();
}
| kSUPER command_args
{
$$ = driver.build.keywordSuper(self, $1, nullptr, $2, nullptr);
}
| kYIELD command_args
{
$$ = driver.build.keywordYield(self, $1, nullptr, $2, nullptr);
DIAGCHECK();
}
| k_return call_args
{
$$ = driver.build.keywordReturn(self, $1, nullptr, $2, nullptr);
}
| kBREAK call_args
{
$$ = driver.build.keywordBreak(self, $1, nullptr, $2, nullptr);
}
| kNEXT call_args
{
$$ = driver.build.keywordNext(self, $1, nullptr, $2, nullptr);
}
mlhs: mlhs_basic
{
$$ = driver.build.multi_lhs(self, nullptr, $1, nullptr);
}
| tLPAREN mlhs_inner rparen
{
$$ = driver.build.begin(self, $1, $2, $3);
}
mlhs_inner: mlhs_basic
{
$$ = driver.build.multi_lhs(self, nullptr, $1, nullptr);
}
| tLPAREN mlhs_inner rparen
{
$$ = driver.build.multi_lhs1(self, $1, $2, $3);
}
mlhs_basic: mlhs_head
| mlhs_head mlhs_item
{
auto &list = $1;
list->emplace_back($2);
$$ = list;
}
| mlhs_head tSTAR mlhs_node
{
auto &list = $1;
list->emplace_back(driver.build.splat_mlhs(self, $2, $3));
$$ = list;
}
| mlhs_head tSTAR mlhs_node tCOMMA mlhs_post
{
auto &head = $1;
head->emplace_back(driver.build.splat_mlhs(self, $2, $3));
head->concat($5);
$$ = head;
}
| mlhs_head tSTAR
{
auto &list = $1;
list->emplace_back(driver.build.splat_mlhs(self, $2, nullptr));
$$ = list;
}
| mlhs_head tSTAR tCOMMA mlhs_post
{
auto &head = $1;
head->emplace_back(driver.build.splat_mlhs(self, $2, nullptr));
head->concat($4);
$$ = head;
}
| tSTAR mlhs_node
{
$$ = driver.alloc.node_list(driver.build.splat_mlhs(self, $1, $2));
}
| tSTAR mlhs_node tCOMMA mlhs_post
{
node_list *items = driver.alloc.node_list(driver.build.splat_mlhs(self, $1, $2));
items->concat($4);
$$ = items;
}
| tSTAR
{
$$ = driver.alloc.node_list(driver.build.splat_mlhs(self, $1, nullptr));
}
| tSTAR tCOMMA mlhs_post
{
node_list *items = driver.alloc.node_list(driver.build.splat_mlhs(self, $1, nullptr));
items->concat($3);
$$ = items;
}
mlhs_item: mlhs_node
| tLPAREN mlhs_inner rparen
{
$$ = driver.build.begin(self, $1, $2, $3);
}
mlhs_head: mlhs_item tCOMMA
{
$$ = driver.alloc.node_list($1);
}
| mlhs_head mlhs_item tCOMMA
{
auto &list = $1;
list->emplace_back($2);
$$ = list;
}
mlhs_post: mlhs_item
{
$$ = driver.alloc.node_list($1);
}
| mlhs_post tCOMMA mlhs_item
{
auto &list = $1;
list->emplace_back($3);
$$ = list;
}
mlhs_node: user_variable
{
$$ = driver.build.assignable(self, $1);
DIAGCHECK();
}
| keyword_variable
{
$$ = driver.build.assignable(self, $1);
DIAGCHECK();
}
| primary_value tLBRACK2 opt_call_args rbracket
{
$$ = driver.build.indexAsgn(self, $1, $2, $3, $4);
}
| primary_value call_op tIDENTIFIER
{
$$ = driver.build.attrAsgn(self, $1, $2, $3, true);
}
| primary_value tCOLON2 tIDENTIFIER
{
$$ = driver.build.attrAsgn(self, $1, $2, $3, false);
}