Ruby 3.3.6p108 (2024-11-05 revision 75015d4c1f6965b5e85e96fb309f1f2129f933c0)
prism_compile.c
1#include "prism.h"
2
3#define OLD_ISEQ NEW_ISEQ
4#undef NEW_ISEQ
5
6#define NEW_ISEQ(node, name, type, line_no) \
7 pm_new_child_iseq(iseq, (node), parser, rb_fstring(name), 0, (type), (line_no))
8
9#define OLD_CHILD_ISEQ NEW_CHILD_ISEQ
10#undef NEW_CHILD_ISEQ
11
12#define NEW_CHILD_ISEQ(node, name, type, line_no) \
13 pm_new_child_iseq(iseq, (node), parser, rb_fstring(name), iseq, (type), (line_no))
14
15#define PM_COMPILE(node) \
16 pm_compile_node(iseq, (node), ret, src, popped, scope_node)
17
18#define PM_COMPILE_INTO_ANCHOR(_ret, node) \
19 pm_compile_node(iseq, (node), _ret, src, popped, scope_node)
20
21#define PM_COMPILE_POPPED(node) \
22 pm_compile_node(iseq, (node), ret, src, true, scope_node)
23
24#define PM_COMPILE_NOT_POPPED(node) \
25 pm_compile_node(iseq, (node), ret, src, false, scope_node)
26
27#define PM_POP \
28 ADD_INSN(ret, &dummy_line_node, pop);
29
30#define PM_POP_IF_POPPED \
31 if (popped) PM_POP;
32
33#define PM_POP_UNLESS_POPPED \
34 if (!popped) PM_POP;
35
36#define PM_DUP \
37 ADD_INSN(ret, &dummy_line_node, dup);
38
39#define PM_DUP_UNLESS_POPPED \
40 if (!popped) PM_DUP;
41
42#define PM_PUTSELF \
43 ADD_INSN(ret, &dummy_line_node, putself);
44
45#define PM_PUTNIL \
46 ADD_INSN(ret, &dummy_line_node, putnil);
47
48#define PM_PUTNIL_UNLESS_POPPED \
49 if (!popped) PM_PUTNIL;
50
51#define PM_SWAP \
52 ADD_INSN(ret, &dummy_line_node, swap);
53
54#define PM_SWAP_UNLESS_POPPED \
55 if (!popped) PM_SWAP;
56
57#define PM_NOP \
58 ADD_INSN(ret, &dummy_line_node, nop);
59
71#define TEMP_CONSTANT_IDENTIFIER ((pm_constant_id_t)(1 << 31))
72
74pm_iseq_new_with_opt(pm_scope_node_t *scope_node, pm_parser_t *parser, VALUE name, VALUE path, VALUE realpath,
75 int first_lineno, const rb_iseq_t *parent, int isolated_depth,
76 enum rb_iseq_type type, const rb_compile_option_t *option);
77
78static VALUE
79parse_integer(const pm_integer_node_t *node)
80{
81 char *start = (char *) node->base.location.start;
82 char *end = (char *) node->base.location.end;
83
84 size_t length = end - start;
85 int base = -10;
86
89 base = 2;
90 break;
92 base = 10;
93 break;
95 base = 8;
96 break;
98 base = 16;
99 break;
100 default:
101 rb_bug("Unexpected integer base");
102 }
103
104 return rb_int_parse_cstr(start, length, &end, NULL, base, RB_INT_PARSE_DEFAULT);
105}
106
107static VALUE
108parse_float(const pm_node_t *node)
109{
110 const uint8_t *start = node->location.start;
111 const uint8_t *end = node->location.end;
112 size_t length = end - start;
113
114 char *buffer = malloc(length + 1);
115 memcpy(buffer, start, length);
116
117 buffer[length] = '\0';
118 VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 0));
119
120 free(buffer);
121 return number;
122}
123
124static VALUE
125parse_rational(const pm_node_t *node)
126{
127 const uint8_t *start = node->location.start;
128 const uint8_t *end = node->location.end - 1;
129 size_t length = end - start;
130
131 VALUE res;
132 if (PM_NODE_TYPE_P(((pm_rational_node_t *)node)->numeric, PM_FLOAT_NODE)) {
133 char *buffer = malloc(length + 1);
134 memcpy(buffer, start, length);
135
136 buffer[length] = '\0';
137
138 char *decimal = memchr(buffer, '.', length);
139 RUBY_ASSERT(decimal);
140 size_t seen_decimal = decimal - buffer;
141 size_t fraclen = length - seen_decimal - 1;
142 memmove(decimal, decimal + 1, fraclen + 1);
143
144 VALUE v = rb_cstr_to_inum(buffer, 10, false);
145 res = rb_rational_new(v, rb_int_positive_pow(10, fraclen));
146
147 free(buffer);
148 }
149 else {
151 VALUE number = rb_int_parse_cstr((const char *)start, length, NULL, NULL, -10, RB_INT_PARSE_DEFAULT);
152 res = rb_rational_raw(number, INT2FIX(1));
153 }
154
155 return res;
156}
157
158static VALUE
159parse_imaginary(pm_imaginary_node_t *node)
160{
161 VALUE imaginary_part;
162 switch (PM_NODE_TYPE(node->numeric)) {
163 case PM_FLOAT_NODE: {
164 imaginary_part = parse_float(node->numeric);
165 break;
166 }
167 case PM_INTEGER_NODE: {
168 imaginary_part = parse_integer((pm_integer_node_t *) node->numeric);
169 break;
170 }
171 case PM_RATIONAL_NODE: {
172 imaginary_part = parse_rational(node->numeric);
173 break;
174 }
175 default:
176 rb_bug("Unexpected numeric type on imaginary number");
177 }
178
179 return rb_complex_raw(INT2FIX(0), imaginary_part);
180}
181
182static inline VALUE
183parse_string(pm_string_t *string, const pm_parser_t *parser)
184{
185 rb_encoding *enc = rb_enc_from_index(rb_enc_find_index(parser->encoding->name));
186 return rb_enc_str_new((const char *) pm_string_source(string), pm_string_length(string), enc);
187}
188
194static inline VALUE
195parse_string_encoded(const pm_node_t *node, const pm_string_t *string, const pm_parser_t *parser) {
196 rb_encoding *encoding;
197
199 encoding = rb_ascii8bit_encoding();
201 encoding = rb_utf8_encoding();
202 } else {
203 encoding = rb_enc_from_index(rb_enc_find_index(parser->encoding->name));
204 }
205
206 return rb_enc_str_new((const char *) pm_string_source(string), pm_string_length(string), encoding);
207}
208
209static inline ID
210parse_symbol(const uint8_t *start, const uint8_t *end, pm_parser_t *parser)
211{
212 rb_encoding *enc = rb_enc_from_index(rb_enc_find_index(parser->encoding->name));
213 return rb_intern3((const char *) start, end - start, enc);
214}
215
216static inline ID
217parse_string_symbol(const pm_string_t *string, pm_parser_t *parser)
218{
219 const uint8_t *start = pm_string_source(string);
220 return parse_symbol(start, start + pm_string_length(string), parser);
221}
222
223static inline ID
224parse_location_symbol(pm_location_t *location, pm_parser_t *parser)
225{
226 return parse_symbol(location->start, location->end, parser);
227}
228
229static int
230pm_optimizable_range_item_p(pm_node_t *node)
231{
232 return (!node || PM_NODE_TYPE_P(node, PM_INTEGER_NODE) || PM_NODE_TYPE_P(node, PM_NIL_NODE));
233}
234
235#define RE_OPTION_ENCODING_SHIFT 8
236
241static int
242pm_reg_flags(const pm_node_t *node) {
243 int flags = 0;
244 int dummy = 0;
245
246 // Check "no encoding" first so that flags don't get clobbered
247 // We're calling `rb_char_to_option_kcode` in this case so that
248 // we don't need to have access to `ARG_ENCODING_NONE`
250 rb_char_to_option_kcode('n', &flags, &dummy);
251 }
252
254 rb_char_to_option_kcode('e', &flags, &dummy);
255 flags |= ('e' << RE_OPTION_ENCODING_SHIFT);
256 }
257
259 rb_char_to_option_kcode('s', &flags, &dummy);
260 flags |= ('s' << RE_OPTION_ENCODING_SHIFT);
261 }
262
264 rb_char_to_option_kcode('u', &flags, &dummy);
265 flags |= ('u' << RE_OPTION_ENCODING_SHIFT);
266 }
267
269 flags |= ONIG_OPTION_IGNORECASE;
270 }
271
273 flags |= ONIG_OPTION_MULTILINE;
274 }
275
277 flags |= ONIG_OPTION_EXTEND;
278 }
279
280 return flags;
281}
282
283static rb_encoding *
284pm_reg_enc(const pm_regular_expression_node_t *node, const pm_parser_t *parser) {
286 return rb_ascii8bit_encoding();
287 }
288
290 return rb_enc_get_from_index(ENCINDEX_EUC_JP);
291 }
292
294 return rb_enc_get_from_index(ENCINDEX_Windows_31J);
295 }
296
298 return rb_utf8_encoding();
299 }
300
301 return rb_enc_from_index(rb_enc_find_index(parser->encoding->name));
302}
303
309static inline bool
310pm_static_literal_p(const pm_node_t *node)
311{
312 return node->flags & PM_NODE_FLAG_STATIC_LITERAL;
313}
314
315static VALUE
316pm_new_regex(pm_regular_expression_node_t * cast, const pm_parser_t * parser) {
317 VALUE regex_str = parse_string(&cast->unescaped, parser);
318 rb_encoding * enc = pm_reg_enc(cast, parser);
319
320 return rb_enc_reg_new(RSTRING_PTR(regex_str), RSTRING_LEN(regex_str), enc, pm_reg_flags((const pm_node_t *)cast));
321}
322
328static inline VALUE
329pm_static_literal_value(const pm_node_t *node, pm_scope_node_t *scope_node, pm_parser_t *parser)
330{
331 // Every node that comes into this function should already be marked as
332 // static literal. If it's not, then we have a bug somewhere.
333 assert(pm_static_literal_p(node));
334
335 switch (PM_NODE_TYPE(node)) {
336 case PM_ARRAY_NODE: {
337 pm_array_node_t *cast = (pm_array_node_t *) node;
338 pm_node_list_t *elements = &cast->elements;
339
340 VALUE value = rb_ary_hidden_new(elements->size);
341 for (size_t index = 0; index < elements->size; index++) {
342 rb_ary_push(value, pm_static_literal_value(elements->nodes[index], scope_node, parser));
343 }
344
345 OBJ_FREEZE(value);
346 return value;
347 }
348 case PM_FALSE_NODE:
349 return Qfalse;
350 case PM_FLOAT_NODE:
351 return parse_float(node);
352 case PM_HASH_NODE: {
353 pm_hash_node_t *cast = (pm_hash_node_t *) node;
354 pm_node_list_t *elements = &cast->elements;
355
356 VALUE array = rb_ary_hidden_new(elements->size * 2);
357 for (size_t index = 0; index < elements->size; index++) {
358 assert(PM_NODE_TYPE_P(elements->nodes[index], PM_ASSOC_NODE));
359 pm_assoc_node_t *cast = (pm_assoc_node_t *) elements->nodes[index];
360 VALUE pair[2] = { pm_static_literal_value(cast->key, scope_node, parser), pm_static_literal_value(cast->value, scope_node, parser) };
361 rb_ary_cat(array, pair, 2);
362 }
363
364 VALUE value = rb_hash_new_with_size(elements->size);
365 rb_hash_bulk_insert(RARRAY_LEN(array), RARRAY_CONST_PTR(array), value);
366
367 value = rb_obj_hide(value);
368 OBJ_FREEZE(value);
369 return value;
370 }
372 return parse_imaginary((pm_imaginary_node_t *) node);
373 case PM_INTEGER_NODE:
374 return parse_integer((pm_integer_node_t *) node);
375 case PM_NIL_NODE:
376 return Qnil;
377 case PM_RATIONAL_NODE:
378 return parse_rational(node);
381
382 return pm_new_regex(cast, parser);
383 }
385 rb_encoding *encoding = rb_find_encoding(rb_str_new_cstr(scope_node->parser->encoding->name));
386 if (!encoding) rb_bug("Encoding not found!");
387 return rb_enc_from_encoding(encoding);
388 }
389 case PM_SOURCE_FILE_NODE: {
391 return cast->filepath.length ? parse_string(&cast->filepath, parser) : rb_fstring_lit("<compiled>");
392 }
393 case PM_SOURCE_LINE_NODE: {
394 int source_line = (int) pm_newline_list_line_column(&scope_node->parser->newline_list, node->location.start).line;
395 // Ruby treats file lines as 1-indexed
396 // TODO: Incorporate options which allow for passing a line number
397 source_line += 1;
398 return INT2FIX(source_line);
399 }
400 case PM_STRING_NODE:
401 return parse_string(&((pm_string_node_t *) node)->unescaped, parser);
402 case PM_SYMBOL_NODE:
403 return ID2SYM(parse_string_symbol(&((pm_symbol_node_t *) node)->unescaped, parser));
404 case PM_TRUE_NODE:
405 return Qtrue;
406 default:
407 rb_raise(rb_eArgError, "Don't have a literal value for this type");
408 return Qfalse;
409 }
410}
411
431typedef struct {
432 NODE node;
433 int lineno;
435
442static void
443pm_line_node(pm_line_node_t *line_node, const pm_scope_node_t *scope_node, const pm_node_t *node)
444{
445 // First, clear out the pointer.
446 memset(line_node, 0, sizeof(pm_line_node_t));
447
448 // Next, retrieve the line and column information from prism.
449 pm_line_column_t line_column = pm_newline_list_line_column(&scope_node->parser->newline_list, node->location.start);
450
451 // Next, use the line number for the dummy node.
452 int lineno = (int) line_column.line;
453
454 nd_set_line(&line_node->node, lineno);
455 nd_set_node_id(&line_node->node, lineno);
456 line_node->lineno = lineno;
457}
458
459static void
460pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond,
461 LABEL *then_label, LABEL *else_label, const uint8_t *src, bool popped, pm_scope_node_t *scope_node);
462
463static void
464pm_compile_logical(rb_iseq_t *iseq, LINK_ANCHOR *const ret, pm_node_t *cond,
465 LABEL *then_label, LABEL *else_label, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
466{
467 pm_parser_t *parser = scope_node->parser;
468 pm_newline_list_t newline_list = parser->newline_list;
469 int lineno = (int)pm_newline_list_line_column(&newline_list, cond->location.start).line;
470 NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
471
472 DECL_ANCHOR(seq);
473 INIT_ANCHOR(seq);
474 LABEL *label = NEW_LABEL(lineno);
475 if (!then_label) then_label = label;
476 else if (!else_label) else_label = label;
477
478 pm_compile_branch_condition(iseq, seq, cond, then_label, else_label, src, popped, scope_node);
479
480 if (LIST_INSN_SIZE_ONE(seq)) {
481 INSN *insn = (INSN *)ELEM_FIRST_INSN(FIRST_ELEMENT(seq));
482 if (insn->insn_id == BIN(jump) && (LABEL *)(insn->operands[0]) == label)
483 return;
484 }
485 if (!label->refcnt) {
486 PM_PUTNIL;
487 }
488 else {
489 ADD_LABEL(seq, label);
490 }
491 ADD_SEQ(ret, seq);
492 return;
493}
494
495static void pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node);
496
497static void
498pm_compile_flip_flop(pm_flip_flop_node_t *flip_flop_node, LABEL *else_label, LABEL *then_label, rb_iseq_t *iseq, const int lineno, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
499{
500 NODE dummy_line_node = generate_dummy_line_node(ISEQ_BODY(iseq)->location.first_lineno, -1);
501 LABEL *lend = NEW_LABEL(lineno);
502
503 int again = !(flip_flop_node->base.flags & PM_RANGE_FLAGS_EXCLUDE_END);
504
505 rb_num_t count = ISEQ_FLIP_CNT_INCREMENT(ISEQ_BODY(iseq)->local_iseq) + VM_SVAR_FLIPFLOP_START;
506 VALUE key = INT2FIX(count);
507
508 ADD_INSN2(ret, &dummy_line_node, getspecial, key, INT2FIX(0));
509 ADD_INSNL(ret, &dummy_line_node, branchif, lend);
510
511 if (flip_flop_node->left) {
512 PM_COMPILE(flip_flop_node->left);
513 }
514 else {
515 PM_PUTNIL;
516 }
517
518 ADD_INSNL(ret, &dummy_line_node, branchunless, else_label);
519 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
520 ADD_INSN1(ret, &dummy_line_node, setspecial, key);
521 if (!again) {
522 ADD_INSNL(ret, &dummy_line_node, jump, then_label);
523 }
524
525 ADD_LABEL(ret, lend);
526 if (flip_flop_node->right) {
527 PM_COMPILE(flip_flop_node->right);
528 }
529 else {
530 PM_PUTNIL;
531 }
532
533 ADD_INSNL(ret, &dummy_line_node, branchunless, then_label);
534 ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
535 ADD_INSN1(ret, &dummy_line_node, setspecial, key);
536 ADD_INSNL(ret, &dummy_line_node, jump, then_label);
537}
538
539void pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *defined_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, int lineno, bool in_condition);
540static void
541pm_compile_branch_condition(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const pm_node_t *cond,
542 LABEL *then_label, LABEL *else_label, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
543{
544 pm_parser_t *parser = scope_node->parser;
545 pm_newline_list_t newline_list = parser->newline_list;
546 int lineno = (int) pm_newline_list_line_column(&newline_list, cond->location.start).line;
547 NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
548
549again:
550 switch (PM_NODE_TYPE(cond)) {
551 case PM_AND_NODE: {
552 pm_and_node_t *and_node = (pm_and_node_t *)cond;
553 pm_compile_logical(iseq, ret, and_node->left, NULL, else_label, src, popped, scope_node);
554 cond = and_node->right;
555 goto again;
556 }
557 case PM_OR_NODE: {
558 pm_or_node_t *or_node = (pm_or_node_t *)cond;
559 pm_compile_logical(iseq, ret, or_node->left, then_label, NULL, src, popped, scope_node);
560 cond = or_node->right;
561 goto again;
562 }
563 case PM_FALSE_NODE:
564 case PM_NIL_NODE:
565 ADD_INSNL(ret, &dummy_line_node, jump, else_label);
566 return;
567 case PM_FLOAT_NODE:
569 case PM_INTEGER_NODE:
570 case PM_LAMBDA_NODE:
571 case PM_RATIONAL_NODE:
573 case PM_STRING_NODE:
574 case PM_SYMBOL_NODE:
575 case PM_TRUE_NODE:
576 ADD_INSNL(ret, &dummy_line_node, jump, then_label);
577 return;
579 pm_compile_flip_flop((pm_flip_flop_node_t *)cond, else_label, then_label, iseq, lineno, ret, src, popped, scope_node);
580 return;
581 // TODO: Several more nodes in this case statement
582 case PM_DEFINED_NODE: {
583 pm_defined_node_t *defined_node = (pm_defined_node_t *)cond;
584 pm_compile_defined_expr(iseq, defined_node->value, ret, src, popped, scope_node, dummy_line_node, lineno, true);
585 break;
586 }
587 default: {
588 DECL_ANCHOR(cond_seq);
589 INIT_ANCHOR(cond_seq);
590
591 pm_compile_node(iseq, cond, cond_seq, src, false, scope_node);
592 ADD_SEQ(ret, cond_seq);
593 break;
594 }
595 }
596 ADD_INSNL(ret, &dummy_line_node, branchunless, else_label);
597 ADD_INSNL(ret, &dummy_line_node, jump, then_label);
598 return;
599}
600
601static void
602pm_compile_if(rb_iseq_t *iseq, const int line, pm_statements_node_t *node_body, pm_node_t *node_else, pm_node_t *predicate, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
603{
604 NODE dummy_line_node = generate_dummy_line_node(line, line);
605
606 DECL_ANCHOR(cond_seq);
607
608 LABEL *then_label, *else_label, *end_label;
609
610 INIT_ANCHOR(cond_seq);
611 then_label = NEW_LABEL(line);
612 else_label = NEW_LABEL(line);
613 end_label = 0;
614
615 pm_compile_branch_condition(iseq, cond_seq, predicate, then_label, else_label, src, false, scope_node);
616 ADD_SEQ(ret, cond_seq);
617
618 if (then_label->refcnt) {
619 ADD_LABEL(ret, then_label);
620
621 DECL_ANCHOR(then_seq);
622 INIT_ANCHOR(then_seq);
623 if (node_body) {
624 pm_compile_node(iseq, (pm_node_t *)node_body, then_seq, src, popped, scope_node);
625 } else {
626 PM_PUTNIL_UNLESS_POPPED;
627 }
628
629 if (else_label->refcnt) {
630 end_label = NEW_LABEL(line);
631 ADD_INSNL(then_seq, &dummy_line_node, jump, end_label);
632 if (!popped) {
633 ADD_INSN(then_seq, &dummy_line_node, pop);
634 }
635 }
636 ADD_SEQ(ret, then_seq);
637 }
638
639 if (else_label->refcnt) {
640 ADD_LABEL(ret, else_label);
641
642 DECL_ANCHOR(else_seq);
643 INIT_ANCHOR(else_seq);
644 if (node_else) {
645 pm_compile_node(iseq, (pm_node_t *)node_else, else_seq, src, popped, scope_node);
646 }
647 else {
648 PM_PUTNIL_UNLESS_POPPED;
649 }
650
651 ADD_SEQ(ret, else_seq);
652 }
653
654 if (end_label) {
655 ADD_LABEL(ret, end_label);
656 }
657
658 return;
659}
660
661static void
662pm_compile_while(rb_iseq_t *iseq, int lineno, pm_node_flags_t flags, enum pm_node_type type, pm_statements_node_t *statements, pm_node_t *predicate, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
663{
664 NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
665
666 LABEL *prev_start_label = ISEQ_COMPILE_DATA(iseq)->start_label;
667 LABEL *prev_end_label = ISEQ_COMPILE_DATA(iseq)->end_label;
668 LABEL *prev_redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label;
669
670 // TODO: Deal with ensures in here
671 LABEL *next_label = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(lineno); /* next */
672 LABEL *redo_label = ISEQ_COMPILE_DATA(iseq)->redo_label = NEW_LABEL(lineno); /* redo */
673 LABEL *break_label = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(lineno); /* break */
674 LABEL *end_label = NEW_LABEL(lineno);
675 LABEL *adjust_label = NEW_LABEL(lineno);
676
677 LABEL *next_catch_label = NEW_LABEL(lineno);
678 LABEL *tmp_label = NULL;
679
680 // begin; end while true
681 if (flags & PM_LOOP_FLAGS_BEGIN_MODIFIER) {
682 tmp_label = NEW_LABEL(lineno);
683 ADD_INSNL(ret, &dummy_line_node, jump, tmp_label);
684 }
685 else {
686 // while true; end
687 ADD_INSNL(ret, &dummy_line_node, jump, next_label);
688 }
689
690 ADD_LABEL(ret, adjust_label);
691 PM_PUTNIL;
692 ADD_LABEL(ret, next_catch_label);
693 PM_POP;
694 ADD_INSNL(ret, &dummy_line_node, jump, next_label);
695 if (tmp_label) ADD_LABEL(ret, tmp_label);
696
697 ADD_LABEL(ret, redo_label);
698 if (statements) {
699 PM_COMPILE_POPPED((pm_node_t *)statements);
700 }
701
702 ADD_LABEL(ret, next_label);
703
704 if (type == PM_WHILE_NODE) {
705 pm_compile_branch_condition(iseq, ret, predicate, redo_label, end_label, src, popped, scope_node);
706 } else if (type == PM_UNTIL_NODE) {
707 pm_compile_branch_condition(iseq, ret, predicate, end_label, redo_label, src, popped, scope_node);
708 }
709
710 ADD_LABEL(ret, end_label);
711 ADD_ADJUST_RESTORE(ret, adjust_label);
712
713 PM_PUTNIL;
714
715 ADD_LABEL(ret, break_label);
716
717 PM_POP_IF_POPPED;
718
719 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, redo_label, break_label, NULL,
720 break_label);
721 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, redo_label, break_label, NULL,
722 next_catch_label);
723 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, redo_label, break_label, NULL,
724 ISEQ_COMPILE_DATA(iseq)->redo_label);
725
726 ISEQ_COMPILE_DATA(iseq)->start_label = prev_start_label;
727 ISEQ_COMPILE_DATA(iseq)->end_label = prev_end_label;
728 ISEQ_COMPILE_DATA(iseq)->redo_label = prev_redo_label;
729 return;
730}
731
732static void
733pm_interpolated_node_compile(pm_node_list_t *parts, rb_iseq_t *iseq, NODE dummy_line_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, pm_parser_t *parser)
734{
735 size_t parts_size = parts->size;
736
737 if (parts_size > 0) {
738 for (size_t index = 0; index < parts_size; index++) {
739 pm_node_t *part = parts->nodes[index];
740
741 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
742 pm_string_node_t *string_node = (pm_string_node_t *) part;
743 ADD_INSN1(ret, &dummy_line_node, putobject, parse_string(&string_node->unescaped, parser));
744 }
745 else {
746 PM_COMPILE_NOT_POPPED(part);
747 PM_DUP;
748 ADD_INSN1(ret, &dummy_line_node, objtostring, new_callinfo(iseq, idTo_s, 0, VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE , NULL, FALSE));
749 ADD_INSN(ret, &dummy_line_node, anytostring);
750 }
751 }
752 }
753 else {
754 PM_PUTNIL;
755 }
756}
757
758// This recurses through scopes and finds the local index at any scope level
759// It also takes a pointer to depth, and increments depth appropriately
760// according to the depth of the local
761static int
762pm_lookup_local_index_any_scope(rb_iseq_t *iseq, pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
763{
764 if (!scope_node) {
765 // We have recursed up all scope nodes
766 // and have not found the local yet
767 rb_bug("This local does not exist");
768 }
769
770 st_data_t local_index;
771
772 if (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) {
773 // Local does not exist at this level, continue recursing up
774 return pm_lookup_local_index_any_scope(iseq, scope_node->previous, constant_id);
775 }
776
777 return scope_node->local_table_for_iseq_size - (int)local_index;
778}
779
780static int
781pm_lookup_local_index(rb_iseq_t *iseq, pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
782{
783 st_data_t local_index;
784
785 if (!st_lookup(scope_node->index_lookup_table, constant_id, &local_index)) {
786 rb_bug("This local does not exist");
787 }
788
789 return scope_node->local_table_for_iseq_size - (int)local_index;
790}
791
792static int
793pm_lookup_local_index_with_depth(rb_iseq_t *iseq, pm_scope_node_t *scope_node, pm_constant_id_t constant_id, uint32_t depth)
794{
795 for(uint32_t i = 0; i < depth; i++) {
796 scope_node = scope_node->previous;
797 iseq = (rb_iseq_t *)ISEQ_BODY(iseq)->parent_iseq;
798 }
799
800 return pm_lookup_local_index_any_scope(iseq, scope_node, constant_id);
801}
802
803// This returns the CRuby ID which maps to the pm_constant_id_t
804//
805// Constant_ids in prism are indexes of the constants in prism's constant pool.
806// We add a constants mapping on the scope_node which is a mapping from
807// these constant_id indexes to the CRuby IDs that they represent.
808// This helper method allows easy access to those IDs
809static ID
810pm_constant_id_lookup(pm_scope_node_t *scope_node, pm_constant_id_t constant_id)
811{
812 if (constant_id < 1 || constant_id > scope_node->parser->constant_pool.size) {
813 rb_bug("[PRISM] constant_id out of range: %u", (unsigned int)constant_id);
814 }
815 return scope_node->constants[constant_id - 1];
816}
817
818static rb_iseq_t *
819pm_new_child_iseq(rb_iseq_t *iseq, pm_scope_node_t node, pm_parser_t *parser,
820 VALUE name, const rb_iseq_t *parent, enum rb_iseq_type type, int line_no)
821{
822 debugs("[new_child_iseq]> ---------------------------------------\n");
823 int isolated_depth = ISEQ_COMPILE_DATA(iseq)->isolated_depth;
824 rb_iseq_t * ret_iseq = pm_iseq_new_with_opt(&node, parser, name,
825 rb_iseq_path(iseq), rb_iseq_realpath(iseq),
826 line_no, parent,
827 isolated_depth ? isolated_depth + 1 : 0,
828 type, ISEQ_COMPILE_DATA(iseq)->option);
829 debugs("[new_child_iseq]< ---------------------------------------\n");
830 return ret_iseq;
831}
832
833static int
834pm_compile_class_path(LINK_ANCHOR *const ret, rb_iseq_t *iseq, const pm_node_t *constant_path_node, const NODE *line_node, const uint8_t * src, bool popped, pm_scope_node_t *scope_node)
835{
836 if (PM_NODE_TYPE_P(constant_path_node, PM_CONSTANT_PATH_NODE)) {
837 pm_node_t *parent = ((pm_constant_path_node_t *)constant_path_node)->parent;
838 if (parent) {
839 /* Bar::Foo */
840 PM_COMPILE(parent);
841 return VM_DEFINECLASS_FLAG_SCOPED;
842 }
843 else {
844 /* toplevel class ::Foo */
845 ADD_INSN1(ret, line_node, putobject, rb_cObject);
846 return VM_DEFINECLASS_FLAG_SCOPED;
847 }
848 }
849 else {
850 /* class at cbase Foo */
851 ADD_INSN1(ret, line_node, putspecialobject,
852 INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
853 return 0;
854 }
855}
856
857static void
858pm_compile_call_and_or_write_node(bool and_node, pm_node_t *receiver, pm_node_t *value, pm_constant_id_t write_name, pm_constant_id_t read_name, bool safe_nav, LINK_ANCHOR *const ret, rb_iseq_t *iseq, int lineno, const uint8_t * src, bool popped, pm_scope_node_t *scope_node)
859{
860 LABEL *call_end_label = NEW_LABEL(lineno);
861 LABEL *else_label = NEW_LABEL(lineno);
862 LABEL *end_label = NEW_LABEL(lineno);
863 NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
864
865 int flag = 0;
866
867 if (PM_NODE_TYPE_P(receiver, PM_SELF_NODE)) {
868 flag = VM_CALL_FCALL;
869 }
870
871 PM_COMPILE_NOT_POPPED(receiver);
872
873 if (safe_nav) {
874 PM_DUP;
875 ADD_INSNL(ret, &dummy_line_node, branchnil, else_label);
876 }
877
878 ID write_name_id = pm_constant_id_lookup(scope_node, write_name);
879 ID read_name_id = pm_constant_id_lookup(scope_node, read_name);
880 PM_DUP;
881
882 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, read_name_id, INT2FIX(0), INT2FIX(flag));
883
884 PM_DUP_UNLESS_POPPED;
885
886 if (and_node) {
887 ADD_INSNL(ret, &dummy_line_node, branchunless, call_end_label);
888 }
889 else {
890 // or_node
891 ADD_INSNL(ret, &dummy_line_node, branchif, call_end_label);
892 }
893
894 PM_POP_UNLESS_POPPED;
895
896 PM_COMPILE_NOT_POPPED(value);
897 if (!popped) {
898 PM_SWAP;
899 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
900 }
901 ID aid = rb_id_attrset(write_name_id);
902 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, aid, INT2FIX(1), INT2FIX(flag));
903 ADD_INSNL(ret, &dummy_line_node, jump, end_label);
904 ADD_LABEL(ret, call_end_label);
905
906 if (!popped) {
907 PM_SWAP;
908 }
909
910 if (safe_nav) {
911 ADD_LABEL(ret, else_label);
912 }
913
914 ADD_LABEL(ret, end_label);
915 PM_POP;
916 return;
917}
918
919static void
920pm_compile_index_write_nodes_add_send(bool popped, LINK_ANCHOR *const ret, rb_iseq_t *iseq, NODE dummy_line_node, VALUE argc, int flag, int block_offset)
921{
922 if (!popped) {
923 ADD_INSN1(ret, &dummy_line_node, setn, FIXNUM_INC(argc, 2 + block_offset));
924 }
925
926 if (flag & VM_CALL_ARGS_SPLAT) {
927 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(1));
928 if (block_offset > 0) {
929 ADD_INSN1(ret, &dummy_line_node, dupn, INT2FIX(3));
930 PM_SWAP;
931 PM_POP;
932 }
933 ADD_INSN(ret, &dummy_line_node, concatarray);
934 if (block_offset > 0) {
935 ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(3));
936 PM_POP;
937 }
938 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idASET, argc, INT2FIX(flag));
939 }
940 else {
941 if (block_offset > 0) {
942 PM_SWAP;
943 }
944 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
945 }
946
947 PM_POP;
948 return;
949}
950
951static int
952pm_setup_args(pm_arguments_node_t *arguments_node, int *flags, struct rb_callinfo_kwarg **kw_arg, rb_iseq_t *iseq, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, pm_parser_t *parser)
953{
954 int orig_argc = 0;
955 if (arguments_node == NULL) {
956 if (*flags & VM_CALL_FCALL) {
957 *flags |= VM_CALL_VCALL;
958 }
959 }
960 else {
961 pm_node_list_t arguments_node_list = arguments_node->arguments;
962
963 bool has_keyword_splat = (arguments_node->base.flags & PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT);
964 bool has_splat = false;
965
966 // We count the number of elements post the splat node that are not keyword elements to
967 // eventually pass as an argument to newarray
968 int post_splat_counter = 0;
969
970 for (size_t index = 0; index < arguments_node_list.size; index++) {
971 pm_node_t *argument = arguments_node_list.nodes[index];
972
973 switch (PM_NODE_TYPE(argument)) {
974 // A keyword hash node contains all keyword arguments as AssocNodes and AssocSplatNodes
976 pm_keyword_hash_node_t *keyword_arg = (pm_keyword_hash_node_t *)argument;
977 size_t len = keyword_arg->elements.size;
978
979 if (has_keyword_splat) {
980 int cur_hash_size = 0;
981 orig_argc++;
982
983 bool new_hash_emitted = false;
984 for (size_t i = 0; i < len; i++) {
985 pm_node_t *cur_node = keyword_arg->elements.nodes[i];
986
987 pm_node_type_t cur_type = PM_NODE_TYPE(cur_node);
988
989 switch (PM_NODE_TYPE(cur_node)) {
990 case PM_ASSOC_NODE: {
991 pm_assoc_node_t *assoc = (pm_assoc_node_t *)cur_node;
992
993 PM_COMPILE_NOT_POPPED(assoc->key);
994 PM_COMPILE_NOT_POPPED(assoc->value);
995 cur_hash_size++;
996
997 // If we're at the last keyword arg, or the last assoc node of this "set",
998 // then we want to either construct a newhash or merge onto previous hashes
999 if (i == (len - 1) || !PM_NODE_TYPE_P(keyword_arg->elements.nodes[i + 1], cur_type)) {
1000 if (new_hash_emitted) {
1001 ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(cur_hash_size * 2 + 1));
1002 }
1003 else {
1004 ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(cur_hash_size * 2));
1005 cur_hash_size = 0;
1006 new_hash_emitted = true;
1007 }
1008 }
1009
1010 break;
1011 }
1012 case PM_ASSOC_SPLAT_NODE: {
1013 if (len > 1) {
1014 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1015 if (i == 0) {
1016 ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(0));
1017 new_hash_emitted = true;
1018 }
1019 else {
1020 PM_SWAP;
1021 }
1022
1023 *flags |= VM_CALL_KW_SPLAT_MUT;
1024 }
1025
1026 pm_assoc_splat_node_t *assoc_splat = (pm_assoc_splat_node_t *)cur_node;
1027 PM_COMPILE_NOT_POPPED(assoc_splat->value);
1028
1029 *flags |= VM_CALL_KW_SPLAT;
1030
1031 if (len > 1) {
1032 ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_kwd, INT2FIX(2));
1033 }
1034
1035 if ((i < len - 1) && !PM_NODE_TYPE_P(keyword_arg->elements.nodes[i + 1], cur_type)) {
1036 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1037 PM_SWAP;
1038 }
1039
1040 cur_hash_size = 0;
1041 break;
1042 }
1043 default: {
1044 rb_bug("Unknown type");
1045 }
1046 }
1047 }
1048 break;
1049 }
1050 else {
1051 // We need to first figure out if all elements of the KeywordHashNode are AssocNodes
1052 // with symbol keys.
1054 // If they are all symbol keys then we can pass them as keyword arguments.
1055 *kw_arg = rb_xmalloc_mul_add(len, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
1056 *flags |= VM_CALL_KWARG;
1057 VALUE *keywords = (*kw_arg)->keywords;
1058 (*kw_arg)->references = 0;
1059 (*kw_arg)->keyword_len = (int)len;
1060
1061 for (size_t i = 0; i < len; i++) {
1062 pm_assoc_node_t *assoc = (pm_assoc_node_t *)keyword_arg->elements.nodes[i];
1063 pm_node_t *key = assoc->key;
1064 keywords[i] = pm_static_literal_value(key, scope_node, parser);
1065 PM_COMPILE_NOT_POPPED(assoc->value);
1066 }
1067 } else {
1068 // If they aren't all symbol keys then we need to construct a new hash
1069 // and pass that as an argument.
1070 orig_argc++;
1071 *flags |= VM_CALL_KW_SPLAT;
1072 if (len > 1) {
1073 // A new hash will be created for the keyword arguments in this case,
1074 // so mark the method as passing mutable keyword splat.
1075 *flags |= VM_CALL_KW_SPLAT_MUT;
1076 }
1077
1078 for (size_t i = 0; i < len; i++) {
1079 pm_assoc_node_t *assoc = (pm_assoc_node_t *)keyword_arg->elements.nodes[i];
1080 PM_COMPILE_NOT_POPPED(assoc->key);
1081 PM_COMPILE_NOT_POPPED(assoc->value);
1082 }
1083
1084 ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(len * 2));
1085 }
1086 }
1087 break;
1088 }
1089 case PM_SPLAT_NODE: {
1090 *flags |= VM_CALL_ARGS_SPLAT;
1091 pm_splat_node_t *splat_node = (pm_splat_node_t *)argument;
1092 if (splat_node->expression) {
1093 orig_argc++;
1094 PM_COMPILE_NOT_POPPED(splat_node->expression);
1095 }
1096
1097 ADD_INSN1(ret, &dummy_line_node, splatarray, Qfalse);
1098
1099 has_splat = true;
1100 post_splat_counter = 0;
1101
1102 break;
1103 }
1105 orig_argc++;
1106 *flags |= VM_CALL_ARGS_BLOCKARG | VM_CALL_ARGS_SPLAT;
1107 ADD_GETLOCAL(ret, &dummy_line_node, 3, 0);
1108 ADD_INSN1(ret, &dummy_line_node, splatarray, RBOOL(arguments_node_list.size > 1));
1109 ADD_INSN2(ret, &dummy_line_node, getblockparamproxy, INT2FIX(4), INT2FIX(0));
1110 break;
1111 }
1112 default: {
1113 orig_argc++;
1114 post_splat_counter++;
1115 PM_COMPILE_NOT_POPPED(argument);
1116
1117 if (has_splat) {
1118 // If the next node starts the keyword section of parameters
1119 if ((index < arguments_node_list.size - 1) && PM_NODE_TYPE_P(arguments_node_list.nodes[index + 1], PM_KEYWORD_HASH_NODE)) {
1120
1121 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(post_splat_counter));
1122 ADD_INSN1(ret, &dummy_line_node, splatarray, Qfalse);
1123 ADD_INSN(ret, &dummy_line_node, concatarray);
1124 }
1125 // If it's the final node
1126 else if (index == arguments_node_list.size - 1) {
1127 if (post_splat_counter > 1) {
1128 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(post_splat_counter));
1129 ADD_INSN1(ret, &dummy_line_node, splatarray, Qfalse);
1130 ADD_INSN(ret, &dummy_line_node, concatarray);
1131 }
1132 else {
1133 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(post_splat_counter));
1134 ADD_INSN(ret, &dummy_line_node, concatarray);
1135 }
1136 orig_argc = 1;
1137 }
1138 }
1139 }
1140 }
1141 }
1142 }
1143 return orig_argc;
1144}
1145
1146static void
1147pm_compile_index_and_or_write_node(bool and_node, pm_node_t *receiver, pm_node_t *value, pm_arguments_node_t *arguments, pm_node_t *block, LINK_ANCHOR *const ret, rb_iseq_t *iseq, int lineno, const uint8_t * src, bool popped, pm_scope_node_t *scope_node, pm_parser_t *parser)
1148{
1149 NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
1150 PM_PUTNIL_UNLESS_POPPED;
1151
1152 PM_COMPILE_NOT_POPPED(receiver);
1153
1154 int flag = 0;
1155 int argc_int = 0;
1156
1157 if (arguments) {
1158 // Get any arguments, and set the appropriate values for flag
1159 argc_int = pm_setup_args(arguments, &flag, NULL, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
1160 }
1161
1162 VALUE argc = INT2FIX(argc_int);
1163 int block_offset = 0;
1164
1165 if (block) {
1166 PM_COMPILE_NOT_POPPED(block);
1167 flag |= VM_CALL_ARGS_BLOCKARG;
1168 block_offset = 1;
1169 }
1170
1171 ADD_INSN1(ret, &dummy_line_node, dupn, FIXNUM_INC(argc, 1 + block_offset));
1172
1173 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idAREF, argc, INT2FIX(flag));
1174
1175 LABEL *label = NEW_LABEL(lineno);
1176 LABEL *lfin = NEW_LABEL(lineno);
1177
1178 PM_DUP;
1179
1180 if (and_node) {
1181 ADD_INSNL(ret, &dummy_line_node, branchunless, label);
1182 }
1183 else {
1184 // ornode
1185 ADD_INSNL(ret, &dummy_line_node, branchif, label);
1186 }
1187
1188 PM_POP;
1189
1190 PM_COMPILE_NOT_POPPED(value);
1191
1192 pm_compile_index_write_nodes_add_send(popped, ret, iseq, dummy_line_node, argc, flag, block_offset);
1193
1194 ADD_INSNL(ret, &dummy_line_node, jump, lfin);
1195 ADD_LABEL(ret, label);
1196 if (!popped) {
1197 ADD_INSN1(ret, &dummy_line_node, setn, FIXNUM_INC(argc, 2 + block_offset));
1198 }
1199 ADD_INSN1(ret, &dummy_line_node, adjuststack, FIXNUM_INC(argc, 2 + block_offset));
1200 ADD_LABEL(ret, lfin);
1201
1202 return;
1203}
1204
1212static uint8_t
1213pm_compile_multi_write_lhs(rb_iseq_t *iseq, NODE dummy_line_node, const uint8_t *src, bool popped, const pm_node_t *node, LINK_ANCHOR *const ret, pm_scope_node_t *scope_node, uint8_t pushed, bool nested)
1214{
1215 switch (PM_NODE_TYPE(node)) {
1216 case PM_INDEX_TARGET_NODE: {
1218 PM_COMPILE_NOT_POPPED((pm_node_t *)cast->receiver);
1219 pushed++;
1220
1221 if (cast->arguments) {
1222 for (size_t i = 0; i < cast->arguments->arguments.size; i++) {
1223 PM_COMPILE_NOT_POPPED((pm_node_t *)cast->arguments->arguments.nodes[i]);
1224 }
1225 pushed += cast->arguments->arguments.size;
1226 }
1227 break;
1228 }
1229 case PM_CALL_TARGET_NODE: {
1231 PM_COMPILE_NOT_POPPED((pm_node_t *)cast->receiver);
1232 pushed++;
1233 break;
1234 }
1235 case PM_MULTI_TARGET_NODE: {
1237 for (size_t index = 0; index < cast->lefts.size; index++) {
1238 pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, cast->lefts.nodes[index], ret, scope_node, pushed, false);
1239 }
1240 break;
1241 }
1244 if (cast->parent) {
1245 PM_PUTNIL;
1246 pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, cast->parent, ret, scope_node, pushed, false);
1247 } else {
1248 ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
1249 }
1250 break;
1251 }
1252 case PM_CONSTANT_PATH_NODE: {
1254 if (cast->parent) {
1255 pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, cast->parent, ret, scope_node, pushed, false);
1256 } else {
1257 PM_POP;
1258 ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
1259 }
1260 pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, cast->child, ret, scope_node, pushed, cast->parent);
1261 break;
1262 }
1263 case PM_CONSTANT_READ_NODE: {
1265 ADD_INSN1(ret, &dummy_line_node, putobject, RBOOL(!nested));
1266 ADD_INSN1(ret, &dummy_line_node, getconstant, ID2SYM(pm_constant_id_lookup(scope_node, cast->name)));
1267 pushed = pushed + 2;
1268 break;
1269 }
1270 default:
1271 break;
1272 }
1273
1274 return pushed;
1275}
1276
1277// When we compile a pattern matching expression, we use the stack as a scratch
1278// space to store lots of different values (consider it like we have a pattern
1279// matching function and we need space for a bunch of different local
1280// variables). The "base index" refers to the index on the stack where we
1281// started compiling the pattern matching expression. These offsets from that
1282// base index indicate the location of the various locals we need.
1283#define PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE 0
1284#define PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING 1
1285#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P 2
1286#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE 3
1287#define PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY 4
1288
1289// A forward declaration because this is the recursive function that handles
1290// compiling a pattern. It can be reentered by nesting patterns, as in the case
1291// of arrays or hashes.
1292static int pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index);
1293
1298static int
1299pm_compile_pattern_generic_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, unsigned int base_index)
1300{
1301 pm_line_node_t line;
1302 pm_line_node(&line, scope_node, node);
1303
1304 LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
1305
1306 ADD_INSN(ret, &line.node, dup);
1307 ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
1308
1309 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1310 ADD_INSN1(ret, &line.node, putobject, message);
1311 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1312 ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(2));
1313 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
1314
1315 ADD_INSN1(ret, &line.node, putobject, Qfalse);
1316 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
1317
1318 ADD_INSN(ret, &line.node, pop);
1319 ADD_INSN(ret, &line.node, pop);
1320 ADD_LABEL(ret, match_succeeded_label);
1321
1322 return COMPILE_OK;
1323}
1324
1330static int
1331pm_compile_pattern_length_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, VALUE message, VALUE length, unsigned int base_index)
1332{
1333 pm_line_node_t line;
1334 pm_line_node(&line, scope_node, node);
1335
1336 LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
1337
1338 ADD_INSN(ret, &line.node, dup);
1339 ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
1340
1341 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1342 ADD_INSN1(ret, &line.node, putobject, message);
1343 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1344 ADD_INSN(ret, &line.node, dup);
1345 ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
1346 ADD_INSN1(ret, &line.node, putobject, length);
1347 ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(4));
1348 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
1349
1350 ADD_INSN1(ret, &line.node, putobject, Qfalse);
1351 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
1352
1353 ADD_INSN(ret, &line.node, pop);
1354 ADD_INSN(ret, &line.node, pop);
1355 ADD_LABEL(ret, match_succeeded_label);
1356
1357 return COMPILE_OK;
1358}
1359
1365static int
1366pm_compile_pattern_eqq_error(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, unsigned int base_index)
1367{
1368 pm_line_node_t line;
1369 pm_line_node(&line, scope_node, node);
1370
1371 LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
1372
1373 ADD_INSN(ret, &line.node, dup);
1374 ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
1375
1376 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1377 ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("%p === %p does not return true"));
1378 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1379 ADD_INSN1(ret, &line.node, topn, INT2FIX(5));
1380 ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(3));
1381 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
1382 ADD_INSN1(ret, &line.node, putobject, Qfalse);
1383 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
1384 ADD_INSN(ret, &line.node, pop);
1385 ADD_INSN(ret, &line.node, pop);
1386
1387 ADD_LABEL(ret, match_succeeded_label);
1388 ADD_INSN1(ret, &line.node, setn, INT2FIX(2));
1389 ADD_INSN(ret, &line.node, pop);
1390 ADD_INSN(ret, &line.node, pop);
1391
1392 return COMPILE_OK;
1393}
1394
1401static int
1402pm_compile_pattern_match(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
1403{
1404 LABEL *matched_label = NEW_LABEL(nd_line(node));
1405 CHECK(pm_compile_pattern(iseq, scope_node, node, ret, src, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
1406 ADD_LABEL(ret, matched_label);
1407 return COMPILE_OK;
1408}
1409
1415static int
1416pm_compile_pattern_deconstruct(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *deconstruct_label, LABEL *match_failed_label, LABEL *deconstructed_label, LABEL *type_error_label, bool in_single_pattern, bool use_deconstructed_cache, unsigned int base_index)
1417{
1418 pm_line_node_t line;
1419 pm_line_node(&line, scope_node, node);
1420
1421 if (use_deconstructed_cache) {
1422 ADD_INSN1(ret, &line.node, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
1423 ADD_INSNL(ret, &line.node, branchnil, deconstruct_label);
1424
1425 ADD_INSN1(ret, &line.node, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
1426 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1427
1428 ADD_INSN(ret, &line.node, pop);
1429 ADD_INSN1(ret, &line.node, topn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE - 1));
1430 ADD_INSNL(ret, &line.node, jump, deconstructed_label);
1431 } else {
1432 ADD_INSNL(ret, &line.node, jump, deconstruct_label);
1433 }
1434
1435 ADD_LABEL(ret, deconstruct_label);
1436 ADD_INSN(ret, &line.node, dup);
1437 ADD_INSN1(ret, &line.node, putobject, ID2SYM(rb_intern("deconstruct")));
1438 ADD_SEND(ret, &line.node, idRespond_to, INT2FIX(1));
1439
1440 if (use_deconstructed_cache) {
1441 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE + 1));
1442 }
1443
1444 if (in_single_pattern) {
1445 CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1));
1446 }
1447
1448 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1449 ADD_SEND(ret, &line.node, rb_intern("deconstruct"), INT2FIX(0));
1450
1451 if (use_deconstructed_cache) {
1452 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE));
1453 }
1454
1455 ADD_INSN(ret, &line.node, dup);
1456 ADD_INSN1(ret, &line.node, checktype, INT2FIX(T_ARRAY));
1457 ADD_INSNL(ret, &line.node, branchunless, type_error_label);
1458 ADD_LABEL(ret, deconstructed_label);
1459
1460 return COMPILE_OK;
1461}
1462
1467static int
1468pm_compile_pattern_constant(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *match_failed_label, bool in_single_pattern, unsigned int base_index)
1469{
1470 pm_line_node_t line;
1471 pm_line_node(&line, scope_node, node);
1472
1473 ADD_INSN(ret, &line.node, dup);
1474 PM_COMPILE_NOT_POPPED(node);
1475
1476 if (in_single_pattern) {
1477 ADD_INSN1(ret, &line.node, dupn, INT2FIX(2));
1478 }
1479 ADD_INSN1(ret, &line.node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
1480 if (in_single_pattern) {
1481 CHECK(pm_compile_pattern_eqq_error(iseq, scope_node, node, ret, base_index + 3));
1482 }
1483 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1484 return COMPILE_OK;
1485}
1486
1491static void
1492pm_compile_pattern_error_handler(rb_iseq_t *iseq, const pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *done_label, bool popped)
1493{
1494 pm_line_node_t line;
1495 pm_line_node(&line, scope_node, node);
1496
1497 LABEL *key_error_label = NEW_LABEL(line.lineno);
1498 LABEL *cleanup_label = NEW_LABEL(line.lineno);
1499
1500 struct rb_callinfo_kwarg *kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
1501 kw_arg->references = 0;
1502 kw_arg->keyword_len = 2;
1503 kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
1504 kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
1505
1506 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1507 ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
1508 ADD_INSNL(ret, &line.node, branchif, key_error_label);
1509
1510 ADD_INSN1(ret, &line.node, putobject, rb_eNoMatchingPatternError);
1511 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1512 ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("%p: %s"));
1513 ADD_INSN1(ret, &line.node, topn, INT2FIX(4));
1514 ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 6));
1515 ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(3));
1516 ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(2));
1517 ADD_INSNL(ret, &line.node, jump, cleanup_label);
1518
1519 ADD_LABEL(ret, key_error_label);
1520 ADD_INSN1(ret, &line.node, putobject, rb_eNoMatchingPatternKeyError);
1521 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1522 ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("%p: %s"));
1523 ADD_INSN1(ret, &line.node, topn, INT2FIX(4));
1524 ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 6));
1525 ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(3));
1526 ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE + 4));
1527 ADD_INSN1(ret, &line.node, topn, INT2FIX(PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY + 5));
1528 ADD_SEND_R(ret, &line.node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
1529 ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(1));
1530 ADD_LABEL(ret, cleanup_label);
1531
1532 ADD_INSN1(ret, &line.node, adjuststack, INT2FIX(7));
1533 if (!popped) ADD_INSN(ret, &line.node, putnil);
1534 ADD_INSNL(ret, &line.node, jump, done_label);
1535 ADD_INSN1(ret, &line.node, dupn, INT2FIX(5));
1536 if (popped) ADD_INSN(ret, &line.node, putnil);
1537}
1538
1542static int
1543pm_compile_pattern(rb_iseq_t *iseq, pm_scope_node_t *scope_node, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, LABEL *matched_label, LABEL *unmatched_label, bool in_single_pattern, bool in_alternation_pattern, bool use_deconstructed_cache, unsigned int base_index)
1544{
1545 pm_line_node_t line;
1546 pm_line_node(&line, scope_node, node);
1547
1548 switch (PM_NODE_TYPE(node)) {
1549 case PM_ARRAY_PATTERN_NODE: {
1550 // Array patterns in pattern matching are triggered by using commas in
1551 // a pattern or wrapping it in braces. They are represented by a
1552 // ArrayPatternNode. This looks like:
1553 //
1554 // foo => [1, 2, 3]
1555 //
1556 // It can optionally have a splat in the middle of it, which can
1557 // optionally have a name attached.
1558 const pm_array_pattern_node_t *cast = (const pm_array_pattern_node_t *) node;
1559
1560 const size_t requireds_size = cast->requireds.size;
1561 const size_t posts_size = cast->posts.size;
1562 const size_t minimum_size = requireds_size + posts_size;
1563
1564 bool use_rest_size = (
1565 cast->rest != NULL &&
1567 ((((const pm_splat_node_t *) cast->rest)->expression != NULL) || posts_size > 0)
1568 );
1569
1570 LABEL *match_failed_label = NEW_LABEL(line.lineno);
1571 LABEL *type_error_label = NEW_LABEL(line.lineno);
1572 LABEL *deconstruct_label = NEW_LABEL(line.lineno);
1573 LABEL *deconstructed_label = NEW_LABEL(line.lineno);
1574
1575 if (use_rest_size) {
1576 ADD_INSN1(ret, &line.node, putobject, INT2FIX(0));
1577 ADD_INSN(ret, &line.node, swap);
1578 base_index++;
1579 }
1580
1581 if (cast->constant != NULL) {
1582 CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, src, match_failed_label, in_single_pattern, base_index));
1583 }
1584
1585 CHECK(pm_compile_pattern_deconstruct(iseq, scope_node, node, ret, src, deconstruct_label, match_failed_label, deconstructed_label, type_error_label, in_single_pattern, use_deconstructed_cache, base_index));
1586
1587 ADD_INSN(ret, &line.node, dup);
1588 ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
1589 ADD_INSN1(ret, &line.node, putobject, INT2FIX(minimum_size));
1590 ADD_SEND(ret, &line.node, cast->rest == NULL ? idEq : idGE, INT2FIX(1));
1591 if (in_single_pattern) {
1592 VALUE message = cast->rest == NULL ? rb_fstring_lit("%p length mismatch (given %p, expected %p)") : rb_fstring_lit("%p length mismatch (given %p, expected %p+)");
1593 CHECK(pm_compile_pattern_length_error(iseq, scope_node, node, ret, message, INT2FIX(minimum_size), base_index + 1));
1594 }
1595 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1596
1597 for (size_t index = 0; index < requireds_size; index++) {
1598 const pm_node_t *required = cast->requireds.nodes[index];
1599 ADD_INSN(ret, &line.node, dup);
1600 ADD_INSN1(ret, &line.node, putobject, INT2FIX(index));
1601 ADD_SEND(ret, &line.node, idAREF, INT2FIX(1));
1602 CHECK(pm_compile_pattern_match(iseq, scope_node, required, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
1603 }
1604
1605 if (cast->rest != NULL) {
1606 if (((const pm_splat_node_t *) cast->rest)->expression != NULL) {
1607 ADD_INSN(ret, &line.node, dup);
1608 ADD_INSN1(ret, &line.node, putobject, INT2FIX(requireds_size));
1609 ADD_INSN1(ret, &line.node, topn, INT2FIX(1));
1610 ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
1611 ADD_INSN1(ret, &line.node, putobject, INT2FIX(minimum_size));
1612 ADD_SEND(ret, &line.node, idMINUS, INT2FIX(1));
1613 ADD_INSN1(ret, &line.node, setn, INT2FIX(4));
1614 ADD_SEND(ret, &line.node, idAREF, INT2FIX(2));
1615 CHECK(pm_compile_pattern_match(iseq, scope_node, ((const pm_splat_node_t *) cast->rest)->expression, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
1616 } else if (posts_size > 0) {
1617 ADD_INSN(ret, &line.node, dup);
1618 ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
1619 ADD_INSN1(ret, &line.node, putobject, INT2FIX(minimum_size));
1620 ADD_SEND(ret, &line.node, idMINUS, INT2FIX(1));
1621 ADD_INSN1(ret, &line.node, setn, INT2FIX(2));
1622 ADD_INSN(ret, &line.node, pop);
1623 }
1624 }
1625
1626 for (size_t index = 0; index < posts_size; index++) {
1627 const pm_node_t *post = cast->posts.nodes[index];
1628 ADD_INSN(ret, &line.node, dup);
1629
1630 ADD_INSN1(ret, &line.node, putobject, INT2FIX(requireds_size + index));
1631 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1632 ADD_SEND(ret, &line.node, idPLUS, INT2FIX(1));
1633 ADD_SEND(ret, &line.node, idAREF, INT2FIX(1));
1634 CHECK(pm_compile_pattern_match(iseq, scope_node, post, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
1635 }
1636
1637 ADD_INSN(ret, &line.node, pop);
1638 if (use_rest_size) {
1639 ADD_INSN(ret, &line.node, pop);
1640 }
1641
1642 ADD_INSNL(ret, &line.node, jump, matched_label);
1643 ADD_INSN(ret, &line.node, putnil);
1644 if (use_rest_size) {
1645 ADD_INSN(ret, &line.node, putnil);
1646 }
1647
1648 ADD_LABEL(ret, type_error_label);
1649 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1650 ADD_INSN1(ret, &line.node, putobject, rb_eTypeError);
1651 ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("deconstruct must return Array"));
1652 ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(2));
1653 ADD_INSN(ret, &line.node, pop);
1654
1655 ADD_LABEL(ret, match_failed_label);
1656 ADD_INSN(ret, &line.node, pop);
1657 if (use_rest_size) {
1658 ADD_INSN(ret, &line.node, pop);
1659 }
1660
1661 ADD_INSNL(ret, &line.node, jump, unmatched_label);
1662 break;
1663 }
1664 case PM_FIND_PATTERN_NODE: {
1665 // Find patterns in pattern matching are triggered by using commas in
1666 // a pattern or wrapping it in braces and using a splat on both the left
1667 // and right side of the pattern. This looks like:
1668 //
1669 // foo => [*, 1, 2, 3, *]
1670 //
1671 // There can be any number of requireds in the middle. The splats on
1672 // both sides can optionally have names attached.
1673 const pm_find_pattern_node_t *cast = (const pm_find_pattern_node_t *) node;
1674 const size_t size = cast->requireds.size;
1675
1676 LABEL *match_failed_label = NEW_LABEL(line.lineno);
1677 LABEL *type_error_label = NEW_LABEL(line.lineno);
1678 LABEL *deconstruct_label = NEW_LABEL(line.lineno);
1679 LABEL *deconstructed_label = NEW_LABEL(line.lineno);
1680
1681 if (cast->constant) {
1682 CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, src, match_failed_label, in_single_pattern, base_index));
1683 }
1684
1685 CHECK(pm_compile_pattern_deconstruct(iseq, scope_node, node, ret, src, deconstruct_label, match_failed_label, deconstructed_label, type_error_label, in_single_pattern, use_deconstructed_cache, base_index));
1686
1687 ADD_INSN(ret, &line.node, dup);
1688 ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
1689 ADD_INSN1(ret, &line.node, putobject, INT2FIX(size));
1690 ADD_SEND(ret, &line.node, idGE, INT2FIX(1));
1691 if (in_single_pattern) {
1692 CHECK(pm_compile_pattern_length_error(iseq, scope_node, node, ret, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(size), base_index + 1));
1693 }
1694 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1695
1696 {
1697 LABEL *while_begin_label = NEW_LABEL(line.lineno);
1698 LABEL *next_loop_label = NEW_LABEL(line.lineno);
1699 LABEL *find_succeeded_label = NEW_LABEL(line.lineno);
1700 LABEL *find_failed_label = NEW_LABEL(line.lineno);
1701
1702 ADD_INSN(ret, &line.node, dup);
1703 ADD_SEND(ret, &line.node, idLength, INT2FIX(0));
1704
1705 ADD_INSN(ret, &line.node, dup);
1706 ADD_INSN1(ret, &line.node, putobject, INT2FIX(size));
1707 ADD_SEND(ret, &line.node, idMINUS, INT2FIX(1));
1708 ADD_INSN1(ret, &line.node, putobject, INT2FIX(0));
1709 ADD_LABEL(ret, while_begin_label);
1710
1711 ADD_INSN(ret, &line.node, dup);
1712 ADD_INSN1(ret, &line.node, topn, INT2FIX(2));
1713 ADD_SEND(ret, &line.node, idLE, INT2FIX(1));
1714 ADD_INSNL(ret, &line.node, branchunless, find_failed_label);
1715
1716 for (size_t index = 0; index < size; index++) {
1717 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1718 ADD_INSN1(ret, &line.node, topn, INT2FIX(1));
1719
1720 if (index != 0) {
1721 ADD_INSN1(ret, &line.node, putobject, INT2FIX(index));
1722 ADD_SEND(ret, &line.node, idPLUS, INT2FIX(1));
1723 }
1724
1725 ADD_SEND(ret, &line.node, idAREF, INT2FIX(1));
1726 CHECK(pm_compile_pattern_match(iseq, scope_node, cast->requireds.nodes[index], ret, src, next_loop_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
1727 }
1728
1729 assert(PM_NODE_TYPE_P(cast->left, PM_SPLAT_NODE));
1730 const pm_splat_node_t *left = (const pm_splat_node_t *) cast->left;
1731
1732 if (left->expression != NULL) {
1733 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1734 ADD_INSN1(ret, &line.node, putobject, INT2FIX(0));
1735 ADD_INSN1(ret, &line.node, topn, INT2FIX(2));
1736 ADD_SEND(ret, &line.node, idAREF, INT2FIX(2));
1737 CHECK(pm_compile_pattern_match(iseq, scope_node, left->expression, ret, src, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4));
1738 }
1739
1740 assert(PM_NODE_TYPE_P(cast->right, PM_SPLAT_NODE));
1741 const pm_splat_node_t *right = (const pm_splat_node_t *) cast->right;
1742
1743 if (right->expression != NULL) {
1744 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1745 ADD_INSN1(ret, &line.node, topn, INT2FIX(1));
1746 ADD_INSN1(ret, &line.node, putobject, INT2FIX(size));
1747 ADD_SEND(ret, &line.node, idPLUS, INT2FIX(1));
1748 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1749 ADD_SEND(ret, &line.node, idAREF, INT2FIX(2));
1750 pm_compile_pattern_match(iseq, scope_node, right->expression, ret, src, find_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 4);
1751 }
1752
1753 ADD_INSNL(ret, &line.node, jump, find_succeeded_label);
1754
1755 ADD_LABEL(ret, next_loop_label);
1756 ADD_INSN1(ret, &line.node, putobject, INT2FIX(1));
1757 ADD_SEND(ret, &line.node, idPLUS, INT2FIX(1));
1758 ADD_INSNL(ret, &line.node, jump, while_begin_label);
1759
1760 ADD_LABEL(ret, find_failed_label);
1761 ADD_INSN1(ret, &line.node, adjuststack, INT2FIX(3));
1762 if (in_single_pattern) {
1763 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1764 ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("%p does not match to find pattern"));
1765 ADD_INSN1(ret, &line.node, topn, INT2FIX(2));
1766 ADD_SEND(ret, &line.node, id_core_sprintf, INT2FIX(2));
1767 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
1768
1769 ADD_INSN1(ret, &line.node, putobject, Qfalse);
1770 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
1771
1772 ADD_INSN(ret, &line.node, pop);
1773 ADD_INSN(ret, &line.node, pop);
1774 }
1775 ADD_INSNL(ret, &line.node, jump, match_failed_label);
1776 ADD_INSN1(ret, &line.node, dupn, INT2FIX(3));
1777
1778 ADD_LABEL(ret, find_succeeded_label);
1779 ADD_INSN1(ret, &line.node, adjuststack, INT2FIX(3));
1780 }
1781
1782 ADD_INSN(ret, &line.node, pop);
1783 ADD_INSNL(ret, &line.node, jump, matched_label);
1784 ADD_INSN(ret, &line.node, putnil);
1785
1786 ADD_LABEL(ret, type_error_label);
1787 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1788 ADD_INSN1(ret, &line.node, putobject, rb_eTypeError);
1789 ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("deconstruct must return Array"));
1790 ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(2));
1791 ADD_INSN(ret, &line.node, pop);
1792
1793 ADD_LABEL(ret, match_failed_label);
1794 ADD_INSN(ret, &line.node, pop);
1795 ADD_INSNL(ret, &line.node, jump, unmatched_label);
1796
1797 break;
1798 }
1799 case PM_HASH_PATTERN_NODE: {
1800 // Hash patterns in pattern matching are triggered by using labels and
1801 // values in a pattern or by using the ** operator. They are represented
1802 // by the HashPatternNode. This looks like:
1803 //
1804 // foo => { a: 1, b: 2, **bar }
1805 //
1806 // It can optionally have an assoc splat in the middle of it, which can
1807 // optionally have a name.
1808 const pm_hash_pattern_node_t *cast = (const pm_hash_pattern_node_t *) node;
1809
1810 // We don't consider it a "rest" parameter if it's a ** that is unnamed.
1811 bool has_rest = cast->rest != NULL && !(PM_NODE_TYPE_P(cast->rest, PM_ASSOC_SPLAT_NODE) && ((const pm_assoc_splat_node_t *) cast->rest)->value == NULL);
1812 bool has_keys = cast->elements.size > 0 || cast->rest != NULL;
1813
1814 LABEL *match_failed_label = NEW_LABEL(line.lineno);
1815 LABEL *type_error_label = NEW_LABEL(line.lineno);
1816 VALUE keys = Qnil;
1817
1818 if (has_keys && !has_rest) {
1819 keys = rb_ary_new_capa(cast->elements.size);
1820
1821 for (size_t index = 0; index < cast->elements.size; index++) {
1822 const pm_node_t *element = cast->elements.nodes[index];
1823 assert(PM_NODE_TYPE_P(element, PM_ASSOC_NODE));
1824
1825 const pm_node_t *key = ((const pm_assoc_node_t *) element)->key;
1826 assert(PM_NODE_TYPE_P(key, PM_SYMBOL_NODE));
1827
1828 VALUE symbol = ID2SYM(parse_string_symbol(&((const pm_symbol_node_t *) key)->unescaped, scope_node->parser));
1829 rb_ary_push(keys, symbol);
1830 }
1831 }
1832
1833 if (cast->constant) {
1834 CHECK(pm_compile_pattern_constant(iseq, scope_node, cast->constant, ret, src, match_failed_label, in_single_pattern, base_index));
1835 }
1836
1837 ADD_INSN(ret, &line.node, dup);
1838 ADD_INSN1(ret, &line.node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
1839 ADD_SEND(ret, &line.node, idRespond_to, INT2FIX(1));
1840 if (in_single_pattern) {
1841 CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1));
1842 }
1843 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1844
1845 if (NIL_P(keys)) {
1846 ADD_INSN(ret, &line.node, putnil);
1847 } else {
1848 ADD_INSN1(ret, &line.node, duparray, keys);
1849 RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
1850 }
1851 ADD_SEND(ret, &line.node, rb_intern("deconstruct_keys"), INT2FIX(1));
1852
1853 ADD_INSN(ret, &line.node, dup);
1854 ADD_INSN1(ret, &line.node, checktype, INT2FIX(T_HASH));
1855 ADD_INSNL(ret, &line.node, branchunless, type_error_label);
1856
1857 if (has_rest) {
1858 ADD_SEND(ret, &line.node, rb_intern("dup"), INT2FIX(0));
1859 }
1860
1861 if (has_keys) {
1862 DECL_ANCHOR(match_values);
1863 INIT_ANCHOR(match_values);
1864
1865 for (size_t index = 0; index < cast->elements.size; index++) {
1866 const pm_node_t *element = cast->elements.nodes[index];
1867 assert(PM_NODE_TYPE_P(element, PM_ASSOC_NODE));
1868
1869 const pm_assoc_node_t *assoc = (const pm_assoc_node_t *) element;
1870 const pm_node_t *key = assoc->key;
1871 assert(PM_NODE_TYPE_P(key, PM_SYMBOL_NODE));
1872
1873 VALUE symbol = ID2SYM(parse_string_symbol(&((const pm_symbol_node_t *) key)->unescaped, scope_node->parser));
1874 ADD_INSN(ret, &line.node, dup);
1875 ADD_INSN1(ret, &line.node, putobject, symbol);
1876 ADD_SEND(ret, &line.node, rb_intern("key?"), INT2FIX(1));
1877
1878 if (in_single_pattern) {
1879 LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
1880
1881 ADD_INSN(ret, &line.node, dup);
1882 ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
1883
1884 ADD_INSN1(ret, &line.node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, symbol)));
1885 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 2));
1886 ADD_INSN1(ret, &line.node, putobject, Qtrue);
1887 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 3));
1888 ADD_INSN1(ret, &line.node, topn, INT2FIX(3));
1889 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE + 4));
1890 ADD_INSN1(ret, &line.node, putobject, symbol);
1891 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY + 5));
1892
1893 ADD_INSN1(ret, &line.node, adjuststack, INT2FIX(4));
1894 ADD_LABEL(ret, match_succeeded_label);
1895 }
1896
1897 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1898 ADD_INSN(match_values, &line.node, dup);
1899 ADD_INSN1(match_values, &line.node, putobject, symbol);
1900 ADD_SEND(match_values, &line.node, has_rest ? rb_intern("delete") : idAREF, INT2FIX(1));
1901
1902 CHECK(pm_compile_pattern_match(iseq, scope_node, assoc->value, match_values, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1));
1903 }
1904
1905 ADD_SEQ(ret, match_values);
1906 } else {
1907 ADD_INSN(ret, &line.node, dup);
1908 ADD_SEND(ret, &line.node, idEmptyP, INT2FIX(0));
1909 if (in_single_pattern) {
1910 CHECK(pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("%p is not empty"), base_index + 1));
1911 }
1912 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1913 }
1914
1915 if (has_rest) {
1916 switch (PM_NODE_TYPE(cast->rest)) {
1918 ADD_INSN(ret, &line.node, dup);
1919 ADD_SEND(ret, &line.node, idEmptyP, INT2FIX(0));
1920 if (in_single_pattern) {
1921 pm_compile_pattern_generic_error(iseq, scope_node, node, ret, rb_fstring_lit("rest of %p is not empty"), base_index + 1);
1922 }
1923 ADD_INSNL(ret, &line.node, branchunless, match_failed_label);
1924 break;
1925 }
1926 case PM_ASSOC_SPLAT_NODE: {
1927 const pm_assoc_splat_node_t *splat = (const pm_assoc_splat_node_t *) cast->rest;
1928 ADD_INSN(ret, &line.node, dup);
1929 pm_compile_pattern_match(iseq, scope_node, splat->value, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index + 1);
1930 break;
1931 }
1932 default:
1933 rb_bug("unreachable");
1934 break;
1935 }
1936 }
1937
1938 ADD_INSN(ret, &line.node, pop);
1939 ADD_INSNL(ret, &line.node, jump, matched_label);
1940 ADD_INSN(ret, &line.node, putnil);
1941
1942 ADD_LABEL(ret, type_error_label);
1943 ADD_INSN1(ret, &line.node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
1944 ADD_INSN1(ret, &line.node, putobject, rb_eTypeError);
1945 ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("deconstruct_keys must return Hash"));
1946 ADD_SEND(ret, &line.node, id_core_raise, INT2FIX(2));
1947 ADD_INSN(ret, &line.node, pop);
1948
1949 ADD_LABEL(ret, match_failed_label);
1950 ADD_INSN(ret, &line.node, pop);
1951 ADD_INSNL(ret, &line.node, jump, unmatched_label);
1952 break;
1953 }
1955 // Capture patterns allow you to pattern match against an element in a
1956 // pattern and also capture the value into a local variable. This looks
1957 // like:
1958 //
1959 // [1] => [Integer => foo]
1960 //
1961 // In this case the `Integer => foo` will be represented by a
1962 // CapturePatternNode, which has both a value (the pattern to match
1963 // against) and a target (the place to write the variable into).
1964 const pm_capture_pattern_node_t *cast = (const pm_capture_pattern_node_t *) node;
1965
1966 LABEL *match_failed_label = NEW_LABEL(line.lineno);
1967
1968 ADD_INSN(ret, &line.node, dup);
1969 CHECK(pm_compile_pattern_match(iseq, scope_node, cast->value, ret, src, match_failed_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index + 1));
1970 CHECK(pm_compile_pattern(iseq, scope_node, cast->target, ret, src, matched_label, match_failed_label, in_single_pattern, in_alternation_pattern, false, base_index));
1971 ADD_INSN(ret, &line.node, putnil);
1972
1973 ADD_LABEL(ret, match_failed_label);
1974 ADD_INSN(ret, &line.node, pop);
1975 ADD_INSNL(ret, &line.node, jump, unmatched_label);
1976
1977 break;
1978 }
1980 // Local variables can be targetted by placing identifiers in the place
1981 // of a pattern. For example, foo in bar. This results in the value
1982 // being matched being written to that local variable.
1984 int index = pm_lookup_local_index(iseq, scope_node, cast->name);
1985
1986 // If this local variable is being written from within an alternation
1987 // pattern, then it cannot actually be added to the local table since
1988 // it's ambiguous which value should be used. So instead we indicate
1989 // this with a compile error.
1990 if (in_alternation_pattern) {
1991 ID id = pm_constant_id_lookup(scope_node, cast->name);
1992 const char *name = rb_id2name(id);
1993
1994 if (name && strlen(name) > 0 && name[0] != '_') {
1995 COMPILE_ERROR(ERROR_ARGS "illegal variable in alternative pattern (%"PRIsVALUE")", rb_id2str(id));
1996 return COMPILE_NG;
1997 }
1998 }
1999
2000 ADD_SETLOCAL(ret, &line.node, index, (int) cast->depth);
2001 ADD_INSNL(ret, &line.node, jump, matched_label);
2002 break;
2003 }
2005 // Alternation patterns allow you to specify multiple patterns in a
2006 // single expression using the | operator.
2008
2009 LABEL *matched_left_label = NEW_LABEL(line.lineno);
2010 LABEL *unmatched_left_label = NEW_LABEL(line.lineno);
2011
2012 // First, we're going to attempt to match against the left pattern. If
2013 // that pattern matches, then we'll skip matching the right pattern.
2014 ADD_INSN(ret, &line.node, dup);
2015 CHECK(pm_compile_pattern(iseq, scope_node, cast->left, ret, src, matched_left_label, unmatched_left_label, in_single_pattern, true, true, base_index + 1));
2016
2017 // If we get here, then we matched on the left pattern. In this case we
2018 // should pop out the duplicate value that we preemptively added to
2019 // match against the right pattern and then jump to the match label.
2020 ADD_LABEL(ret, matched_left_label);
2021 ADD_INSN(ret, &line.node, pop);
2022 ADD_INSNL(ret, &line.node, jump, matched_label);
2023 ADD_INSN(ret, &line.node, putnil);
2024
2025 // If we get here, then we didn't match on the left pattern. In this
2026 // case we attempt to match against the right pattern.
2027 ADD_LABEL(ret, unmatched_left_label);
2028 CHECK(pm_compile_pattern(iseq, scope_node, cast->right, ret, src, matched_label, unmatched_label, in_single_pattern, true, true, base_index));
2029 break;
2030 }
2031 case PM_ARRAY_NODE:
2035 case PM_FALSE_NODE:
2036 case PM_FLOAT_NODE:
2038 case PM_IMAGINARY_NODE:
2040 case PM_INTEGER_NODE:
2045 case PM_LAMBDA_NODE:
2047 case PM_NIL_NODE:
2048 case PM_RANGE_NODE:
2049 case PM_RATIONAL_NODE:
2051 case PM_SELF_NODE:
2052 case PM_STRING_NODE:
2053 case PM_SYMBOL_NODE:
2054 case PM_TRUE_NODE:
2055 case PM_X_STRING_NODE: {
2056 // These nodes are all simple patterns, which means we'll use the
2057 // checkmatch instruction to match against them, which is effectively a
2058 // VM-level === operator.
2059 PM_COMPILE_NOT_POPPED(node);
2060 if (in_single_pattern) {
2061 ADD_INSN1(ret, &line.node, dupn, INT2FIX(2));
2062 }
2063
2064 ADD_INSN1(ret, &line.node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
2065
2066 if (in_single_pattern) {
2067 pm_compile_pattern_eqq_error(iseq, scope_node, node, ret, base_index + 2);
2068 }
2069
2070 ADD_INSNL(ret, &line.node, branchif, matched_label);
2071 ADD_INSNL(ret, &line.node, jump, unmatched_label);
2072 break;
2073 }
2075 // Pinned variables are a way to match against the value of a variable
2076 // without it looking like you're trying to write to the variable. This
2077 // looks like: foo in ^@bar. To compile these, we compile the variable
2078 // that they hold.
2080 CHECK(pm_compile_pattern(iseq, scope_node, cast->variable, ret, src, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, true, base_index));
2081 break;
2082 }
2084 // Pinned expressions are a way to match against the value of an
2085 // expression that should be evaluated at runtime. This looks like:
2086 // foo in ^(bar). To compile these, we compile the expression that they
2087 // hold.
2089 CHECK(pm_compile_pattern(iseq, scope_node, cast->expression, ret, src, matched_label, unmatched_label, in_single_pattern, in_alternation_pattern, true, base_index));
2090 break;
2091 }
2092 case PM_IF_NODE:
2093 case PM_UNLESS_NODE: {
2094 // If and unless nodes can show up here as guards on `in` clauses. This
2095 // looks like:
2096 //
2097 // case foo
2098 // in bar if baz?
2099 // qux
2100 // end
2101 //
2102 // Because we know they're in the modifier form and they can't have any
2103 // variation on this pattern, we compile them differently (more simply)
2104 // here than we would in the normal compilation path.
2105 const pm_node_t *predicate;
2106 const pm_node_t *statement;
2107
2108 if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
2109 const pm_if_node_t *cast = (const pm_if_node_t *) node;
2110 predicate = cast->predicate;
2111
2112 assert(cast->statements != NULL && cast->statements->body.size == 1);
2113 statement = cast->statements->body.nodes[0];
2114 } else {
2115 const pm_unless_node_t *cast = (const pm_unless_node_t *) node;
2116 predicate = cast->predicate;
2117
2118 assert(cast->statements != NULL && cast->statements->body.size == 1);
2119 statement = cast->statements->body.nodes[0];
2120 }
2121
2122 CHECK(pm_compile_pattern_match(iseq, scope_node, statement, ret, src, unmatched_label, in_single_pattern, in_alternation_pattern, use_deconstructed_cache, base_index));
2123 PM_COMPILE_NOT_POPPED(predicate);
2124
2125 if (in_single_pattern) {
2126 LABEL *match_succeeded_label = NEW_LABEL(line.lineno);
2127
2128 ADD_INSN(ret, &line.node, dup);
2129 if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
2130 ADD_INSNL(ret, &line.node, branchif, match_succeeded_label);
2131 } else {
2132 ADD_INSNL(ret, &line.node, branchunless, match_succeeded_label);
2133 }
2134
2135 ADD_INSN1(ret, &line.node, putobject, rb_fstring_lit("guard clause does not return true"));
2136 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING + 1));
2137 ADD_INSN1(ret, &line.node, putobject, Qfalse);
2138 ADD_INSN1(ret, &line.node, setn, INT2FIX(base_index + PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P + 2));
2139
2140 ADD_INSN(ret, &line.node, pop);
2141 ADD_INSN(ret, &line.node, pop);
2142
2143 ADD_LABEL(ret, match_succeeded_label);
2144 }
2145
2146 if (PM_NODE_TYPE_P(node, PM_IF_NODE)) {
2147 ADD_INSNL(ret, &line.node, branchunless, unmatched_label);
2148 } else {
2149 ADD_INSNL(ret, &line.node, branchif, unmatched_label);
2150 }
2151
2152 ADD_INSNL(ret, &line.node, jump, matched_label);
2153 break;
2154 }
2155 default:
2156 // If we get here, then we have a node type that should not be in this
2157 // position. This would be a bug in the parser, because a different node
2158 // type should never have been created in this position in the tree.
2159 rb_bug("Unexpected node type in pattern matching expression: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
2160 break;
2161 }
2162
2163 return COMPILE_OK;
2164}
2165
2166#undef PM_PATTERN_BASE_INDEX_OFFSET_DECONSTRUCTED_CACHE
2167#undef PM_PATTERN_BASE_INDEX_OFFSET_ERROR_STRING
2168#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_P
2169#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_MATCHEE
2170#undef PM_PATTERN_BASE_INDEX_OFFSET_KEY_ERROR_KEY
2171
2172// Generate a scope node from the given node.
2173void
2174pm_scope_node_init(const pm_node_t *node, pm_scope_node_t *scope, pm_scope_node_t *previous, pm_parser_t *parser)
2175{
2176 scope->base.type = PM_SCOPE_NODE;
2177 scope->base.location.start = node->location.start;
2178 scope->base.location.end = node->location.end;
2179
2180 scope->previous = previous;
2181 scope->parser = parser;
2182 scope->ast_node = (pm_node_t *)node;
2183 scope->parameters = NULL;
2184 scope->body = NULL;
2185 scope->constants = NULL;
2186 scope->local_depth_offset = 0;
2187 scope->local_table_for_iseq_size = 0;
2188
2189 if (previous) {
2190 scope->constants = previous->constants;
2191 scope->local_depth_offset = previous->local_depth_offset;
2192 }
2193 scope->index_lookup_table = NULL;
2194
2195 pm_constant_id_list_init(&scope->locals);
2196
2197 switch (PM_NODE_TYPE(node)) {
2198 case PM_BLOCK_NODE: {
2199 pm_block_node_t *cast = (pm_block_node_t *) node;
2200 scope->body = cast->body;
2201 scope->locals = cast->locals;
2202 scope->local_depth_offset = 0;
2203 scope->parameters = cast->parameters;
2204 break;
2205 }
2206 case PM_CLASS_NODE: {
2207 pm_class_node_t *cast = (pm_class_node_t *) node;
2208 scope->body = cast->body;
2209 scope->locals = cast->locals;
2210 break;
2211 }
2212 case PM_DEF_NODE: {
2213 pm_def_node_t *cast = (pm_def_node_t *) node;
2214 scope->parameters = (pm_node_t *)cast->parameters;
2215 scope->body = cast->body;
2216 scope->locals = cast->locals;
2217 break;
2218 }
2219 case PM_ENSURE_NODE: {
2220 scope->body = (pm_node_t *)node;
2221 scope->local_depth_offset += 1;
2222 break;
2223 }
2224 case PM_FOR_NODE: {
2225 pm_for_node_t *cast = (pm_for_node_t *)node;
2226 scope->body = (pm_node_t *)cast->statements;
2227 scope->local_depth_offset += 1;
2228 break;
2229 }
2232 scope->body = (pm_node_t *)node;
2233 scope->local_depth_offset += 1;
2234 break;
2235 }
2236 case PM_LAMBDA_NODE: {
2237 pm_lambda_node_t *cast = (pm_lambda_node_t *) node;
2238 scope->parameters = cast->parameters;
2239 scope->body = cast->body;
2240 scope->locals = cast->locals;
2241 break;
2242 }
2243 case PM_MODULE_NODE: {
2244 pm_module_node_t *cast = (pm_module_node_t *) node;
2245 scope->body = cast->body;
2246 scope->locals = cast->locals;
2247 break;
2248 }
2251 scope->body = (pm_node_t *) cast->statements;
2252 scope->local_depth_offset += 2;
2253 break;
2254 }
2255 case PM_PROGRAM_NODE: {
2256 pm_program_node_t *cast = (pm_program_node_t *) node;
2257 scope->body = (pm_node_t *) cast->statements;
2258 scope->locals = cast->locals;
2259 break;
2260 }
2261 case PM_RESCUE_NODE: {
2262 pm_rescue_node_t *cast = (pm_rescue_node_t *)node;
2263 scope->body = (pm_node_t *)cast->statements;
2264 scope->local_depth_offset += 1;
2265 break;
2266 }
2269 scope->body = (pm_node_t *)cast->rescue_expression;
2270 scope->local_depth_offset += 1;
2271 break;
2272 }
2275 scope->body = cast->body;
2276 scope->locals = cast->locals;
2277 break;
2278 }
2279 case PM_STATEMENTS_NODE: {
2281 scope->body = (pm_node_t *)cast;
2282 break;
2283 }
2284 default:
2285 assert(false && "unreachable");
2286 break;
2287 }
2288}
2289
2290static void pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, ID method_id, LABEL *start);
2291
2292void
2293pm_compile_defined_expr0(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, int lineno, bool in_condition, LABEL **lfinish, bool explicit_receiver)
2294{
2295 // in_condition is the same as compile.c's needstr
2296 enum defined_type dtype = DEFINED_NOT_DEFINED;
2297 switch (PM_NODE_TYPE(node)) {
2298 case PM_ARGUMENTS_NODE: {
2299 const pm_arguments_node_t *cast = (pm_arguments_node_t *) node;
2300 const pm_node_list_t *arguments = &cast->arguments;
2301 for (size_t idx = 0; idx < arguments->size; idx++) {
2302 const pm_node_t *argument = arguments->nodes[idx];
2303 pm_compile_defined_expr0(iseq, argument, ret, src, popped, scope_node, dummy_line_node, lineno, in_condition, lfinish, explicit_receiver);
2304
2305 if (!lfinish[1]) {
2306 lfinish[1] = NEW_LABEL(lineno);
2307 }
2308 ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
2309 }
2310 dtype = DEFINED_TRUE;
2311 break;
2312 }
2313 case PM_NIL_NODE:
2314 dtype = DEFINED_NIL;
2315 break;
2316 case PM_PARENTHESES_NODE: {
2317 pm_parentheses_node_t *parentheses_node = (pm_parentheses_node_t *) node;
2318
2319 if (parentheses_node->body == NULL) {
2320 dtype = DEFINED_NIL;
2321 } else {
2322 dtype = DEFINED_EXPR;
2323 }
2324 break;
2325 }
2326 case PM_SELF_NODE:
2327 dtype = DEFINED_SELF;
2328 break;
2329 case PM_TRUE_NODE:
2330 dtype = DEFINED_TRUE;
2331 break;
2332 case PM_FALSE_NODE:
2333 dtype = DEFINED_FALSE;
2334 break;
2335 case PM_ARRAY_NODE: {
2336 pm_array_node_t *array_node = (pm_array_node_t *) node;
2337 if (!(array_node->base.flags & PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT)) {
2338 for (size_t index = 0; index < array_node->elements.size; index++) {
2339 pm_compile_defined_expr0(iseq, array_node->elements.nodes[index], ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish, false);
2340 if (!lfinish[1]) {
2341 lfinish[1] = NEW_LABEL(lineno);
2342 }
2343 ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
2344 }
2345 }
2346 }
2347 case PM_AND_NODE:
2348 case PM_FLOAT_NODE:
2349 case PM_HASH_NODE:
2350 case PM_IMAGINARY_NODE:
2351 case PM_INTEGER_NODE:
2355 case PM_LAMBDA_NODE:
2357 case PM_OR_NODE:
2358 case PM_RANGE_NODE:
2363 case PM_STRING_NODE:
2364 case PM_SYMBOL_NODE:
2365 case PM_X_STRING_NODE:
2366 dtype = DEFINED_EXPR;
2367 break;
2369 dtype = DEFINED_LVAR;
2370 break;
2371#define PUSH_VAL(type) (in_condition ? Qtrue : rb_iseq_defined_string(type))
2373 pm_instance_variable_read_node_t *instance_variable_read_node = (pm_instance_variable_read_node_t *)node;
2374 ID id = pm_constant_id_lookup(scope_node, instance_variable_read_node->name);
2375 ADD_INSN3(ret, &dummy_line_node, definedivar,
2376 ID2SYM(id), get_ivar_ic_value(iseq, id), PUSH_VAL(DEFINED_IVAR));
2377 return;
2378 }
2380 char *char_ptr = (char *)(node->location.start) + 1;
2381 ID backref_val = INT2FIX(rb_intern2(char_ptr, 1)) << 1 | 1;
2382
2383 PM_PUTNIL;
2384 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_REF),
2385 backref_val,
2386 PUSH_VAL(DEFINED_GVAR));
2387
2388 return;
2389 }
2391 uint32_t reference_number = ((pm_numbered_reference_read_node_t *)node)->number;
2392
2393 PM_PUTNIL;
2394 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_REF),
2395 INT2FIX(reference_number << 1),
2396 PUSH_VAL(DEFINED_GVAR));
2397
2398 return;
2399 }
2401 pm_global_variable_read_node_t *glabal_variable_read_node = (pm_global_variable_read_node_t *)node;
2402 PM_PUTNIL;
2403 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_GVAR),
2404 ID2SYM(pm_constant_id_lookup(scope_node, glabal_variable_read_node->name)), PUSH_VAL(DEFINED_GVAR));
2405 return;
2406 }
2408 pm_class_variable_read_node_t *class_variable_read_node = (pm_class_variable_read_node_t *)node;
2409 PM_PUTNIL;
2410 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CVAR),
2411 ID2SYM(pm_constant_id_lookup(scope_node, class_variable_read_node->name)), PUSH_VAL(DEFINED_CVAR));
2412
2413 return;
2414 }
2415 case PM_CONSTANT_READ_NODE: {
2416 pm_constant_read_node_t *constant_node = (pm_constant_read_node_t *)node;
2417 PM_PUTNIL;
2418 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CONST),
2419 ID2SYM(pm_constant_id_lookup(scope_node, constant_node->name)), PUSH_VAL(DEFINED_CONST));
2420 return;
2421 }
2422 case PM_CONSTANT_PATH_NODE: {
2423 pm_constant_path_node_t *constant_path_node = ((pm_constant_path_node_t *)node);
2424 if (constant_path_node->parent) {
2425 if (!lfinish[1]) {
2426 lfinish[1] = NEW_LABEL(lineno);
2427 }
2428 pm_compile_defined_expr0(iseq, constant_path_node->parent, ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish, false);
2429 ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
2430 PM_COMPILE(constant_path_node->parent);
2431 }
2432 else {
2433 ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
2434 }
2435 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CONST_FROM),
2436 ID2SYM(pm_constant_id_lookup(scope_node, ((pm_constant_read_node_t *)constant_path_node->child)->name)), PUSH_VAL(DEFINED_CONST));
2437 return;
2438 }
2439
2440 case PM_CALL_NODE: {
2441 pm_call_node_t *call_node = ((pm_call_node_t *)node);
2442 ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
2443
2444 if (call_node->receiver || call_node->arguments) {
2445 if (!lfinish[1]) {
2446 lfinish[1] = NEW_LABEL(lineno);
2447 }
2448 if (!lfinish[2]) {
2449 lfinish[2] = NEW_LABEL(lineno);
2450 }
2451 }
2452
2453 if (call_node->arguments) {
2454 pm_compile_defined_expr0(iseq, (const pm_node_t *)call_node->arguments, ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish, false);
2455 ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
2456 }
2457
2458 if (call_node->receiver) {
2459 pm_compile_defined_expr0(iseq, call_node->receiver, ret, src, popped, scope_node, dummy_line_node, lineno, true, lfinish, true);
2460 if (PM_NODE_TYPE_P(call_node->receiver, PM_CALL_NODE)) {
2461 ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[2]);
2462 ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
2463 pm_compile_call(iseq, (const pm_call_node_t *)call_node->receiver, ret, src, popped, scope_node, method_id, NULL);
2464 }
2465 else {
2466 ADD_INSNL(ret, &dummy_line_node, branchunless, lfinish[1]);
2467 PM_COMPILE(call_node->receiver);
2468 }
2469
2470 if (explicit_receiver) {
2471 PM_DUP;
2472 }
2473
2474 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_METHOD), rb_id2sym(method_id), PUSH_VAL(DEFINED_METHOD));
2475 }
2476 else {
2477 PM_PUTSELF;
2478 if (explicit_receiver) {
2479 PM_DUP;
2480 }
2481 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_FUNC), rb_id2sym(method_id), PUSH_VAL(DEFINED_METHOD));
2482 }
2483 return;
2484 }
2485
2486 case PM_YIELD_NODE:
2487 PM_PUTNIL;
2488 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_YIELD), 0,
2489 PUSH_VAL(DEFINED_YIELD));
2490 return;
2491 case PM_SUPER_NODE:
2493 PM_PUTNIL;
2494 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_ZSUPER), 0,
2495 PUSH_VAL(DEFINED_ZSUPER));
2496 return;
2501
2506
2511
2516
2521
2523 dtype = DEFINED_ASGN;
2524 break;
2525 default:
2526 rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
2527 }
2528
2529 assert(dtype != DEFINED_NOT_DEFINED);
2530
2531 ADD_INSN1(ret, &dummy_line_node, putobject, PUSH_VAL(dtype));
2532#undef PUSH_VAL
2533}
2534
2535static void
2536pm_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, int lineno, bool in_condition, LABEL **lfinish, bool explicit_receiver)
2537{
2538 LINK_ELEMENT *lcur = ret->last;
2539
2540 pm_compile_defined_expr0(iseq, node, ret, src, popped, scope_node, dummy_line_node, lineno, in_condition, lfinish, false);
2541
2542 if (lfinish[1]) {
2543 LABEL *lstart = NEW_LABEL(lineno);
2544 LABEL *lend = NEW_LABEL(lineno);
2545
2547 rb_iseq_new_with_callback_new_callback(build_defined_rescue_iseq, NULL);
2548
2549 const rb_iseq_t *rescue = new_child_iseq_with_callback(iseq, ifunc,
2550 rb_str_concat(rb_str_new2("defined guard in "),
2551 ISEQ_BODY(iseq)->location.label),
2552 iseq, ISEQ_TYPE_RESCUE, 0);
2553
2554 lstart->rescued = LABEL_RESCUE_BEG;
2555 lend->rescued = LABEL_RESCUE_END;
2556
2557 APPEND_LABEL(ret, lcur, lstart);
2558 ADD_LABEL(ret, lend);
2559 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue, lfinish[1]);
2560 }
2561}
2562
2563void
2564pm_compile_defined_expr(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, NODE dummy_line_node, int lineno, bool in_condition)
2565{
2566 LABEL *lfinish[3];
2567 LINK_ELEMENT *last = ret->last;
2568
2569 lfinish[0] = NEW_LABEL(lineno);
2570 lfinish[1] = 0;
2571 lfinish[2] = 0;
2572
2573 if (!popped) {
2574 pm_defined_expr(iseq, node, ret, src, popped, scope_node, dummy_line_node, lineno, in_condition, lfinish, false);
2575 }
2576
2577 if (lfinish[1]) {
2578 ELEM_INSERT_NEXT(last, &new_insn_body(iseq, &dummy_line_node, BIN(putnil), 0)->link);
2579 PM_SWAP;
2580 if (lfinish[2]) {
2581 ADD_LABEL(ret, lfinish[2]);
2582 }
2583 PM_POP;
2584 ADD_LABEL(ret, lfinish[1]);
2585
2586 }
2587 ADD_LABEL(ret, lfinish[0]);
2588}
2589
2590static void
2591pm_compile_call(rb_iseq_t *iseq, const pm_call_node_t *call_node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node, ID method_id, LABEL *start)
2592{
2593 pm_parser_t *parser = scope_node->parser;
2594 pm_newline_list_t newline_list = parser->newline_list;
2595 int lineno = (int)pm_newline_list_line_column(&newline_list, ((pm_node_t *)call_node)->location.start).line;
2596 NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
2597 LABEL *else_label = NEW_LABEL(lineno);
2598 LABEL *end_label = NEW_LABEL(lineno);
2599
2600 pm_node_t *pm_node = (pm_node_t *)call_node;
2601
2602 if (call_node->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) {
2603 PM_DUP;
2604 ADD_INSNL(ret, &dummy_line_node, branchnil, else_label);
2605 }
2606
2607 int flags = 0;
2608 struct rb_callinfo_kwarg *kw_arg = NULL;
2609
2610 int orig_argc = pm_setup_args(call_node->arguments, &flags, &kw_arg, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
2611
2612 const rb_iseq_t *block_iseq = NULL;
2613 if (call_node->block != NULL && PM_NODE_TYPE_P(call_node->block, PM_BLOCK_NODE)) {
2614 // Scope associated with the block
2615 pm_scope_node_t next_scope_node;
2616 pm_scope_node_init(call_node->block, &next_scope_node, scope_node, parser);
2617
2618 block_iseq = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
2619 if (ISEQ_BODY(block_iseq)->catch_table) {
2620 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, start, end_label, block_iseq, end_label);
2621 }
2622 ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
2623 }
2624 else {
2626 flags |= VM_CALL_VCALL;
2627 }
2628
2629 if (call_node->block != NULL) {
2630 PM_COMPILE_NOT_POPPED(call_node->block);
2631 flags |= VM_CALL_ARGS_BLOCKARG;
2632 }
2633
2634 if (!flags) {
2635 flags |= VM_CALL_ARGS_SIMPLE;
2636 }
2637 }
2638
2639 if (call_node->receiver == NULL || PM_NODE_TYPE_P(call_node->receiver, PM_SELF_NODE)) {
2640 flags |= VM_CALL_FCALL;
2641 }
2642
2644 if (!popped) {
2645 ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(orig_argc + 1));
2646 }
2647 ADD_SEND_R(ret, &dummy_line_node, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
2648 PM_POP_UNLESS_POPPED;
2649 }
2650 else {
2651 ADD_SEND_R(ret, &dummy_line_node, method_id, INT2FIX(orig_argc), block_iseq, INT2FIX(flags), kw_arg);
2652 }
2653
2654 if (call_node->base.flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION) {
2655 ADD_INSNL(ret, &dummy_line_node, jump, end_label);
2656 ADD_LABEL(ret, else_label);
2657 }
2658 ADD_LABEL(ret, end_label);
2659
2660 PM_POP_IF_POPPED;
2661}
2662
2663// This is exactly the same as add_ensure_iseq, except it compiled
2664// the node as a Prism node, and not a CRuby node
2665static void
2666pm_add_ensure_iseq(LINK_ANCHOR *const ret, rb_iseq_t *iseq, int is_return, const uint8_t *src, pm_scope_node_t *scope_node)
2667{
2668 assert(can_add_ensure_iseq(iseq));
2669
2671 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack;
2672 struct iseq_compile_data_ensure_node_stack *prev_enlp = enlp;
2673 DECL_ANCHOR(ensure);
2674
2675 INIT_ANCHOR(ensure);
2676 while (enlp) {
2677 if (enlp->erange != NULL) {
2678 DECL_ANCHOR(ensure_part);
2679 LABEL *lstart = NEW_LABEL(0);
2680 LABEL *lend = NEW_LABEL(0);
2681 INIT_ANCHOR(ensure_part);
2682
2683 add_ensure_range(iseq, enlp->erange, lstart, lend);
2684
2685 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = enlp->prev;
2686 ADD_LABEL(ensure_part, lstart);
2687 bool popped = true;
2688 PM_COMPILE_INTO_ANCHOR(ensure_part, (pm_node_t *)enlp->ensure_node);
2689 ADD_LABEL(ensure_part, lend);
2690 ADD_SEQ(ensure, ensure_part);
2691 }
2692 else {
2693 if (!is_return) {
2694 break;
2695 }
2696 }
2697 enlp = enlp->prev;
2698 }
2699 ISEQ_COMPILE_DATA(iseq)->ensure_node_stack = prev_enlp;
2700 ADD_SEQ(ret, ensure);
2701}
2702
2703static void
2704pm_insert_local_index(pm_constant_id_t constant_id, int local_index, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node)
2705{
2706 ID local = pm_constant_id_lookup(scope_node, constant_id);
2707 local_table_for_iseq->ids[local_index] = local;
2708 st_insert(index_lookup_table, constant_id, local_index);
2709}
2710
2711static int
2712pm_compile_multi_assign_params(pm_multi_target_node_t *multi, st_table *index_lookup_table, rb_ast_id_table_t *local_table_for_iseq, pm_scope_node_t *scope_node, int local_index)
2713{
2714 for (size_t m = 0; m < multi->lefts.size; m++) {
2715 pm_node_t *multi_node = multi->lefts.nodes[m];
2716
2717 switch (PM_NODE_TYPE(multi_node)) {
2720 pm_insert_local_index(req->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
2721 local_index++;
2722 break;
2723 }
2724 case PM_MULTI_TARGET_NODE: {
2725 local_index = pm_compile_multi_assign_params((pm_multi_target_node_t *)multi_node, index_lookup_table, local_table_for_iseq, scope_node, local_index);
2726 break;
2727 }
2728 default: {
2729 rb_bug("Parameter within a MultiTargetNode isn't allowed");
2730 }
2731 }
2732 }
2733
2734 if (multi->rest && PM_NODE_TYPE_P(multi->rest, PM_SPLAT_NODE)) {
2735 pm_splat_node_t *rest = (pm_splat_node_t *)multi->rest;
2736 if (rest->expression && PM_NODE_TYPE_P(rest->expression, PM_REQUIRED_PARAMETER_NODE)) {
2738 pm_insert_local_index(req->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
2739 local_index++;
2740 }
2741 }
2742
2743 for (size_t m = 0; m < multi->rights.size; m++) {
2744 pm_node_t *multi_node = multi->rights.nodes[m];
2745
2746 switch (PM_NODE_TYPE(multi_node)) {
2749 pm_insert_local_index(req->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
2750 local_index++;
2751 break;
2752 }
2753 case PM_MULTI_TARGET_NODE: {
2754 local_index = pm_compile_multi_assign_params((pm_multi_target_node_t *)multi_node, index_lookup_table, local_table_for_iseq, scope_node, local_index);
2755 break;
2756 }
2757 default: {
2758 rb_bug("Parameter within a MultiTargetNode isn't allowed");
2759 }
2760 }
2761 }
2762
2763 return local_index;
2764}
2765
2766/*
2767 * Compiles a prism node into instruction sequences
2768 *
2769 * iseq - The current instruction sequence object (used for locals)
2770 * node - The prism node to compile
2771 * ret - The linked list of instructions to append instructions onto
2772 * popped - True if compiling something with no side effects, so instructions don't
2773 * need to be added
2774 * scope_node - Stores parser and local information
2775 */
2776static void
2777pm_compile_node(rb_iseq_t *iseq, const pm_node_t *node, LINK_ANCHOR *const ret, const uint8_t *src, bool popped, pm_scope_node_t *scope_node)
2778{
2779 pm_parser_t *parser = scope_node->parser;
2780 pm_newline_list_t newline_list = parser->newline_list;
2781 int lineno = (int)pm_newline_list_line_column(&newline_list, node->location.start).line;
2782 NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
2783
2784 if (node->flags & PM_NODE_FLAG_NEWLINE &&
2785 ISEQ_COMPILE_DATA(iseq)->last_line != lineno) {
2786 int event = RUBY_EVENT_LINE;
2787
2788 ISEQ_COMPILE_DATA(iseq)->last_line = lineno;
2789 if (ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq)) {
2790 event |= RUBY_EVENT_COVERAGE_LINE;
2791 }
2792 ADD_TRACE(ret, event);
2793 }
2794
2795 switch (PM_NODE_TYPE(node)) {
2798
2799 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
2800
2801 ADD_INSN1(ret, &dummy_line_node, putobject, ID2SYM(parse_location_symbol(&alias_node->new_name->location, parser)));
2802 ADD_INSN1(ret, &dummy_line_node, putobject, ID2SYM(parse_location_symbol(&alias_node->old_name->location, parser)));
2803
2804 ADD_SEND(ret, &dummy_line_node, id_core_set_variable_alias, INT2FIX(2));
2805
2806 PM_POP_IF_POPPED;
2807 return;
2808 }
2809 case PM_ALIAS_METHOD_NODE: {
2810 pm_alias_method_node_t *alias_node = (pm_alias_method_node_t *) node;
2811
2812 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
2813 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
2814
2815 PM_COMPILE_NOT_POPPED(alias_node->new_name);
2816 PM_COMPILE_NOT_POPPED(alias_node->old_name);
2817
2818 ADD_SEND(ret, &dummy_line_node, id_core_set_method_alias, INT2FIX(3));
2819
2820 PM_POP_IF_POPPED;
2821
2822 return;
2823 }
2824 case PM_AND_NODE: {
2825 pm_and_node_t *and_node = (pm_and_node_t *) node;
2826
2827 LABEL *end_label = NEW_LABEL(lineno);
2828 PM_COMPILE_NOT_POPPED(and_node->left);
2829 PM_DUP_UNLESS_POPPED;
2830 ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
2831
2832 PM_POP_UNLESS_POPPED;
2833 PM_COMPILE(and_node->right);
2834 ADD_LABEL(ret, end_label);
2835 return;
2836 }
2837 case PM_ARGUMENTS_NODE: {
2838 // These are ArgumentsNodes that are not compiled directly by their
2839 // parent call nodes, used in the cases of NextNodes, ReturnNodes
2840 // and BreakNodes
2841 pm_arguments_node_t *arguments_node = (pm_arguments_node_t *) node;
2842 pm_node_list_t node_list = arguments_node->arguments;
2843 for (size_t index = 0; index < node_list.size; index++) {
2844 PM_COMPILE(node_list.nodes[index]);
2845 }
2846 if (node_list.size > 1) {
2847 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(node_list.size));
2848 }
2849 return;
2850 }
2851 case PM_ARRAY_NODE: {
2852 // If every node in the array is static, then we can compile the entire
2853 // array now instead of later.
2854 if (pm_static_literal_p(node)) {
2855 // We're only going to compile this node if it's not popped. If it
2856 // is popped, then we know we don't need to do anything since it's
2857 // statically known.
2858 if (!popped) {
2859 pm_array_node_t *cast = (pm_array_node_t *) node;
2860 if (cast->elements.size) {
2861 VALUE value = pm_static_literal_value(node, scope_node, parser);
2862 ADD_INSN1(ret, &dummy_line_node, duparray, value);
2863 RB_OBJ_WRITTEN(iseq, Qundef, value);
2864 }
2865 else {
2866 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(0));
2867 }
2868 }
2869 } else {
2870 // Here since we know there are possible side-effects inside the
2871 // array contents, we're going to build it entirely at runtime.
2872 // We'll do this by pushing all of the elements onto the stack and
2873 // then combining them with newarray.
2874 //
2875 // If this hash is popped, then this serves only to ensure we enact
2876 // all side-effects (like method calls) that are contained within
2877 // the hash contents.
2878 pm_array_node_t *cast = (pm_array_node_t *) node;
2879 pm_node_list_t *elements = &cast->elements;
2880
2881 // In the case that there is a splat node within the array,
2882 // the array gets compiled slightly differently.
2884 if (elements->size == 1) {
2885 // If the only nodes is a SplatNode, we never
2886 // need to emit the newarray or concatarray
2887 // instructions
2888 PM_COMPILE_NOT_POPPED(elements->nodes[0]);
2889 }
2890 else {
2891 // We treat all sequences of non-splat elements as their
2892 // own arrays, followed by a newarray, and then continually
2893 // concat the arrays with the SplatNodes
2894 int new_array_size = 0;
2895 bool need_to_concat_array = false;
2896 for (size_t index = 0; index < elements->size; index++) {
2897 pm_node_t *array_element = elements->nodes[index];
2898 if (PM_NODE_TYPE_P(array_element, PM_SPLAT_NODE)) {
2899 pm_splat_node_t *splat_element = (pm_splat_node_t *)array_element;
2900
2901 // If we already have non-splat elements, we need to emit a newarray
2902 // instruction
2903 if (new_array_size) {
2904 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(new_array_size));
2905
2906 // We don't want to emit a concat array in the case where
2907 // we're seeing our first splat, and already have elements
2908 if (need_to_concat_array) {
2909 ADD_INSN(ret, &dummy_line_node, concatarray);
2910 }
2911
2912 new_array_size = 0;
2913 }
2914
2915 PM_COMPILE_NOT_POPPED(splat_element->expression);
2916
2917 if (index > 0) {
2918 ADD_INSN(ret, &dummy_line_node, concatarray);
2919 }
2920 else {
2921 // If this is the first element, we need to splatarray
2922 ADD_INSN1(ret, &dummy_line_node, splatarray, Qtrue);
2923 }
2924
2925 need_to_concat_array = true;
2926 }
2927 else {
2928 new_array_size++;
2929 PM_COMPILE_NOT_POPPED(array_element);
2930 }
2931 }
2932
2933 if (new_array_size) {
2934 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(new_array_size));
2935 if (need_to_concat_array) {
2936 ADD_INSN(ret, &dummy_line_node, concatarray);
2937 }
2938 }
2939 }
2940
2941 PM_POP_IF_POPPED;
2942 }
2943 else {
2944 for (size_t index = 0; index < elements->size; index++) {
2945 PM_COMPILE(elements->nodes[index]);
2946 }
2947
2948 if (!popped) {
2949 ADD_INSN1(ret, &dummy_line_node, newarray, INT2FIX(elements->size));
2950 }
2951 }
2952 }
2953 return;
2954 }
2955 case PM_ASSOC_NODE: {
2956 pm_assoc_node_t *assoc_node = (pm_assoc_node_t *) node;
2957 PM_COMPILE(assoc_node->key);
2958 if (assoc_node->value) {
2959 PM_COMPILE(assoc_node->value);
2960 }
2961 return;
2962 }
2963 case PM_ASSOC_SPLAT_NODE: {
2964 pm_assoc_splat_node_t *assoc_splat_node = (pm_assoc_splat_node_t *)node;
2965
2966 PM_COMPILE(assoc_splat_node->value);
2967 return;
2968 }
2970 if (!popped) {
2971 // Since a back reference is `$<char>`, ruby represents the ID as the
2972 // an rb_intern on the value after the `$`.
2973 char *char_ptr = (char *)(node->location.start) + 1;
2974 ID backref_val = INT2FIX(rb_intern2(char_ptr, 1)) << 1 | 1;
2975 ADD_INSN2(ret, &dummy_line_node, getspecial, INT2FIX(1), backref_val);
2976 }
2977 return;
2978 }
2979 case PM_BEGIN_NODE: {
2980 pm_begin_node_t *begin_node = (pm_begin_node_t *) node;
2981 rb_iseq_t *child_iseq;
2982 LABEL *lstart = NEW_LABEL(lineno);
2983 LABEL *lend = NEW_LABEL(lineno);
2984 LABEL *lcont = NEW_LABEL(lineno);
2985
2986
2987 if (begin_node->rescue_clause) {
2988 pm_scope_node_t rescue_scope_node;
2989 pm_scope_node_init((pm_node_t *)begin_node->rescue_clause, &rescue_scope_node, scope_node, parser);
2990
2991 rb_iseq_t *rescue_iseq = NEW_CHILD_ISEQ(rescue_scope_node,
2992 rb_str_concat(rb_str_new2("rescue in"),
2993 ISEQ_BODY(iseq)->location.label),
2994 ISEQ_TYPE_RESCUE, 1);
2995 lstart->rescued = LABEL_RESCUE_BEG;
2996 lend->rescued = LABEL_RESCUE_END;
2997 ADD_LABEL(ret, lstart);
2998 bool prev_in_rescue = ISEQ_COMPILE_DATA(iseq)->in_rescue;
2999 ISEQ_COMPILE_DATA(iseq)->in_rescue = true;
3000 if (begin_node->statements) {
3001 PM_COMPILE_NOT_POPPED((pm_node_t *)begin_node->statements);
3002 }
3003 else {
3004 PM_PUTNIL;
3005 }
3006 ISEQ_COMPILE_DATA(iseq)->in_rescue = prev_in_rescue;
3007
3008 if (begin_node->else_clause) {
3009 PM_POP_UNLESS_POPPED;
3010 PM_COMPILE((pm_node_t *)begin_node->else_clause);
3011 }
3012
3013 ADD_LABEL(ret, lend);
3014 PM_NOP;
3015 ADD_LABEL(ret, lcont);
3016
3017 PM_POP_IF_POPPED;
3018 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue_iseq, lcont);
3019 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
3020 }
3021 if (begin_node->ensure_clause) {
3022 LABEL *estart = NEW_LABEL(lineno);
3023 LABEL *eend = NEW_LABEL(lineno);
3024 LABEL *econt = NEW_LABEL(lineno);
3025 ADD_LABEL(ret, estart);
3026 if (!begin_node->rescue_clause) {
3027 if (begin_node->statements) {
3028 PM_COMPILE((pm_node_t *)begin_node->statements);
3029 }
3030 else {
3031 PM_PUTNIL_UNLESS_POPPED;
3032 }
3033 }
3034 ADD_LABEL(ret, eend);
3035 if (!popped) {
3036 PM_NOP;
3037 }
3038 pm_statements_node_t *statements = begin_node->ensure_clause->statements;
3039 if (statements) {
3040 PM_COMPILE((pm_node_t *)statements);
3041 ADD_LABEL(ret, econt);
3042 PM_POP_UNLESS_POPPED;
3043 }
3044
3045 struct ensure_range er;
3047 struct ensure_range *erange;
3048
3049 er.begin = estart;
3050 er.end = eend;
3051 er.next = 0;
3052 push_ensure_entry(iseq, &enl, &er, (void *)begin_node->ensure_clause);
3053
3054 pm_scope_node_t next_scope_node;
3055 pm_scope_node_init((pm_node_t *)begin_node->ensure_clause, &next_scope_node, scope_node, parser);
3056
3057 child_iseq = NEW_CHILD_ISEQ(next_scope_node,
3058 rb_str_new2("ensure in"),
3059 ISEQ_TYPE_ENSURE, lineno);
3060 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
3061
3062
3063 erange = ISEQ_COMPILE_DATA(iseq)->ensure_node_stack->erange;
3064 if (estart->link.next != &eend->link) {
3065 while (erange) {
3066 ADD_CATCH_ENTRY(CATCH_TYPE_ENSURE, erange->begin, erange->end, child_iseq, econt);
3067 erange = erange->next;
3068 }
3069 }
3070 }
3071
3072 if (!begin_node->rescue_clause && !begin_node->ensure_clause) {
3073 ADD_LABEL(ret, lstart);
3074 if (begin_node->statements) {
3075 PM_COMPILE((pm_node_t *)begin_node->statements);
3076 }
3077 else {
3078 PM_PUTNIL_UNLESS_POPPED;
3079 }
3080 ADD_LABEL(ret, lend);
3081 }
3082 return;
3083 }
3085 pm_block_argument_node_t *block_argument_node = (pm_block_argument_node_t *) node;
3086 if (block_argument_node->expression) {
3087 PM_COMPILE(block_argument_node->expression);
3088 }
3089 return;
3090 }
3091 case PM_BREAK_NODE: {
3092 pm_break_node_t *break_node = (pm_break_node_t *) node;
3093 unsigned long throw_flag = 0;
3094 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
3095 /* while/until */
3096 LABEL *splabel = NEW_LABEL(0);
3097 ADD_LABEL(ret, splabel);
3098 ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
3099 if (break_node->arguments) {
3100 PM_COMPILE_NOT_POPPED((pm_node_t *)break_node->arguments);
3101 }
3102 else {
3103 PM_PUTNIL;
3104 }
3105 ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
3106 ADD_ADJUST_RESTORE(ret, splabel);
3107
3108 PM_PUTNIL_UNLESS_POPPED;
3109 } else {
3110 const rb_iseq_t *ip = iseq;
3111
3112 while (ip) {
3113 if (!ISEQ_COMPILE_DATA(ip)) {
3114 ip = 0;
3115 break;
3116 }
3117
3118 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
3119 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
3120 }
3121 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
3122 throw_flag = 0;
3123 }
3124 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
3125 COMPILE_ERROR(ERROR_ARGS "Can't escape from eval with break");
3126 rb_bug("Can't escape from eval with break");
3127 }
3128 else {
3129 ip = ISEQ_BODY(ip)->parent_iseq;
3130 continue;
3131 }
3132
3133 /* escape from block */
3134 if (break_node->arguments) {
3135 PM_COMPILE_NOT_POPPED((pm_node_t *)break_node->arguments);
3136 }
3137 else {
3138 PM_PUTNIL;
3139 }
3140
3141 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(throw_flag | TAG_BREAK));
3142 PM_POP_IF_POPPED;
3143
3144 return;
3145 }
3146 COMPILE_ERROR(ERROR_ARGS "Invalid break");
3147 rb_bug("Invalid break");
3148 }
3149 return;
3150 }
3151 case PM_CALL_NODE: {
3152 pm_call_node_t *call_node = (pm_call_node_t *) node;
3153 LABEL *start = NEW_LABEL(lineno);
3154
3155 if (call_node->block) {
3156 ADD_LABEL(ret, start);
3157 }
3158
3159 ID method_id = pm_constant_id_lookup(scope_node, call_node->name);
3161 if (!popped) {
3162 PM_PUTNIL;
3163 }
3164 }
3165
3166 if (call_node->receiver == NULL) {
3167 PM_PUTSELF;
3168 } else {
3169 PM_COMPILE_NOT_POPPED(call_node->receiver);
3170 }
3171
3172 pm_compile_call(iseq, call_node, ret, src, popped, scope_node, method_id, start);
3173 return;
3174 }
3176 pm_call_and_write_node_t *call_and_write_node = (pm_call_and_write_node_t*) node;
3177
3178 bool safe_nav = node->flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION;
3179
3180 pm_compile_call_and_or_write_node(true, call_and_write_node->receiver, call_and_write_node->value, call_and_write_node->write_name, call_and_write_node->read_name, safe_nav, ret, iseq, lineno, src, popped, scope_node);
3181
3182 return;
3183 }
3184 case PM_CALL_OR_WRITE_NODE: {
3185 pm_call_or_write_node_t *call_or_write_node = (pm_call_or_write_node_t*) node;
3186 bool safe_nav = node->flags & PM_CALL_NODE_FLAGS_SAFE_NAVIGATION;
3187
3188 pm_compile_call_and_or_write_node(false, call_or_write_node->receiver, call_or_write_node->value, call_or_write_node->write_name, call_or_write_node->read_name, safe_nav, ret, iseq, lineno, src, popped, scope_node);
3189
3190 return;
3191 }
3193 pm_call_operator_write_node_t *call_operator_write_node = (pm_call_operator_write_node_t*) node;
3194
3195 NODE dummy_line_node = generate_dummy_line_node(lineno, lineno);
3196
3197 int flag = 0;
3198
3199 if (PM_NODE_TYPE_P(call_operator_write_node->receiver, PM_SELF_NODE)) {
3200 flag = VM_CALL_FCALL;
3201 }
3202
3203 PM_COMPILE_NOT_POPPED(call_operator_write_node->receiver);
3204
3205 ID write_name_id = pm_constant_id_lookup(scope_node, call_operator_write_node->write_name);
3206 ID read_name_id = pm_constant_id_lookup(scope_node, call_operator_write_node->read_name);
3207 ID operator_id = pm_constant_id_lookup(scope_node, call_operator_write_node->operator);
3208 PM_DUP;
3209
3210 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, read_name_id, INT2FIX(0), INT2FIX(flag));
3211
3212 PM_COMPILE_NOT_POPPED(call_operator_write_node->value);
3213 ADD_SEND(ret, &dummy_line_node, operator_id, INT2FIX(1));
3214
3215 if (!popped) {
3216 PM_SWAP;
3217 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
3218 }
3219
3220 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, write_name_id, INT2FIX(1), INT2FIX(flag));
3221 PM_POP;
3222
3223 return;
3224 }
3225 case PM_CASE_NODE: {
3226 pm_case_node_t *case_node = (pm_case_node_t *)node;
3227 bool has_predicate = case_node->predicate;
3228 if (has_predicate) {
3229 PM_COMPILE_NOT_POPPED(case_node->predicate);
3230 }
3231 LABEL *end_label = NEW_LABEL(lineno);
3232
3233 pm_node_list_t conditions = case_node->conditions;
3234
3235 LABEL **conditions_labels = (LABEL **)ALLOC_N(VALUE, conditions.size + 1);
3236 LABEL *label;
3237
3238 for (size_t i = 0; i < conditions.size; i++) {
3239 label = NEW_LABEL(lineno);
3240 conditions_labels[i] = label;
3241 if (has_predicate) {
3242 pm_when_node_t *when_node = (pm_when_node_t *)conditions.nodes[i];
3243
3244 for (size_t i = 0; i < when_node->conditions.size; i++) {
3245 PM_COMPILE_NOT_POPPED(when_node->conditions.nodes[i]);
3246 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
3247 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idEqq, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
3248 ADD_INSNL(ret, &dummy_line_node, branchif, label);
3249 }
3250 }
3251 else {
3252 ADD_INSNL(ret, &dummy_line_node, jump, label);
3253 PM_PUTNIL;
3254 }
3255 }
3256
3257 if (has_predicate) {
3258 PM_POP;
3259
3260 if (case_node->consequent) {
3261 PM_COMPILE((pm_node_t *)case_node->consequent);
3262 }
3263 else {
3264 PM_PUTNIL_UNLESS_POPPED;
3265 }
3266 }
3267
3268 ADD_INSNL(ret, &dummy_line_node, jump, end_label);
3269
3270 for (size_t i = 0; i < conditions.size; i++) {
3271 label = conditions_labels[i];
3272 ADD_LABEL(ret, label);
3273 if (has_predicate) {
3274 PM_POP;
3275 }
3276
3277 pm_while_node_t *condition_node = (pm_while_node_t *)conditions.nodes[i];
3278 if (condition_node->statements) {
3279 PM_COMPILE((pm_node_t *)condition_node->statements);
3280 }
3281 else {
3282 PM_PUTNIL_UNLESS_POPPED;
3283 }
3284
3285 ADD_INSNL(ret, &dummy_line_node, jump, end_label);
3286 }
3287
3288 ADD_LABEL(ret, end_label);
3289 return;
3290 }
3291 case PM_CASE_MATCH_NODE: {
3292 // If you use the `case` keyword to create a case match node, it will
3293 // match against all of the `in` clauses until it finds one that
3294 // matches. If it doesn't find one, it can optionally fall back to an
3295 // `else` clause. If none is present and a match wasn't found, it will
3296 // raise an appropriate error.
3297 const pm_case_match_node_t *cast = (const pm_case_match_node_t *) node;
3298
3299 // This is the anchor that we will compile the bodies of the various
3300 // `in` nodes into. We'll make sure that the patterns that are compiled
3301 // jump into the correct spots within this anchor.
3302 DECL_ANCHOR(body_seq);
3303 INIT_ANCHOR(body_seq);
3304
3305 // This is the anchor that we will compile the patterns of the various
3306 // `in` nodes into. If a match is found, they will need to jump into the
3307 // body_seq anchor to the correct spot.
3308 DECL_ANCHOR(cond_seq);
3309 INIT_ANCHOR(cond_seq);
3310
3311 // This label is used to indicate the end of the entire node. It is
3312 // jumped to after the entire stack is cleaned up.
3313 LABEL *end_label = NEW_LABEL(lineno);
3314
3315 // This label is used as the fallback for the case match. If no match is
3316 // found, then we jump to this label. This is either an `else` clause or
3317 // an error handler.
3318 LABEL *else_label = NEW_LABEL(lineno);
3319
3320 // We're going to use this to uniquely identify each branch so that we
3321 // can track coverage information.
3322 int branch_id = 0;
3323 // VALUE branches = 0;
3324
3325 // If there is only one pattern, then the behavior changes a bit. It
3326 // effectively gets treated as a match required node (this is how it is
3327 // represented in the other parser).
3328 bool in_single_pattern = cast->consequent == NULL && cast->conditions.size == 1;
3329
3330 // First, we're going to push a bunch of stuff onto the stack that is
3331 // going to serve as our scratch space.
3332 if (in_single_pattern) {
3333 ADD_INSN(ret, &dummy_line_node, putnil); // key error key
3334 ADD_INSN(ret, &dummy_line_node, putnil); // key error matchee
3335 ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse); // key error?
3336 ADD_INSN(ret, &dummy_line_node, putnil); // error string
3337 }
3338
3339 // Now we're going to compile the value to match against.
3340 ADD_INSN(ret, &dummy_line_node, putnil); // deconstruct cache
3341 PM_COMPILE_NOT_POPPED(cast->predicate);
3342
3343 // Next, we'll loop through every in clause and compile its body into
3344 // the body_seq anchor and its pattern into the cond_seq anchor. We'll
3345 // make sure the pattern knows how to jump correctly into the body if it
3346 // finds a match.
3347 for (size_t index = 0; index < cast->conditions.size; index++) {
3348 const pm_node_t *condition = cast->conditions.nodes[index];
3349 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3350
3351 const pm_in_node_t *in_node = (const pm_in_node_t *) condition;
3352
3353 pm_line_node_t in_line;
3354 pm_line_node(&in_line, scope_node, (const pm_node_t *) in_node);
3355
3356 pm_line_node_t pattern_line;
3357 pm_line_node(&pattern_line, scope_node, (const pm_node_t *) in_node->pattern);
3358
3359 if (branch_id) {
3360 ADD_INSN(body_seq, &in_line.node, putnil);
3361 }
3362
3363 LABEL *body_label = NEW_LABEL(in_line.lineno);
3364 ADD_LABEL(body_seq, body_label);
3365 ADD_INSN1(body_seq, &in_line.node, adjuststack, INT2FIX(in_single_pattern ? 6 : 2));
3366
3367 // TODO: We need to come back to this and enable trace branch
3368 // coverage. At the moment we can't call this function because it
3369 // accepts a NODE* and not a pm_node_t*.
3370 // add_trace_branch_coverage(iseq, body_seq, in_node->statements || in, branch_id++, "in", branches);
3371
3372 branch_id++;
3373 if (in_node->statements != NULL) {
3374 PM_COMPILE_INTO_ANCHOR(body_seq, (const pm_node_t *) in_node->statements);
3375 } else if (!popped) {
3376 ADD_INSN(body_seq, &in_line.node, putnil);
3377 }
3378
3379 ADD_INSNL(body_seq, &in_line.node, jump, end_label);
3380 LABEL *next_pattern_label = NEW_LABEL(pattern_line.lineno);
3381
3382 ADD_INSN(cond_seq, &pattern_line.node, dup);
3383 pm_compile_pattern(iseq, scope_node, in_node->pattern, cond_seq, src, body_label, next_pattern_label, in_single_pattern, false, true, 2);
3384 ADD_LABEL(cond_seq, next_pattern_label);
3385 LABEL_UNREMOVABLE(next_pattern_label);
3386 }
3387
3388 if (cast->consequent != NULL) {
3389 // If we have an `else` clause, then this becomes our fallback (and
3390 // there is no need to compile in code to potentially raise an
3391 // error).
3392 const pm_else_node_t *else_node = (const pm_else_node_t *) cast->consequent;
3393
3394 ADD_LABEL(cond_seq, else_label);
3395 ADD_INSN(cond_seq, &dummy_line_node, pop);
3396 ADD_INSN(cond_seq, &dummy_line_node, pop);
3397
3398 // TODO: trace branch coverage
3399 // add_trace_branch_coverage(iseq, cond_seq, cast->consequent, branch_id, "else", branches);
3400
3401 if (else_node->statements != NULL) {
3402 PM_COMPILE_INTO_ANCHOR(cond_seq, (const pm_node_t *) else_node->statements);
3403 } else if (!popped) {
3404 ADD_INSN(cond_seq, &dummy_line_node, putnil);
3405 }
3406
3407 ADD_INSNL(cond_seq, &dummy_line_node, jump, end_label);
3408 ADD_INSN(cond_seq, &dummy_line_node, putnil);
3409 if (popped) {
3410 ADD_INSN(cond_seq, &dummy_line_node, putnil);
3411 }
3412 } else {
3413 // Otherwise, if we do not have an `else` clause, we will compile in
3414 // the code to handle raising an appropriate error.
3415 ADD_LABEL(cond_seq, else_label);
3416
3417 // TODO: trace branch coverage
3418 // add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
3419
3420 if (in_single_pattern) {
3421 pm_compile_pattern_error_handler(iseq, scope_node, node, cond_seq, src, end_label, popped);
3422 } else {
3423 ADD_INSN1(cond_seq, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
3424 ADD_INSN1(cond_seq, &dummy_line_node, putobject, rb_eNoMatchingPatternError);
3425 ADD_INSN1(cond_seq, &dummy_line_node, topn, INT2FIX(2));
3426 ADD_SEND(cond_seq, &dummy_line_node, id_core_raise, INT2FIX(2));
3427
3428 ADD_INSN1(cond_seq, &dummy_line_node, adjuststack, INT2FIX(3));
3429 if (!popped) ADD_INSN(cond_seq, &dummy_line_node, putnil);
3430 ADD_INSNL(cond_seq, &dummy_line_node, jump, end_label);
3431 ADD_INSN1(cond_seq, &dummy_line_node, dupn, INT2FIX(1));
3432 if (popped) ADD_INSN(cond_seq, &dummy_line_node, putnil);
3433 }
3434 }
3435
3436 // At the end of all of this compilation, we will add the code for the
3437 // conditions first, then the various bodies, then mark the end of the
3438 // entire sequence with the end label.
3439 ADD_SEQ(ret, cond_seq);
3440 ADD_SEQ(ret, body_seq);
3441 ADD_LABEL(ret, end_label);
3442
3443 return;
3444 }
3445 case PM_CLASS_NODE: {
3446 pm_class_node_t *class_node = (pm_class_node_t *)node;
3447 pm_scope_node_t next_scope_node;
3448 pm_scope_node_init((pm_node_t *)class_node, &next_scope_node, scope_node, parser);
3449
3450 ID class_id = pm_constant_id_lookup(scope_node, class_node->name);
3451
3452 VALUE class_name = rb_str_freeze(rb_sprintf("<class:%"PRIsVALUE">", rb_id2str(class_id)));
3453
3454 const rb_iseq_t *class_iseq = NEW_CHILD_ISEQ(next_scope_node, class_name, ISEQ_TYPE_CLASS, lineno);
3455
3456 // TODO: Once we merge constant path nodes correctly, fix this flag
3457 const int flags = VM_DEFINECLASS_TYPE_CLASS |
3458 (class_node->superclass ? VM_DEFINECLASS_FLAG_HAS_SUPERCLASS : 0) |
3459 pm_compile_class_path(ret, iseq, class_node->constant_path, &dummy_line_node, src, false, scope_node);
3460
3461 if (class_node->superclass) {
3462 PM_COMPILE_NOT_POPPED(class_node->superclass);
3463 }
3464 else {
3465 PM_PUTNIL;
3466 }
3467
3468 ADD_INSN3(ret, &dummy_line_node, defineclass, ID2SYM(class_id), class_iseq, INT2FIX(flags));
3469 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
3470
3471 PM_POP_IF_POPPED;
3472 return;
3473 }
3475 pm_class_variable_and_write_node_t *class_variable_and_write_node = (pm_class_variable_and_write_node_t*) node;
3476
3477 LABEL *end_label = NEW_LABEL(lineno);
3478
3479 ID class_variable_name_id = pm_constant_id_lookup(scope_node, class_variable_and_write_node->name);
3480 VALUE class_variable_name_val = ID2SYM(class_variable_name_id);
3481
3482 ADD_INSN2(ret, &dummy_line_node, getclassvariable,
3483 class_variable_name_val,
3484 get_cvar_ic_value(iseq, class_variable_name_id));
3485
3486 PM_DUP_UNLESS_POPPED;
3487
3488 ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
3489
3490 PM_POP_UNLESS_POPPED;
3491
3492 PM_COMPILE_NOT_POPPED(class_variable_and_write_node->value);
3493
3494 PM_DUP_UNLESS_POPPED;
3495
3496 ADD_INSN2(ret, &dummy_line_node, setclassvariable,
3497 class_variable_name_val,
3498 get_cvar_ic_value(iseq, class_variable_name_id));
3499 ADD_LABEL(ret, end_label);
3500
3501 return;
3502 }
3504 pm_class_variable_operator_write_node_t *class_variable_operator_write_node = (pm_class_variable_operator_write_node_t*) node;
3505
3506 ID class_variable_name_id = pm_constant_id_lookup(scope_node, class_variable_operator_write_node->name);
3507 VALUE class_variable_name_val = ID2SYM(class_variable_name_id);
3508
3509 ADD_INSN2(ret, &dummy_line_node, getclassvariable,
3510 class_variable_name_val,
3511 get_cvar_ic_value(iseq, class_variable_name_id));
3512
3513 PM_COMPILE_NOT_POPPED(class_variable_operator_write_node->value);
3514 ID method_id = pm_constant_id_lookup(scope_node, class_variable_operator_write_node->operator);
3515
3516 int flags = VM_CALL_ARGS_SIMPLE;
3517 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
3518
3519 PM_DUP_UNLESS_POPPED;
3520
3521 ADD_INSN2(ret, &dummy_line_node, setclassvariable,
3522 class_variable_name_val,
3523 get_cvar_ic_value(iseq, class_variable_name_id));
3524
3525 return;
3526 }
3528 pm_class_variable_or_write_node_t *class_variable_or_write_node = (pm_class_variable_or_write_node_t*) node;
3529
3530 LABEL *end_label = NEW_LABEL(lineno);
3531 LABEL *start_label = NEW_LABEL(lineno);
3532
3533 ADD_INSN(ret, &dummy_line_node, putnil);
3534 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CVAR),
3535 ID2SYM(pm_constant_id_lookup(scope_node, class_variable_or_write_node->name)), Qtrue);
3536
3537 ADD_INSNL(ret, &dummy_line_node, branchunless, start_label);
3538
3539 ID class_variable_name_id = pm_constant_id_lookup(scope_node, class_variable_or_write_node->name);
3540 VALUE class_variable_name_val = ID2SYM(class_variable_name_id);
3541
3542 ADD_INSN2(ret, &dummy_line_node, getclassvariable,
3543 class_variable_name_val,
3544 get_cvar_ic_value(iseq, class_variable_name_id));
3545
3546 PM_DUP_UNLESS_POPPED;
3547
3548 ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
3549
3550 PM_POP_UNLESS_POPPED;
3551 ADD_LABEL(ret, start_label);
3552
3553 PM_COMPILE_NOT_POPPED(class_variable_or_write_node->value);
3554
3555 PM_DUP_UNLESS_POPPED;
3556
3557 ADD_INSN2(ret, &dummy_line_node, setclassvariable,
3558 class_variable_name_val,
3559 get_cvar_ic_value(iseq, class_variable_name_id));
3560 ADD_LABEL(ret, end_label);
3561
3562 return;
3563 }
3565 if (!popped) {
3566 pm_class_variable_read_node_t *class_variable_read_node = (pm_class_variable_read_node_t *) node;
3567 ID cvar_name = pm_constant_id_lookup(scope_node, class_variable_read_node->name);
3568 ADD_INSN2(ret, &dummy_line_node, getclassvariable, ID2SYM(cvar_name), get_cvar_ic_value(iseq, cvar_name));
3569 }
3570 return;
3571 }
3574 ID cvar_name = pm_constant_id_lookup(scope_node, write_node->name);
3575 ADD_INSN2(ret, &dummy_line_node, setclassvariable, ID2SYM(cvar_name), get_cvar_ic_value(iseq, cvar_name));
3576 return;
3577 }
3580 PM_COMPILE_NOT_POPPED(write_node->value);
3581 PM_DUP_UNLESS_POPPED;
3582
3583 ID cvar_name = pm_constant_id_lookup(scope_node, write_node->name);
3584 ADD_INSN2(ret, &dummy_line_node, setclassvariable, ID2SYM(cvar_name), get_cvar_ic_value(iseq, cvar_name));
3585 return;
3586 }
3587 case PM_CONSTANT_PATH_NODE: {
3588 pm_constant_path_node_t *constant_path_node = (pm_constant_path_node_t*) node;
3589 if (constant_path_node->parent) {
3590 PM_COMPILE_NOT_POPPED(constant_path_node->parent);
3591 } else {
3592 ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
3593 }
3594 ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
3595
3596 assert(PM_NODE_TYPE_P(constant_path_node->child, PM_CONSTANT_READ_NODE));
3597 pm_constant_read_node_t *child = (pm_constant_read_node_t *) constant_path_node->child;
3598
3599 ADD_INSN1(ret, &dummy_line_node, getconstant, ID2SYM(pm_constant_id_lookup(scope_node, child->name)));
3600 PM_POP_IF_POPPED;
3601 return;
3602 }
3604 pm_constant_path_and_write_node_t *constant_path_and_write_node = (pm_constant_path_and_write_node_t*) node;
3605
3606 LABEL *lfin = NEW_LABEL(lineno);
3607
3608 pm_constant_path_node_t *target = constant_path_and_write_node->target;
3609 if (target->parent) {
3610 PM_COMPILE_NOT_POPPED(target->parent);
3611 }
3612 else {
3613 ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
3614 }
3615
3617 VALUE child_name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
3618
3619 PM_DUP;
3620 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
3621 ADD_INSN1(ret, &dummy_line_node, getconstant, child_name);
3622
3623 PM_DUP_UNLESS_POPPED;
3624 ADD_INSNL(ret, &dummy_line_node, branchunless, lfin);
3625
3626 PM_POP_UNLESS_POPPED;
3627 PM_COMPILE_NOT_POPPED(constant_path_and_write_node->value);
3628
3629 if (popped) {
3630 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
3631 }
3632 else {
3633 ADD_INSN1(ret, &dummy_line_node, dupn, INT2FIX(2));
3634 PM_SWAP;
3635 }
3636
3637 ADD_INSN1(ret, &dummy_line_node, setconstant, child_name);
3638 ADD_LABEL(ret, lfin);
3639
3640 PM_SWAP_UNLESS_POPPED;
3641 PM_POP;
3642
3643 return;
3644 }
3646 pm_constant_path_or_write_node_t *constant_path_or_write_node = (pm_constant_path_or_write_node_t*) node;
3647
3648 LABEL *lassign = NEW_LABEL(lineno);
3649 LABEL *lfin = NEW_LABEL(lineno);
3650
3651 pm_constant_path_node_t *target = constant_path_or_write_node->target;
3652 if (target->parent) {
3653 PM_COMPILE_NOT_POPPED(target->parent);
3654 }
3655 else {
3656 ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
3657 }
3658
3660 VALUE child_name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
3661
3662 PM_DUP;
3663 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CONST_FROM), child_name, Qtrue);
3664 ADD_INSNL(ret, &dummy_line_node, branchunless, lassign);
3665
3666 PM_DUP;
3667 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
3668 ADD_INSN1(ret, &dummy_line_node, getconstant, child_name);
3669
3670 PM_DUP_UNLESS_POPPED;
3671 ADD_INSNL(ret, &dummy_line_node, branchif, lfin);
3672
3673 PM_POP_UNLESS_POPPED;
3674 ADD_LABEL(ret, lassign);
3675 PM_COMPILE_NOT_POPPED(constant_path_or_write_node->value);
3676
3677 if (popped) {
3678 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
3679 }
3680 else {
3681 ADD_INSN1(ret, &dummy_line_node, dupn, INT2FIX(2));
3682 PM_SWAP;
3683 }
3684
3685 ADD_INSN1(ret, &dummy_line_node, setconstant, child_name);
3686 ADD_LABEL(ret, lfin);
3687
3688 PM_SWAP_UNLESS_POPPED;
3689 PM_POP;
3690
3691 return;
3692 }
3694 pm_constant_path_operator_write_node_t *constant_path_operator_write_node = (pm_constant_path_operator_write_node_t*) node;
3695
3696 pm_constant_path_node_t *target = constant_path_operator_write_node->target;
3697 if (target->parent) {
3698 PM_COMPILE_NOT_POPPED(target->parent);
3699 }
3700 else {
3701 ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
3702 }
3703
3704 PM_DUP;
3705 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
3706
3708 VALUE child_name = ID2SYM(pm_constant_id_lookup(scope_node, child->name));
3709 ADD_INSN1(ret, &dummy_line_node, getconstant, child_name);
3710
3711 PM_COMPILE_NOT_POPPED(constant_path_operator_write_node->value);
3712 ID method_id = pm_constant_id_lookup(scope_node, constant_path_operator_write_node->operator);
3713 ADD_CALL(ret, &dummy_line_node, method_id, INT2FIX(1));
3714 PM_SWAP;
3715
3716 if (!popped) {
3717 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
3718 PM_SWAP;
3719 }
3720
3721 ADD_INSN1(ret, &dummy_line_node, setconstant, child_name);
3722 return ;
3723 }
3726
3727 if (cast->parent) {
3728 PM_COMPILE(cast->parent);
3729 }
3730
3731 return;
3732 }
3734 pm_constant_path_write_node_t *constant_path_write_node = (pm_constant_path_write_node_t*) node;
3735 if (constant_path_write_node->target->parent) {
3736 PM_COMPILE_NOT_POPPED((pm_node_t *)constant_path_write_node->target->parent);
3737 }
3738 else {
3739 ADD_INSN1(ret, &dummy_line_node, putobject, rb_cObject);
3740 }
3741 PM_COMPILE_NOT_POPPED(constant_path_write_node->value);
3742 if (!popped) {
3743 PM_SWAP;
3744 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(1));
3745 }
3746 PM_SWAP;
3747 VALUE constant_name = ID2SYM(pm_constant_id_lookup(scope_node,
3748 ((pm_constant_read_node_t *)constant_path_write_node->target->child)->name));
3749 ADD_INSN1(ret, &dummy_line_node, setconstant, constant_name);
3750 return;
3751 }
3752 case PM_CONSTANT_READ_NODE: {
3753 pm_constant_read_node_t *constant_read_node = (pm_constant_read_node_t *) node;
3754 PM_PUTNIL;
3755 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
3756 ADD_INSN1(ret, &dummy_line_node, getconstant, ID2SYM(pm_constant_id_lookup(scope_node, constant_read_node->name)));
3757 PM_POP_IF_POPPED;
3758 return;
3759 }
3761 pm_constant_and_write_node_t *constant_and_write_node = (pm_constant_and_write_node_t*) node;
3762
3763 LABEL *end_label = NEW_LABEL(lineno);
3764
3765 VALUE constant_name = ID2SYM(pm_constant_id_lookup(scope_node, constant_and_write_node->name));
3766
3767 PM_PUTNIL;
3768 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
3769 ADD_INSN1(ret, &dummy_line_node, getconstant, constant_name);
3770 PM_DUP_UNLESS_POPPED;
3771
3772 ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
3773
3774 PM_POP_UNLESS_POPPED;
3775
3776 PM_COMPILE_NOT_POPPED(constant_and_write_node->value);
3777
3778 PM_DUP_UNLESS_POPPED;
3779
3780 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
3781 ADD_INSN1(ret, &dummy_line_node, setconstant, constant_name);
3782 ADD_LABEL(ret, end_label);
3783
3784 return;
3785 }
3787 pm_constant_operator_write_node_t *constant_operator_write_node = (pm_constant_operator_write_node_t*) node;
3788
3789 ID constant_name = pm_constant_id_lookup(scope_node, constant_operator_write_node->name);
3790 PM_PUTNIL;
3791 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
3792 ADD_INSN1(ret, &dummy_line_node, getconstant, ID2SYM(constant_name));
3793
3794 PM_COMPILE_NOT_POPPED(constant_operator_write_node->value);
3795 ID method_id = pm_constant_id_lookup(scope_node, constant_operator_write_node->operator);
3796
3797 int flags = VM_CALL_ARGS_SIMPLE;
3798 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
3799
3800 PM_DUP_UNLESS_POPPED;
3801
3802 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
3803 ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(constant_name));
3804
3805 return;
3806 }
3808 pm_constant_or_write_node_t *constant_or_write_node = (pm_constant_or_write_node_t*) node;
3809
3810 LABEL *set_label= NEW_LABEL(lineno);
3811 LABEL *end_label = NEW_LABEL(lineno);
3812
3813 PM_PUTNIL;
3814 VALUE constant_name = ID2SYM(pm_constant_id_lookup(scope_node, constant_or_write_node->name));
3815
3816 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_CONST), constant_name, Qtrue);
3817
3818 ADD_INSNL(ret, &dummy_line_node, branchunless, set_label);
3819
3820 PM_PUTNIL;
3821 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
3822 ADD_INSN1(ret, &dummy_line_node, getconstant, constant_name);
3823
3824 PM_DUP_UNLESS_POPPED;
3825
3826 ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
3827
3828 PM_POP_UNLESS_POPPED;
3829
3830 ADD_LABEL(ret, set_label);
3831 PM_COMPILE_NOT_POPPED(constant_or_write_node->value);
3832
3833 PM_DUP_UNLESS_POPPED;
3834
3835 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
3836 ADD_INSN1(ret, &dummy_line_node, setconstant, constant_name);
3837 ADD_LABEL(ret, end_label);
3838
3839 return;
3840 }
3842 pm_constant_target_node_t *constant_write_node = (pm_constant_target_node_t *) node;
3843 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
3844 ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(pm_constant_id_lookup(scope_node, constant_write_node->name)));
3845 return;
3846 }
3848 pm_constant_write_node_t *constant_write_node = (pm_constant_write_node_t *) node;
3849 PM_COMPILE_NOT_POPPED(constant_write_node->value);
3850
3851 PM_DUP_UNLESS_POPPED;
3852
3853 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
3854 ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(pm_constant_id_lookup(scope_node, constant_write_node->name)));
3855 return;
3856 }
3857 case PM_DEF_NODE: {
3858 pm_def_node_t *def_node = (pm_def_node_t *) node;
3859 ID method_name = pm_constant_id_lookup(scope_node, def_node->name);
3860 pm_scope_node_t next_scope_node;
3861 pm_scope_node_init((pm_node_t *)def_node, &next_scope_node, scope_node, parser);
3862 rb_iseq_t *method_iseq = NEW_ISEQ(next_scope_node, rb_id2str(method_name), ISEQ_TYPE_METHOD, lineno);
3863
3864 if (def_node->receiver) {
3865 PM_COMPILE_NOT_POPPED(def_node->receiver);
3866 ADD_INSN2(ret, &dummy_line_node, definesmethod, ID2SYM(method_name), method_iseq);
3867 }
3868 else {
3869 ADD_INSN2(ret, &dummy_line_node, definemethod, ID2SYM(method_name), method_iseq);
3870 }
3871 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
3872
3873 if (!popped) {
3874 ADD_INSN1(ret, &dummy_line_node, putobject, ID2SYM(method_name));
3875 }
3876 return;
3877 }
3878 case PM_DEFINED_NODE: {
3879 pm_defined_node_t *defined_node = (pm_defined_node_t *)node;
3880 pm_compile_defined_expr(iseq, defined_node->value, ret, src, popped, scope_node, dummy_line_node, lineno, false);
3881 return;
3882 }
3884 pm_embedded_statements_node_t *embedded_statements_node = (pm_embedded_statements_node_t *)node;
3885
3886 if (embedded_statements_node->statements) {
3887 PM_COMPILE((pm_node_t *) (embedded_statements_node->statements));
3888 }
3889 else {
3890 PM_PUTNIL;
3891 }
3892
3893 PM_POP_IF_POPPED;
3894 // TODO: Concatenate the strings that exist here
3895 return;
3896 }
3899 PM_COMPILE(embedded_node->variable);
3900 return;
3901 }
3902 case PM_FALSE_NODE:
3903 if (!popped) {
3904 ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
3905 }
3906 return;
3907 case PM_ENSURE_NODE: {
3908 pm_ensure_node_t *ensure_node = (pm_ensure_node_t *)node;
3909
3910 LABEL *start = NEW_LABEL(lineno);
3911 LABEL *end = NEW_LABEL(lineno);
3912 ADD_LABEL(ret, start);
3913 if (ensure_node->statements) {
3914 ISEQ_COMPILE_DATA(iseq)->end_label = end;
3915 PM_COMPILE((pm_node_t *)ensure_node->statements);
3916 }
3917 ADD_LABEL(ret, end);
3918 }
3919 case PM_ELSE_NODE: {
3920 pm_else_node_t *cast = (pm_else_node_t *)node;
3921 if (cast->statements) {
3922 PM_COMPILE((pm_node_t *)cast->statements);
3923 }
3924 else {
3925 PM_PUTNIL_UNLESS_POPPED;
3926 }
3927 return;
3928 }
3929 case PM_FLIP_FLOP_NODE: {
3930 pm_flip_flop_node_t *flip_flop_node = (pm_flip_flop_node_t *)node;
3931
3932 LABEL *final_label = NEW_LABEL(lineno);
3933 LABEL *then_label = NEW_LABEL(lineno);
3934 LABEL *else_label = NEW_LABEL(lineno);
3935
3936 pm_compile_flip_flop(flip_flop_node, else_label, then_label, iseq, lineno, ret, src, popped, scope_node);
3937
3938 ADD_LABEL(ret, then_label);
3939 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
3940 ADD_INSNL(ret, &dummy_line_node, jump, final_label);
3941 ADD_LABEL(ret, else_label);
3942 ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
3943 ADD_LABEL(ret, final_label);
3944 return;
3945 }
3946 case PM_FLOAT_NODE: {
3947 if (!popped) {
3948 ADD_INSN1(ret, &dummy_line_node, putobject, parse_float(node));
3949 }
3950 return;
3951 }
3952 case PM_FOR_NODE: {
3953 pm_for_node_t *for_node = (pm_for_node_t *)node;
3954
3955 ISEQ_COMPILE_DATA(iseq)->catch_except_p = true;
3956
3957 const rb_iseq_t *child_iseq;
3958 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
3959
3960 LABEL *retry_label = NEW_LABEL(lineno);
3961 LABEL *retry_end_l = NEW_LABEL(lineno);
3962
3963 pm_scope_node_t next_scope_node;
3964 pm_scope_node_init((pm_node_t *)for_node, &next_scope_node, scope_node, parser);
3965
3966 pm_constant_id_list_t locals;
3967 pm_constant_id_list_init(&locals);
3968
3969 ADD_LABEL(ret, retry_label);
3970
3971 PM_COMPILE_NOT_POPPED(for_node->collection);
3972
3973 child_iseq = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
3974 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
3975 ADD_SEND_WITH_BLOCK(ret, &dummy_line_node, idEach, INT2FIX(0), child_iseq);
3976
3977 ADD_LABEL(ret, retry_end_l);
3978 PM_POP_IF_POPPED;
3979
3980 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
3981 ADD_CATCH_ENTRY(CATCH_TYPE_BREAK, retry_label, retry_end_l, child_iseq, retry_end_l);
3982 return;
3983 }
3985 rb_bug("Should never hit the forwarding arguments case directly\n");
3986 return;
3987 }
3989 pm_forwarding_super_node_t *forwarding_super_node = (pm_forwarding_super_node_t *) node;
3990 const rb_iseq_t *block = NULL;
3991 PM_PUTSELF;
3992 int flag = VM_CALL_ZSUPER | VM_CALL_SUPER | VM_CALL_FCALL;
3993
3994 if (forwarding_super_node->block) {
3995 pm_scope_node_t next_scope_node;
3996 pm_scope_node_init((pm_node_t *)forwarding_super_node->block, &next_scope_node, scope_node, parser);
3997 block = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
3998 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
3999 }
4000
4001 DECL_ANCHOR(args);
4002 INIT_ANCHOR(args);
4003
4004 struct rb_iseq_constant_body *const body = ISEQ_BODY(iseq);
4005
4006 const rb_iseq_t *local_iseq = body->local_iseq;
4007 const struct rb_iseq_constant_body *const local_body = ISEQ_BODY(local_iseq);
4008
4009 int argc = 0;
4010 int depth = get_lvar_level(iseq);
4011
4012 if (local_body->param.flags.has_lead) {
4013 /* required arguments */
4014 for (int i = 0; i < local_body->param.lead_num; i++) {
4015 int idx = local_body->local_table_size - i;
4016 ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
4017 }
4018 argc += local_body->param.lead_num;
4019 }
4020
4021
4022 if (local_body->param.flags.has_opt) {
4023 /* optional arguments */
4024 for (int j = 0; j < local_body->param.opt_num; j++) {
4025 int idx = local_body->local_table_size - (argc + j);
4026 ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
4027 }
4028 argc += local_body->param.opt_num;
4029 }
4030
4031 if (local_body->param.flags.has_rest) {
4032 /* rest argument */
4033 int idx = local_body->local_table_size - local_body->param.rest_start;
4034 ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
4035 ADD_INSN1(args, &dummy_line_node, splatarray, Qfalse);
4036
4037 argc = local_body->param.rest_start + 1;
4038 flag |= VM_CALL_ARGS_SPLAT;
4039 }
4040
4041 if (local_body->param.flags.has_post) {
4042 /* post arguments */
4043 int post_len = local_body->param.post_num;
4044 int post_start = local_body->param.post_start;
4045
4046 int j = 0;
4047 for (; j < post_len; j++) {
4048 int idx = local_body->local_table_size - (post_start + j);
4049 ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
4050 }
4051
4052 if (local_body->param.flags.has_rest) {
4053 // argc remains unchanged from rest branch
4054 ADD_INSN1(args, &dummy_line_node, newarray, INT2FIX(j));
4055 ADD_INSN (args, &dummy_line_node, concatarray);
4056 }
4057 else {
4058 argc = post_len + post_start;
4059 }
4060 }
4061
4062 const struct rb_iseq_param_keyword *const local_keyword = local_body->param.keyword;
4063 if (local_body->param.flags.has_kw) {
4064 int local_size = local_body->local_table_size;
4065 argc++;
4066
4067 ADD_INSN1(args, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4068
4069 if (local_body->param.flags.has_kwrest) {
4070 int idx = local_body->local_table_size - local_keyword->rest_start;
4071 ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
4072 if (local_keyword->num > 0) {
4073 ADD_SEND(args, &dummy_line_node, rb_intern("dup"), INT2FIX(0));
4074 flag |= VM_CALL_KW_SPLAT_MUT;
4075 }
4076 }
4077 else {
4078 ADD_INSN1(args, &dummy_line_node, newhash, INT2FIX(0));
4079 flag |= VM_CALL_KW_SPLAT_MUT;
4080 }
4081 int i = 0;
4082 for (; i < local_keyword->num; ++i) {
4083 ID id = local_keyword->table[i];
4084 int idx = local_size - get_local_var_idx(local_iseq, id);
4085 ADD_INSN1(args, &dummy_line_node, putobject, ID2SYM(id));
4086 ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
4087 }
4088 ADD_SEND(args, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
4089 flag |= VM_CALL_KW_SPLAT;
4090 }
4091 else if (local_body->param.flags.has_kwrest) {
4092 int idx = local_body->local_table_size - local_keyword->rest_start;
4093 ADD_GETLOCAL(args, &dummy_line_node, idx, depth);
4094 argc++;
4095 flag |= VM_CALL_KW_SPLAT | VM_CALL_KW_SPLAT_MUT;
4096 }
4097
4098 ADD_SEQ(ret, args);
4099 ADD_INSN2(ret, &dummy_line_node, invokesuper, new_callinfo(iseq, 0, argc, flag, NULL, block != NULL), block);
4100 PM_POP_IF_POPPED;
4101 return;
4102 }
4104 pm_global_variable_and_write_node_t *global_variable_and_write_node = (pm_global_variable_and_write_node_t*) node;
4105
4106 LABEL *end_label = NEW_LABEL(lineno);
4107
4108 VALUE global_variable_name = ID2SYM(pm_constant_id_lookup(scope_node, global_variable_and_write_node->name));
4109
4110 ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
4111
4112 PM_DUP_UNLESS_POPPED;
4113
4114 ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
4115
4116 PM_POP_UNLESS_POPPED;
4117
4118 PM_COMPILE_NOT_POPPED(global_variable_and_write_node->value);
4119
4120 PM_DUP_UNLESS_POPPED;
4121
4122 ADD_INSN1(ret, &dummy_line_node, setglobal, global_variable_name);
4123 ADD_LABEL(ret, end_label);
4124
4125 return;
4126 }
4128 pm_global_variable_operator_write_node_t *global_variable_operator_write_node = (pm_global_variable_operator_write_node_t*) node;
4129
4130 VALUE global_variable_name = ID2SYM(pm_constant_id_lookup(scope_node, global_variable_operator_write_node->name));
4131 ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
4132
4133 PM_COMPILE_NOT_POPPED(global_variable_operator_write_node->value);
4134 ID method_id = pm_constant_id_lookup(scope_node, global_variable_operator_write_node->operator);
4135
4136 int flags = VM_CALL_ARGS_SIMPLE;
4137 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
4138
4139 PM_DUP_UNLESS_POPPED;
4140
4141 ADD_INSN1(ret, &dummy_line_node, setglobal, global_variable_name);
4142
4143 return;
4144 }
4146 pm_global_variable_or_write_node_t *global_variable_or_write_node = (pm_global_variable_or_write_node_t*) node;
4147
4148 LABEL *set_label= NEW_LABEL(lineno);
4149 LABEL *end_label = NEW_LABEL(lineno);
4150
4151 PM_PUTNIL;
4152 VALUE global_variable_name = ID2SYM(pm_constant_id_lookup(scope_node, global_variable_or_write_node->name));
4153
4154 ADD_INSN3(ret, &dummy_line_node, defined, INT2FIX(DEFINED_GVAR), global_variable_name, Qtrue);
4155
4156 ADD_INSNL(ret, &dummy_line_node, branchunless, set_label);
4157
4158 ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
4159
4160 PM_DUP_UNLESS_POPPED;
4161
4162 ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
4163
4164 PM_POP_UNLESS_POPPED;
4165
4166 ADD_LABEL(ret, set_label);
4167 PM_COMPILE_NOT_POPPED(global_variable_or_write_node->value);
4168
4169 PM_DUP_UNLESS_POPPED;
4170
4171 ADD_INSN1(ret, &dummy_line_node, setglobal, global_variable_name);
4172 ADD_LABEL(ret, end_label);
4173
4174 return;
4175 }
4177 pm_global_variable_read_node_t *global_variable_read_node = (pm_global_variable_read_node_t *)node;
4178 VALUE global_variable_name = ID2SYM(pm_constant_id_lookup(scope_node, global_variable_read_node->name));
4179 ADD_INSN1(ret, &dummy_line_node, getglobal, global_variable_name);
4180 PM_POP_IF_POPPED;
4181 return;
4182 }
4185
4186 ID ivar_name = pm_constant_id_lookup(scope_node, write_node->name);
4187 ADD_INSN1(ret, &dummy_line_node, setglobal, ID2SYM(ivar_name));
4188 return;
4189 }
4192 PM_COMPILE_NOT_POPPED(write_node->value);
4193 PM_DUP_UNLESS_POPPED;
4194 ID ivar_name = pm_constant_id_lookup(scope_node, write_node->name);
4195 ADD_INSN1(ret, &dummy_line_node, setglobal, ID2SYM(ivar_name));
4196 return;
4197 }
4198 case PM_HASH_NODE: {
4199 // If every node in the hash is static, then we can compile the entire
4200 // hash now instead of later.
4201 if (pm_static_literal_p(node)) {
4202 // We're only going to compile this node if it's not popped. If it
4203 // is popped, then we know we don't need to do anything since it's
4204 // statically known.
4205 if (!popped) {
4206 VALUE value = pm_static_literal_value(node, scope_node, parser);
4207 ADD_INSN1(ret, &dummy_line_node, duphash, value);
4208 RB_OBJ_WRITTEN(iseq, Qundef, value);
4209 }
4210 } else {
4211 // Here since we know there are possible side-effects inside the
4212 // hash contents, we're going to build it entirely at runtime. We'll
4213 // do this by pushing all of the key-value pairs onto the stack and
4214 // then combining them with newhash.
4215 //
4216 // If this hash is popped, then this serves only to ensure we enact
4217 // all side-effects (like method calls) that are contained within
4218 // the hash contents.
4219 pm_hash_node_t *cast = (pm_hash_node_t *) node;
4220 // Elements must be non-empty, otherwise it would be static literal
4221 pm_node_list_t *elements = &cast->elements;
4222
4223 pm_node_t *cur_node = elements->nodes[0];
4224 pm_node_type_t cur_type = PM_NODE_TYPE(cur_node);
4225 int elements_of_cur_type = 0;
4226 int allocated_hashes = 0;
4227
4228 if (!PM_NODE_TYPE_P(cur_node, PM_ASSOC_NODE) && !popped) {
4229 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4230 ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(0));
4231 allocated_hashes++;
4232 }
4233
4234 for (size_t index = 0; index < elements->size; index++) {
4235 pm_node_t *cur_node = elements->nodes[index];
4236 if (!popped) {
4237 if (!PM_NODE_TYPE_P(cur_node, cur_type)) {
4238 if (!allocated_hashes) {
4239 ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(elements_of_cur_type * 2));
4240 }
4241 else {
4242 if (cur_type == PM_ASSOC_NODE) {
4243 ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(3));
4244 }
4245 else {
4246 ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_kwd, INT2FIX(2));
4247 }
4248 }
4249
4250 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4251 PM_SWAP;
4252 PM_COMPILE(elements->nodes[index]);
4253
4254 allocated_hashes++;
4255 elements_of_cur_type = 0;
4256 cur_type = PM_NODE_TYPE(cur_node);
4257 }
4258 else {
4259 elements_of_cur_type++;
4260 PM_COMPILE(elements->nodes[index]);
4261 }
4262 }
4263 else {
4264 PM_COMPILE(elements->nodes[index]);
4265 }
4266 }
4267
4268 if (!popped) {
4269 if (!allocated_hashes) {
4270 ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(elements_of_cur_type * 2));
4271 }
4272 else {
4273 if (cur_type == PM_ASSOC_NODE) {
4274 ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_ptr, INT2FIX(3));
4275 }
4276 else {
4277 ADD_SEND(ret, &dummy_line_node, id_core_hash_merge_kwd, INT2FIX(2));
4278 }
4279 }
4280 }
4281 }
4282
4283 return;
4284 }
4285 case PM_IF_NODE: {
4286 const int line = (int)pm_newline_list_line_column(&(parser->newline_list), node->location.start).line;
4287 pm_if_node_t *if_node = (pm_if_node_t *)node;
4288 pm_statements_node_t *node_body = if_node->statements;
4289 pm_node_t *node_else = if_node->consequent;
4290 pm_node_t *predicate = if_node->predicate;
4291
4292 pm_compile_if(iseq, line, node_body, node_else, predicate, ret, src, popped, scope_node);
4293 return;
4294 }
4295 case PM_IMAGINARY_NODE: {
4296 if (!popped) {
4297 ADD_INSN1(ret, &dummy_line_node, putobject, parse_imaginary((pm_imaginary_node_t *)node));
4298 }
4299 return;
4300 }
4301 case PM_IMPLICIT_NODE: {
4302 // Implicit nodes mark places in the syntax tree where explicit syntax
4303 // was omitted, but implied. For example,
4304 //
4305 // { foo: }
4306 //
4307 // In this case a method call/local variable read is implied by virtue
4308 // of the missing value. To compile these nodes, we simply compile the
4309 // value that is implied, which is helpfully supplied by the parser.
4310 pm_implicit_node_t *cast = (pm_implicit_node_t *)node;
4311 PM_COMPILE(cast->value);
4312 return;
4313 }
4314 case PM_IN_NODE: {
4315 // In nodes are handled by the case match node directly, so we should
4316 // never end up hitting them through this path.
4317 rb_bug("Should not ever enter an in node directly");
4318 return;
4319 }
4321 pm_index_and_write_node_t *index_and_write_node = (pm_index_and_write_node_t *)node;
4322
4323 pm_compile_index_and_or_write_node(true, index_and_write_node->receiver, index_and_write_node->value, index_and_write_node->arguments, index_and_write_node->block, ret, iseq, lineno, src, popped, scope_node, parser);
4324 return;
4325 }
4327 pm_index_or_write_node_t *index_or_write_node = (pm_index_or_write_node_t *)node;
4328
4329 pm_compile_index_and_or_write_node(false, index_or_write_node->receiver, index_or_write_node->value, index_or_write_node->arguments, index_or_write_node->block, ret, iseq, lineno, src, popped, scope_node, parser);
4330 return;
4331 }
4333 pm_index_operator_write_node_t *index_operator_write_node = (pm_index_operator_write_node_t *)node;
4334
4335 PM_PUTNIL_UNLESS_POPPED;
4336
4337 PM_COMPILE_NOT_POPPED(index_operator_write_node->receiver);
4338
4339 int flag = 0;
4340 struct rb_callinfo_kwarg *keywords = NULL;
4341 int argc_int = 0;
4342
4343 if (index_operator_write_node->arguments) {
4344 argc_int = pm_setup_args(index_operator_write_node->arguments, &flag, &keywords, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
4345 }
4346
4347 VALUE argc = INT2FIX(argc_int);
4348
4349 int block_offset = 0;
4350
4351 if (index_operator_write_node->block) {
4352 PM_COMPILE_NOT_POPPED(index_operator_write_node->block);
4353 flag |= VM_CALL_ARGS_BLOCKARG;
4354 block_offset = 1;
4355 }
4356
4357 ADD_INSN1(ret, &dummy_line_node, dupn, FIXNUM_INC(argc, 1 + block_offset));
4358
4359 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idAREF, argc, INT2FIX(flag));
4360
4361 PM_COMPILE_NOT_POPPED(index_operator_write_node->value);
4362
4363 ID method_id = pm_constant_id_lookup(scope_node, index_operator_write_node->operator);
4364 ADD_SEND(ret, &dummy_line_node, method_id, INT2FIX(1));
4365
4366 pm_compile_index_write_nodes_add_send(popped, ret, iseq, dummy_line_node, argc, flag, block_offset);
4367
4368 return;
4369 }
4371 pm_instance_variable_and_write_node_t *instance_variable_and_write_node = (pm_instance_variable_and_write_node_t*) node;
4372
4373 LABEL *end_label = NEW_LABEL(lineno);
4374 ID instance_variable_name_id = pm_constant_id_lookup(scope_node, instance_variable_and_write_node->name);
4375 VALUE instance_variable_name_val = ID2SYM(instance_variable_name_id);
4376
4377 ADD_INSN2(ret, &dummy_line_node, getinstancevariable, instance_variable_name_val, get_ivar_ic_value(iseq, instance_variable_name_id));
4378 PM_DUP_UNLESS_POPPED;
4379
4380 ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
4381 PM_POP_UNLESS_POPPED;
4382
4383 PM_COMPILE_NOT_POPPED(instance_variable_and_write_node->value);
4384 PM_DUP_UNLESS_POPPED;
4385
4386 ADD_INSN2(ret, &dummy_line_node, setinstancevariable, instance_variable_name_val, get_ivar_ic_value(iseq, instance_variable_name_id));
4387 ADD_LABEL(ret, end_label);
4388
4389 return;
4390 }
4392 pm_instance_variable_operator_write_node_t *instance_variable_operator_write_node = (pm_instance_variable_operator_write_node_t*) node;
4393
4394 ID instance_variable_name_id = pm_constant_id_lookup(scope_node, instance_variable_operator_write_node->name);
4395 VALUE instance_variable_name_val = ID2SYM(instance_variable_name_id);
4396
4397 ADD_INSN2(ret, &dummy_line_node, getinstancevariable,
4398 instance_variable_name_val,
4399 get_ivar_ic_value(iseq, instance_variable_name_id));
4400
4401 PM_COMPILE_NOT_POPPED(instance_variable_operator_write_node->value);
4402 ID method_id = pm_constant_id_lookup(scope_node, instance_variable_operator_write_node->operator);
4403
4404 int flags = VM_CALL_ARGS_SIMPLE;
4405 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
4406
4407 PM_DUP_UNLESS_POPPED;
4408
4409 ADD_INSN2(ret, &dummy_line_node, setinstancevariable,
4410 instance_variable_name_val,
4411 get_ivar_ic_value(iseq, instance_variable_name_id));
4412
4413 return;
4414 }
4416 pm_instance_variable_or_write_node_t *instance_variable_or_write_node = (pm_instance_variable_or_write_node_t*) node;
4417
4418 LABEL *end_label = NEW_LABEL(lineno);
4419
4420 ID instance_variable_name_id = pm_constant_id_lookup(scope_node, instance_variable_or_write_node->name);
4421 VALUE instance_variable_name_val = ID2SYM(instance_variable_name_id);
4422
4423 ADD_INSN2(ret, &dummy_line_node, getinstancevariable, instance_variable_name_val, get_ivar_ic_value(iseq, instance_variable_name_id));
4424 PM_DUP_UNLESS_POPPED;
4425
4426 ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
4427 PM_POP_UNLESS_POPPED;
4428
4429 PM_COMPILE_NOT_POPPED(instance_variable_or_write_node->value);
4430 PM_DUP_UNLESS_POPPED;
4431
4432 ADD_INSN2(ret, &dummy_line_node, setinstancevariable, instance_variable_name_val, get_ivar_ic_value(iseq, instance_variable_name_id));
4433 ADD_LABEL(ret, end_label);
4434
4435 return;
4436 }
4438 if (!popped) {
4439 pm_instance_variable_read_node_t *instance_variable_read_node = (pm_instance_variable_read_node_t *) node;
4440 ID ivar_name = pm_constant_id_lookup(scope_node, instance_variable_read_node->name);
4441 ADD_INSN2(ret, &dummy_line_node, getinstancevariable, ID2SYM(ivar_name), get_ivar_ic_value(iseq, ivar_name));
4442 }
4443 return;
4444 }
4447
4448 ID ivar_name = pm_constant_id_lookup(scope_node, write_node->name);
4449 ADD_INSN2(ret, &dummy_line_node, setinstancevariable, ID2SYM(ivar_name), get_ivar_ic_value(iseq, ivar_name));
4450 return;
4451 }
4454 PM_COMPILE_NOT_POPPED(write_node->value);
4455
4456 PM_DUP_UNLESS_POPPED;
4457
4458 ID ivar_name = pm_constant_id_lookup(scope_node, write_node->name);
4459 ADD_INSN2(ret, &dummy_line_node, setinstancevariable,
4460 ID2SYM(ivar_name),
4461 get_ivar_ic_value(iseq, ivar_name));
4462 return;
4463 }
4464 case PM_INTEGER_NODE: {
4465 if (!popped) {
4466 ADD_INSN1(ret, &dummy_line_node, putobject, parse_integer((pm_integer_node_t *) node));
4467 }
4468 return;
4469 }
4472
4473 int parts_size = (int)cast->parts.size;
4474 if (parts_size > 0 && !PM_NODE_TYPE_P(cast->parts.nodes[0], PM_STRING_NODE)) {
4475 ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_new(0, 0));
4476 parts_size++;
4477 }
4478
4479 pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, src, popped, scope_node, parser);
4480
4481 ADD_INSN2(ret, &dummy_line_node, toregexp, INT2FIX(pm_reg_flags(node)), INT2FIX(parts_size));
4482
4483 ADD_INSN1(ret, &dummy_line_node, getglobal, rb_id2sym(idLASTLINE));
4484 ADD_SEND(ret, &dummy_line_node, idEqTilde, INT2NUM(1));
4485 PM_POP_IF_POPPED;
4486
4487 return;
4488 }
4491 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
4492 const rb_iseq_t *block_iseq = NULL;
4493 int ic_index = ISEQ_BODY(iseq)->ise_size++;
4494
4495 pm_scope_node_t next_scope_node;
4496 pm_scope_node_init((pm_node_t*)node, &next_scope_node, scope_node, parser);
4497
4498 block_iseq = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
4499 ISEQ_COMPILE_DATA(iseq)->current_block = block_iseq;
4500
4501 ADD_INSN2(ret, &dummy_line_node, once, block_iseq, INT2FIX(ic_index));
4502
4503 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
4504 return;
4505 }
4506
4508
4509 int parts_size = (int)cast->parts.size;
4510 if (cast->parts.size > 0 && !PM_NODE_TYPE_P(cast->parts.nodes[0], PM_STRING_NODE)) {
4511 ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_new(0, 0));
4512 parts_size++;
4513 }
4514
4515 pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, src, popped, scope_node, parser);
4516
4517 ADD_INSN2(ret, &dummy_line_node, toregexp, INT2FIX(pm_reg_flags(node)), INT2FIX(parts_size));
4518 PM_POP_IF_POPPED;
4519 return;
4520 }
4522 pm_interpolated_string_node_t *interp_string_node = (pm_interpolated_string_node_t *) node;
4523 pm_interpolated_node_compile(&interp_string_node->parts, iseq, dummy_line_node, ret, src, popped, scope_node, parser);
4524
4525 size_t parts_size = interp_string_node->parts.size;
4526 if (parts_size > 1) {
4527 ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX((int)(parts_size)));
4528 }
4529
4530 PM_POP_IF_POPPED;
4531 return;
4532 }
4534 pm_interpolated_symbol_node_t *interp_symbol_node = (pm_interpolated_symbol_node_t *) node;
4535 pm_interpolated_node_compile(&interp_symbol_node->parts, iseq, dummy_line_node, ret, src, popped, scope_node, parser);
4536
4537 size_t parts_size = interp_symbol_node->parts.size;
4538 if (parts_size > 1) {
4539 ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX((int)(parts_size)));
4540 }
4541
4542 if (!popped) {
4543 ADD_INSN(ret, &dummy_line_node, intern);
4544 }
4545 else {
4546 PM_POP;
4547 }
4548
4549 return;
4550 }
4553 PM_PUTSELF;
4554 pm_interpolated_node_compile(&interp_x_string_node->parts, iseq, dummy_line_node, ret, src, false, scope_node, parser);
4555
4556 size_t parts_size = interp_x_string_node->parts.size;
4557 if (parts_size > 1) {
4558 ADD_INSN1(ret, &dummy_line_node, concatstrings, INT2FIX((int)(parts_size)));
4559 }
4560
4561 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idBackquote, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
4562 PM_POP_IF_POPPED;
4563 return;
4564 }
4565 case PM_KEYWORD_HASH_NODE: {
4566 pm_keyword_hash_node_t *keyword_hash_node = (pm_keyword_hash_node_t *) node;
4567 pm_node_list_t elements = keyword_hash_node->elements;
4568
4569 for (size_t index = 0; index < elements.size; index++) {
4570 PM_COMPILE(elements.nodes[index]);
4571 }
4572
4573 if (!popped) {
4574 ADD_INSN1(ret, &dummy_line_node, newhash, INT2FIX(elements.size * 2));
4575 }
4576 return;
4577 }
4578 case PM_LAMBDA_NODE: {
4579 pm_scope_node_t next_scope_node;
4580 pm_scope_node_init(node, &next_scope_node, scope_node, parser);
4581
4582 const rb_iseq_t *block = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
4583 VALUE argc = INT2FIX(0);
4584
4585 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
4586 ADD_CALL_WITH_BLOCK(ret, &dummy_line_node, idLambda, argc, block);
4587 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
4588
4589 PM_POP_IF_POPPED;
4590 return;
4591 }
4593 pm_local_variable_and_write_node_t *local_variable_and_write_node = (pm_local_variable_and_write_node_t*) node;
4594
4595 LABEL *end_label = NEW_LABEL(lineno);
4596
4597 pm_constant_id_t constant_id = local_variable_and_write_node->name;
4598 int depth = local_variable_and_write_node->depth + scope_node->local_depth_offset;
4599 int local_index = pm_lookup_local_index_with_depth(iseq, scope_node, constant_id, depth);
4600 ADD_GETLOCAL(ret, &dummy_line_node, local_index, depth);
4601
4602 PM_DUP_UNLESS_POPPED;
4603
4604 ADD_INSNL(ret, &dummy_line_node, branchunless, end_label);
4605
4606 PM_POP_UNLESS_POPPED;
4607
4608 PM_COMPILE_NOT_POPPED(local_variable_and_write_node->value);
4609
4610 PM_DUP_UNLESS_POPPED;
4611
4612 ADD_SETLOCAL(ret, &dummy_line_node, local_index, depth);
4613 ADD_LABEL(ret, end_label);
4614
4615 return;
4616 }
4618 pm_local_variable_operator_write_node_t *local_variable_operator_write_node = (pm_local_variable_operator_write_node_t*) node;
4619
4620 pm_constant_id_t constant_id = local_variable_operator_write_node->name;
4621
4622 int depth = local_variable_operator_write_node->depth + scope_node->local_depth_offset;
4623 int local_index = pm_lookup_local_index_with_depth(iseq, scope_node, constant_id, depth);
4624 ADD_GETLOCAL(ret, &dummy_line_node, local_index, depth);
4625
4626 PM_COMPILE_NOT_POPPED(local_variable_operator_write_node->value);
4627 ID method_id = pm_constant_id_lookup(scope_node, local_variable_operator_write_node->operator);
4628
4629 int flags = VM_CALL_ARGS_SIMPLE | VM_CALL_FCALL | VM_CALL_VCALL;
4630 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, method_id, INT2NUM(1), INT2FIX(flags));
4631
4632 PM_DUP_UNLESS_POPPED;
4633
4634 ADD_SETLOCAL(ret, &dummy_line_node, local_index, depth);
4635
4636 return;
4637 }
4639 pm_local_variable_or_write_node_t *local_variable_or_write_node = (pm_local_variable_or_write_node_t*) node;
4640
4641 LABEL *set_label= NEW_LABEL(lineno);
4642 LABEL *end_label = NEW_LABEL(lineno);
4643
4644 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
4645 ADD_INSNL(ret, &dummy_line_node, branchunless, set_label);
4646
4647 pm_constant_id_t constant_id = local_variable_or_write_node->name;
4648 int depth = local_variable_or_write_node->depth + scope_node->local_depth_offset;
4649 int local_index = pm_lookup_local_index_with_depth(iseq, scope_node, constant_id, depth);
4650 ADD_GETLOCAL(ret, &dummy_line_node, local_index, depth);
4651
4652 PM_DUP_UNLESS_POPPED;
4653
4654 ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
4655
4656 PM_POP_UNLESS_POPPED;
4657
4658 ADD_LABEL(ret, set_label);
4659 PM_COMPILE_NOT_POPPED(local_variable_or_write_node->value);
4660
4661 PM_DUP_UNLESS_POPPED;
4662
4663 ADD_SETLOCAL(ret, &dummy_line_node, local_index, depth);
4664 ADD_LABEL(ret, end_label);
4665
4666 return;
4667 }
4670
4671 if (!popped) {
4672 int index = pm_lookup_local_index_with_depth(iseq, scope_node, local_read_node->name, local_read_node->depth);
4673 ADD_GETLOCAL(ret, &dummy_line_node, index, local_read_node->depth + scope_node->local_depth_offset);
4674 }
4675 return;
4676 }
4679
4680 pm_constant_id_t constant_id = local_write_node->name;
4681 int index = pm_lookup_local_index_any_scope(iseq, scope_node, constant_id);
4682
4683 ADD_SETLOCAL(ret, &dummy_line_node, index, local_write_node->depth + scope_node->local_depth_offset);
4684 return;
4685 }
4688 PM_COMPILE_NOT_POPPED(local_write_node->value);
4689
4690 PM_DUP_UNLESS_POPPED;
4691
4692 pm_constant_id_t constant_id = local_write_node->name;
4693
4694 int index = pm_lookup_local_index_any_scope(iseq, scope_node, constant_id);
4695
4696 ADD_SETLOCAL(ret, &dummy_line_node, index, local_write_node->depth + scope_node->local_depth_offset);
4697 return;
4698 }
4700 if (!popped) {
4702
4703 VALUE regex_str = parse_string(&cast->unescaped, parser);
4704 VALUE regex = rb_reg_new(RSTRING_PTR(regex_str), RSTRING_LEN(regex_str), pm_reg_flags(node));
4705
4706 ADD_INSN1(ret, &dummy_line_node, putobject, regex);
4707 ADD_INSN2(ret, &dummy_line_node, getspecial, INT2FIX(0), INT2FIX(0));
4708 ADD_SEND(ret, &dummy_line_node, idEqTilde, INT2NUM(1));
4709 }
4710
4711 return;
4712 }
4715
4716 // First, allocate some stack space for the cached return value of any
4717 // calls to #deconstruct.
4718 PM_PUTNIL;
4719
4720 // Next, compile the expression that we're going to match against.
4721 PM_COMPILE_NOT_POPPED(cast->value);
4722 PM_DUP;
4723
4724 // Now compile the pattern that is going to be used to match against the
4725 // expression.
4726 LABEL *matched_label = NEW_LABEL(lineno);
4727 LABEL *unmatched_label = NEW_LABEL(lineno);
4728 LABEL *done_label = NEW_LABEL(lineno);
4729 pm_compile_pattern(iseq, scope_node, cast->pattern, ret, src, matched_label, unmatched_label, false, false, true, 2);
4730
4731 // If the pattern did not match, then compile the necessary instructions
4732 // to handle pushing false onto the stack, then jump to the end.
4733 ADD_LABEL(ret, unmatched_label);
4734 PM_POP;
4735 PM_POP;
4736
4737 if (!popped) ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse);
4738 ADD_INSNL(ret, &dummy_line_node, jump, done_label);
4739 PM_PUTNIL;
4740
4741 // If the pattern did match, then compile the necessary instructions to
4742 // handle pushing true onto the stack, then jump to the end.
4743 ADD_LABEL(ret, matched_label);
4744 ADD_INSN1(ret, &dummy_line_node, adjuststack, INT2FIX(2));
4745 if (!popped) ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
4746 ADD_INSNL(ret, &dummy_line_node, jump, done_label);
4747
4748 ADD_LABEL(ret, done_label);
4749 return;
4750 }
4752 // A match required node represents pattern matching against a single
4753 // pattern using the => operator. For example,
4754 //
4755 // foo => bar
4756 //
4757 // This is somewhat analogous to compiling a case match statement with a
4758 // single pattern. In both cases, if the pattern fails it should
4759 // immediately raise an error.
4760 const pm_match_required_node_t *cast = (const pm_match_required_node_t *) node;
4761
4762 LABEL *matched_label = NEW_LABEL(lineno);
4763 LABEL *unmatched_label = NEW_LABEL(lineno);
4764 LABEL *done_label = NEW_LABEL(lineno);
4765
4766 // First, we're going to push a bunch of stuff onto the stack that is
4767 // going to serve as our scratch space.
4768 ADD_INSN(ret, &dummy_line_node, putnil); // key error key
4769 ADD_INSN(ret, &dummy_line_node, putnil); // key error matchee
4770 ADD_INSN1(ret, &dummy_line_node, putobject, Qfalse); // key error?
4771 ADD_INSN(ret, &dummy_line_node, putnil); // error string
4772 ADD_INSN(ret, &dummy_line_node, putnil); // deconstruct cache
4773
4774 // Next we're going to compile the value expression such that it's on
4775 // the stack.
4776 PM_COMPILE_NOT_POPPED(cast->value);
4777
4778 // Here we'll dup it so that it can be used for comparison, but also be
4779 // used for error handling.
4780 ADD_INSN(ret, &dummy_line_node, dup);
4781
4782 // Next we'll compile the pattern. We indicate to the pm_compile_pattern
4783 // function that this is the only pattern that will be matched against
4784 // through the in_single_pattern parameter. We also indicate that the
4785 // value to compare against is 2 slots from the top of the stack (the
4786 // base_index parameter).
4787 pm_compile_pattern(iseq, scope_node, cast->pattern, ret, src, matched_label, unmatched_label, true, false, true, 2);
4788
4789 // If the pattern did not match the value, then we're going to compile
4790 // in our error handler code. This will determine which error to raise
4791 // and raise it.
4792 ADD_LABEL(ret, unmatched_label);
4793 pm_compile_pattern_error_handler(iseq, scope_node, node, ret, src, done_label, popped);
4794
4795 // If the pattern did match, we'll clean up the values we've pushed onto
4796 // the stack and then push nil onto the stack if it's not popped.
4797 ADD_LABEL(ret, matched_label);
4798 ADD_INSN1(ret, &dummy_line_node, adjuststack, INT2FIX(6));
4799 if (!popped) ADD_INSN(ret, &dummy_line_node, putnil);
4800 ADD_INSNL(ret, &dummy_line_node, jump, done_label);
4801
4802 ADD_LABEL(ret, done_label);
4803 return;
4804 }
4805 case PM_MATCH_WRITE_NODE: {
4806 // Match write nodes are specialized call nodes that have a regular
4807 // expression with valid named capture groups on the left, the =~
4808 // operator, and some value on the right. The nodes themselves simply
4809 // wrap the call with the local variable targets that will be written
4810 // when the call is executed.
4812 LABEL *fail_label = NEW_LABEL(lineno);
4813 LABEL *end_label = NEW_LABEL(lineno);
4814
4815 // First, we'll compile the call so that all of its instructions are
4816 // present. Then we'll compile all of the local variable targets.
4817 PM_COMPILE_NOT_POPPED((pm_node_t *) cast->call);
4818
4819 // Now, check if the match was successful. If it was, then we'll
4820 // continue on and assign local variables. Otherwise we'll skip over the
4821 // assignment code.
4822 ADD_INSN1(ret, &dummy_line_node, getglobal, rb_id2sym(idBACKREF));
4823 PM_DUP;
4824 ADD_INSNL(ret, &dummy_line_node, branchunless, fail_label);
4825
4826 // If there's only a single local variable target, we can skip some of
4827 // the bookkeeping, so we'll put a special branch here.
4828 size_t targets_count = cast->targets.size;
4829
4830 if (targets_count == 1) {
4831 pm_node_t *target = cast->targets.nodes[0];
4833
4835 int index = pm_lookup_local_index(iseq, scope_node, local_target->name);
4836
4837 ADD_INSN1(ret, &dummy_line_node, putobject, rb_id2sym(pm_constant_id_lookup(scope_node, local_target->name)));
4838 ADD_SEND(ret, &dummy_line_node, idAREF, INT2FIX(1));
4839 ADD_LABEL(ret, fail_label);
4840 ADD_SETLOCAL(ret, &dummy_line_node, index, (int) local_target->depth);
4841 PM_POP_IF_POPPED;
4842 return;
4843 }
4844
4845 // Otherwise there is more than one local variable target, so we'll need
4846 // to do some bookkeeping.
4847 for (size_t targets_index = 0; targets_index < targets_count; targets_index++) {
4848 pm_node_t *target = cast->targets.nodes[targets_index];
4850
4852 int index = pm_lookup_local_index(iseq, scope_node, local_target->name);
4853
4854 if (((size_t) targets_index) < (targets_count - 1)) {
4855 PM_DUP;
4856 }
4857 ADD_INSN1(ret, &dummy_line_node, putobject, rb_id2sym(pm_constant_id_lookup(scope_node, local_target->name)));
4858 ADD_SEND(ret, &dummy_line_node, idAREF, INT2FIX(1));
4859 ADD_SETLOCAL(ret, &dummy_line_node, index, (int) local_target->depth);
4860 }
4861
4862 // Since we matched successfully, now we'll jump to the end.
4863 ADD_INSNL(ret, &dummy_line_node, jump, end_label);
4864
4865 // In the case that the match failed, we'll loop through each local
4866 // variable target and set all of them to `nil`.
4867 ADD_LABEL(ret, fail_label);
4868 PM_POP;
4869
4870 for (size_t targets_index = 0; targets_index < targets_count; targets_index++) {
4871 pm_node_t *target = cast->targets.nodes[targets_index];
4873
4875 int index = pm_lookup_local_index(iseq, scope_node, local_target->name);
4876
4877 PM_PUTNIL;
4878 ADD_SETLOCAL(ret, &dummy_line_node, index, (int) local_target->depth);
4879 }
4880
4881 // Finally, we can push the end label for either case.
4882 PM_POP_IF_POPPED;
4883 ADD_LABEL(ret, end_label);
4884 return;
4885 }
4886 case PM_MISSING_NODE: {
4887 rb_bug("A pm_missing_node_t should not exist in prism's AST.");
4888 return;
4889 }
4890 case PM_MODULE_NODE: {
4891 pm_module_node_t *module_node = (pm_module_node_t *)node;
4892 pm_scope_node_t next_scope_node;
4893 pm_scope_node_init((pm_node_t *)module_node, &next_scope_node, scope_node, parser);
4894
4895 ID module_id = pm_constant_id_lookup(scope_node, module_node->name);
4896 VALUE module_name = rb_str_freeze(rb_sprintf("<module:%"PRIsVALUE">", rb_id2str(module_id)));
4897
4898 const rb_iseq_t *module_iseq = NEW_CHILD_ISEQ(next_scope_node, module_name, ISEQ_TYPE_CLASS, lineno);
4899
4900 const int flags = VM_DEFINECLASS_TYPE_MODULE |
4901 pm_compile_class_path(ret, iseq, module_node->constant_path, &dummy_line_node, src, false, scope_node);
4902
4903 PM_PUTNIL;
4904 ADD_INSN3(ret, &dummy_line_node, defineclass, ID2SYM(module_id), module_iseq, INT2FIX(flags));
4905 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
4906
4907 PM_POP_IF_POPPED;
4908 return;
4909 }
4911 pm_required_parameter_node_t *required_parameter_node = (pm_required_parameter_node_t *)node;
4912 int index = pm_lookup_local_index(iseq, scope_node, required_parameter_node->name);
4913
4914 ADD_SETLOCAL(ret, &dummy_line_node, index, 0);
4915 return;
4916 }
4917 case PM_MULTI_TARGET_NODE: {
4919 bool has_rest_expression = (cast->rest &&
4921 (((pm_splat_node_t *)cast->rest)->expression));
4922
4923 if (cast->lefts.size) {
4924 int flag = (int) (bool) cast->rights.size || has_rest_expression;
4925 ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->lefts.size), INT2FIX(flag));
4926 for (size_t index = 0; index < cast->lefts.size; index++) {
4927 PM_COMPILE_NOT_POPPED(cast->lefts.nodes[index]);
4928 }
4929 }
4930
4931 if (has_rest_expression) {
4932 if (cast->rights.size) {
4933 ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->rights.size), INT2FIX(3));
4934 }
4935 pm_node_t *expression = ((pm_splat_node_t *)cast->rest)->expression;
4936 PM_COMPILE_NOT_POPPED(expression);
4937 }
4938
4939 if (cast->rights.size) {
4940 if (!has_rest_expression) {
4941 ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(cast->rights.size), INT2FIX(2));
4942 }
4943 for (size_t index = 0; index < cast->rights.size; index++) {
4944 PM_COMPILE_NOT_POPPED(cast->rights.nodes[index]);
4945 }
4946 }
4947 return;
4948 }
4949 case PM_MULTI_WRITE_NODE: {
4950 pm_multi_write_node_t *multi_write_node = (pm_multi_write_node_t *)node;
4951 pm_node_list_t *lefts = &multi_write_node->lefts;
4952 pm_node_list_t *rights = &multi_write_node->rights;
4953 size_t argc = 1;
4954
4955 // pre-process the left hand side of multi-assignments.
4956 uint8_t pushed = 0;
4957 for (size_t index = 0; index < lefts->size; index++) {
4958 pushed = pm_compile_multi_write_lhs(iseq, dummy_line_node, src, popped, lefts->nodes[index], ret, scope_node, pushed, false);
4959 }
4960
4961 PM_COMPILE_NOT_POPPED(multi_write_node->value);
4962 PM_DUP_UNLESS_POPPED;
4963
4964 pm_node_t *rest_expression = NULL;
4965 if (multi_write_node->rest && PM_NODE_TYPE_P(multi_write_node->rest, PM_SPLAT_NODE)) {
4966 pm_splat_node_t *rest_splat = ((pm_splat_node_t *)multi_write_node->rest);
4967 rest_expression = rest_splat->expression;
4968 }
4969
4970 size_t remainder = pushed;
4971 if (popped) remainder--;
4972
4973 if (lefts->size) {
4974 ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(lefts->size), INT2FIX((int) (bool) (rights->size || rest_expression)));
4975 for (size_t index = 0; index < lefts->size; index++) {
4976 pm_node_t *considered_node = lefts->nodes[index];
4977
4978 if (PM_NODE_TYPE_P(considered_node, PM_CONSTANT_PATH_TARGET_NODE) && pushed > 0) {
4980 ID name = pm_constant_id_lookup(scope_node, ((pm_constant_read_node_t * ) cast->child)->name);
4981
4982 pushed -= 2;
4983
4984 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(pushed));
4985 ADD_INSN1(ret, &dummy_line_node, setconstant, ID2SYM(name));
4986 } else if (PM_NODE_TYPE_P(considered_node, PM_INDEX_TARGET_NODE)) {
4987 pm_index_target_node_t *cast = (pm_index_target_node_t *)considered_node;
4988
4989 if (cast->arguments) {
4991 argc = args->arguments.size + 1;
4992 }
4993
4994 if (argc == 1) {
4995 ADD_INSN(ret, &dummy_line_node, swap);
4996 }
4997 else {
4998 VALUE vals = INT2FIX(remainder + (lefts->size - index));
4999 ADD_INSN1(ret, &dummy_line_node, topn, vals);
5000 for (size_t i = 1; i < argc; i++) {
5001 ADD_INSN1(ret, &dummy_line_node, topn, vals);
5002 }
5003 ADD_INSN1(ret, &dummy_line_node, topn, INT2FIX(argc));
5004 }
5005
5006 ADD_SEND(ret, &dummy_line_node, idASET, INT2FIX(argc));
5007 PM_POP;
5008 PM_POP;
5009 remainder -= argc;
5010
5011 } else if (PM_NODE_TYPE_P(considered_node, PM_CALL_TARGET_NODE)) {
5012 pm_call_target_node_t *cast = (pm_call_target_node_t *)considered_node;
5013
5014 VALUE vals = INT2FIX(remainder + (lefts->size - index));
5015 ADD_INSN1(ret, &dummy_line_node, topn, vals);
5016 ADD_INSN(ret, &dummy_line_node, swap);
5017
5018 ID method_id = pm_constant_id_lookup(scope_node, cast->name);
5019 ADD_SEND(ret, &dummy_line_node, method_id, INT2FIX(argc));
5020 PM_POP;
5021 remainder -= argc;
5022 } else {
5023 PM_COMPILE(lefts->nodes[index]);
5024 }
5025 }
5026 }
5027
5028 if ((pushed)) {
5029 if (!popped) {
5030 ADD_INSN1(ret, &dummy_line_node, setn, INT2FIX(pushed));
5031 }
5032 for (uint8_t index = 0; index < (pushed); index++) {
5033 PM_POP;
5034 }
5035 }
5036
5037 if (rights->size) {
5038 if (rest_expression) {
5039 ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(rights->size), INT2FIX(3));
5040 PM_COMPILE(rest_expression);
5041 }
5042 else {
5043 ADD_INSN2(ret, &dummy_line_node, expandarray, INT2FIX(rights->size), INT2FIX(2));
5044 }
5045
5046 for (size_t index = 0; index < rights->size; index++) {
5047 PM_COMPILE(rights->nodes[index]);
5048 }
5049 }
5050 else if (rest_expression) {
5051 PM_COMPILE(rest_expression);
5052 }
5053
5054 return;
5055 }
5056 case PM_NEXT_NODE: {
5057 pm_next_node_t *next_node = (pm_next_node_t *) node;
5058
5059 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0 && can_add_ensure_iseq(iseq)) {
5060 LABEL *splabel = NEW_LABEL(0);
5061
5062 ADD_LABEL(ret, splabel);
5063
5064 if (next_node->arguments) {
5065 PM_COMPILE_NOT_POPPED((pm_node_t *)next_node->arguments);
5066 }
5067 else {
5068 PM_PUTNIL;
5069 }
5070 pm_add_ensure_iseq(ret, iseq, 0, src, scope_node);
5071
5072 ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
5073 ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
5074
5075 ADD_ADJUST_RESTORE(ret, splabel);
5076 PM_PUTNIL_UNLESS_POPPED;
5077 }
5078 else if (ISEQ_COMPILE_DATA(iseq)->end_label && can_add_ensure_iseq(iseq)) {
5079 LABEL *splabel = NEW_LABEL(0);
5080
5081 ADD_LABEL(ret, splabel);
5082 ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
5083
5084 if (next_node->arguments) {
5085 PM_COMPILE_NOT_POPPED((pm_node_t *)next_node->arguments);
5086 }
5087 else {
5088 PM_PUTNIL;
5089 }
5090
5091 pm_add_ensure_iseq(ret, iseq, 0, src, scope_node);
5092 ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->end_label);
5093 ADD_ADJUST_RESTORE(ret, splabel);
5094 splabel->unremovable = FALSE;
5095
5096 PM_PUTNIL_UNLESS_POPPED;
5097 }
5098 else {
5099 const rb_iseq_t *ip = iseq;
5100
5101 unsigned long throw_flag = 0;
5102 while (ip) {
5103 if (!ISEQ_COMPILE_DATA(ip)) {
5104 ip = 0;
5105 break;
5106 }
5107
5108 throw_flag = VM_THROW_NO_ESCAPE_FLAG;
5109 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
5110 /* while loop */
5111 break;
5112 }
5113 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
5114 break;
5115 }
5116 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
5117 rb_raise(rb_eArgError, "Can't escape from eval with next");
5118 return;
5119 }
5120
5121 ip = ISEQ_BODY(ip)->parent_iseq;
5122 }
5123 if (ip != 0) {
5124 if (next_node->arguments) {
5125 PM_COMPILE_NOT_POPPED((pm_node_t *)next_node->arguments);
5126 }
5127 else {
5128 PM_PUTNIL;
5129 }
5130 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(throw_flag | TAG_NEXT));
5131
5132 PM_POP_IF_POPPED;
5133 }
5134 else {
5135 rb_raise(rb_eArgError, "Invalid next");
5136 return;
5137 }
5138 }
5139
5140 return;
5141 }
5142 case PM_NIL_NODE:
5143 PM_PUTNIL_UNLESS_POPPED
5144 return;
5146 ISEQ_BODY(iseq)->param.flags.accepts_no_kwarg = TRUE;
5147 return;
5148 }
5150 if (!popped) {
5151 uint32_t reference_number = ((pm_numbered_reference_read_node_t *)node)->number;
5152 ADD_INSN2(ret, &dummy_line_node, getspecial, INT2FIX(1), INT2FIX(reference_number << 1));
5153 }
5154 return;
5155 }
5156 case PM_OR_NODE: {
5157 pm_or_node_t *or_node = (pm_or_node_t *) node;
5158
5159 LABEL *end_label = NEW_LABEL(lineno);
5160 PM_COMPILE_NOT_POPPED(or_node->left);
5161
5162 PM_DUP_UNLESS_POPPED;
5163 ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
5164
5165 PM_POP_UNLESS_POPPED;
5166 PM_COMPILE(or_node->right);
5167 ADD_LABEL(ret, end_label);
5168
5169 return;
5170 }
5172 pm_optional_parameter_node_t *optional_parameter_node = (pm_optional_parameter_node_t *)node;
5173 PM_COMPILE_NOT_POPPED(optional_parameter_node->value);
5174
5175 int index = pm_lookup_local_index(iseq, scope_node, optional_parameter_node->name);
5176
5177 ADD_SETLOCAL(ret, &dummy_line_node, index, 0);
5178
5179 return;
5180 }
5181 case PM_PARAMETERS_NODE: {
5182 rb_bug("Should not ever enter a parameters node directly");
5183
5184 return;
5185 }
5186 case PM_PARENTHESES_NODE: {
5187 pm_parentheses_node_t *parentheses_node = (pm_parentheses_node_t *) node;
5188
5189 if (parentheses_node->body == NULL) {
5190 PM_PUTNIL_UNLESS_POPPED;
5191 } else {
5192 PM_COMPILE(parentheses_node->body);
5193 }
5194
5195 return;
5196 }
5197 case PM_PRE_EXECUTION_NODE: {
5198 pm_pre_execution_node_t *pre_execution_node = (pm_pre_execution_node_t *) node;
5199
5200 DECL_ANCHOR(pre_ex);
5201 INIT_ANCHOR(pre_ex);
5202
5203 if (pre_execution_node->statements) {
5204 pm_node_list_t node_list = pre_execution_node->statements->body;
5205 for (size_t index = 0; index < node_list.size; index++) {
5206 pm_compile_node(iseq, node_list.nodes[index], pre_ex, src, true, scope_node);
5207 }
5208 }
5209
5210 if (!popped) {
5211 ADD_INSN(pre_ex, &dummy_line_node, putnil);
5212 }
5213
5214 pre_ex->last->next = ret->anchor.next;
5215 ret->anchor.next = pre_ex->anchor.next;
5216 ret->anchor.next->prev = pre_ex->anchor.next;
5217
5218 if (ret->last == (LINK_ELEMENT *)ret) {
5219 ret->last = pre_ex->last;
5220 }
5221
5222 return;
5223 }
5225 const rb_iseq_t *child_iseq;
5226 const rb_iseq_t *prevblock = ISEQ_COMPILE_DATA(iseq)->current_block;
5227
5228 pm_scope_node_t next_scope_node;
5229 pm_scope_node_init(node, &next_scope_node, scope_node, parser);
5230
5231 child_iseq = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
5232 ISEQ_COMPILE_DATA(iseq)->current_block = child_iseq;
5233
5234 int is_index = ISEQ_BODY(iseq)->ise_size++;
5235
5236 ADD_INSN2(ret, &dummy_line_node, once, child_iseq, INT2FIX(is_index));
5237 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)child_iseq);
5238
5239 PM_POP_IF_POPPED;
5240
5241 ISEQ_COMPILE_DATA(iseq)->current_block = prevblock;
5242
5243 return;
5244 }
5245 case PM_PROGRAM_NODE: {
5246 rb_bug("Should not ever enter a program node directly");
5247
5248 return;
5249 }
5250 case PM_RANGE_NODE: {
5251 pm_range_node_t *range_node = (pm_range_node_t *) node;
5252 bool exclusive = (range_node->operator_loc.end - range_node->operator_loc.start) == 3;
5253
5254 if (pm_optimizable_range_item_p(range_node->left) && pm_optimizable_range_item_p(range_node->right)) {
5255 if (!popped) {
5256 pm_node_t *left = range_node->left;
5257 pm_node_t *right = range_node->right;
5258 VALUE val = rb_range_new(
5259 left && PM_NODE_TYPE_P(left, PM_INTEGER_NODE) ? parse_integer((pm_integer_node_t *) left) : Qnil,
5260 right && PM_NODE_TYPE_P(right, PM_INTEGER_NODE) ? parse_integer((pm_integer_node_t *) right) : Qnil,
5261 exclusive
5262 );
5263 ADD_INSN1(ret, &dummy_line_node, putobject, val);
5264 RB_OBJ_WRITTEN(iseq, Qundef, val);
5265 }
5266 }
5267 else {
5268 if (range_node->left == NULL) {
5269 PM_PUTNIL;
5270 } else {
5271 PM_COMPILE(range_node->left);
5272 }
5273
5274 if (range_node->right == NULL) {
5275 PM_PUTNIL;
5276 } else {
5277 PM_COMPILE(range_node->right);
5278 }
5279
5280 if (!popped) {
5281 ADD_INSN1(ret, &dummy_line_node, newrange, INT2FIX(exclusive));
5282 }
5283 }
5284 return;
5285 }
5286 case PM_RATIONAL_NODE: {
5287 if (!popped) {
5288 ADD_INSN1(ret, &dummy_line_node, putobject, parse_rational(node));
5289 }
5290 return;
5291 }
5292 case PM_REDO_NODE: {
5293 if (ISEQ_COMPILE_DATA(iseq)->redo_label && can_add_ensure_iseq(iseq)) {
5294 LABEL *splabel = NEW_LABEL(0);
5295
5296 ADD_LABEL(ret, splabel);
5297
5298 ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->redo_label);
5299
5300 pm_add_ensure_iseq(ret, iseq, 0, src, scope_node);
5301 ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->redo_label);
5302 ADD_ADJUST_RESTORE(ret, splabel);
5303 PM_PUTNIL_UNLESS_POPPED;
5304 }
5305 else if (ISEQ_BODY(iseq)->type != ISEQ_TYPE_EVAL && ISEQ_COMPILE_DATA(iseq)->start_label && can_add_ensure_iseq(iseq)) {
5306 LABEL *splabel = NEW_LABEL(0);
5307
5308 ADD_LABEL(ret, splabel);
5309 pm_add_ensure_iseq(ret, iseq, 0, src, scope_node);
5310 ADD_ADJUST(ret, &dummy_line_node, ISEQ_COMPILE_DATA(iseq)->start_label);
5311 ADD_INSNL(ret, &dummy_line_node, jump, ISEQ_COMPILE_DATA(iseq)->start_label);
5312 ADD_ADJUST_RESTORE(ret, splabel);
5313
5314 PM_PUTNIL_UNLESS_POPPED;
5315 }
5316 else {
5317 const rb_iseq_t *ip = iseq;
5318
5319 while (ip) {
5320 if (!ISEQ_COMPILE_DATA(ip)) {
5321 ip = 0;
5322 break;
5323 }
5324
5325 if (ISEQ_COMPILE_DATA(ip)->redo_label != 0) {
5326 break;
5327 }
5328 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_BLOCK) {
5329 break;
5330 }
5331 else if (ISEQ_BODY(ip)->type == ISEQ_TYPE_EVAL) {
5332 rb_bug("Invalid redo\n");
5333 }
5334
5335 ip = ISEQ_BODY(ip)->parent_iseq;
5336 }
5337 if (ip != 0) {
5338 PM_PUTNIL;
5339 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(VM_THROW_NO_ESCAPE_FLAG | TAG_REDO));
5340
5341 PM_POP_IF_POPPED;
5342 }
5343 else {
5344 rb_bug("Invalid redo\n");
5345 }
5346 }
5347 return;
5348 }
5350 if (!popped) {
5352
5353 VALUE regex = pm_new_regex(cast, parser);
5354
5355 ADD_INSN1(ret, &dummy_line_node, putobject, regex);
5356 }
5357 return;
5358 }
5359 case PM_RESCUE_NODE: {
5360 LABEL *excep_match = NEW_LABEL(lineno);
5361 LABEL *rescue_end = NEW_LABEL(lineno);
5362
5363 ISEQ_COMPILE_DATA(iseq)->end_label = rescue_end;
5364
5365 pm_rescue_node_t *rescue_node = (pm_rescue_node_t *)node;
5366 iseq_set_exception_local_table(iseq);
5367
5368 pm_node_list_t exception_list = rescue_node->exceptions;
5369 if (exception_list.size > 0) {
5370 for (size_t i = 0; i < exception_list.size; i++) {
5371 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
5372 PM_COMPILE(exception_list.nodes[i]);
5373 ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
5374 ADD_INSN1(ret, &dummy_line_node, branchif, excep_match);
5375 }
5376 } else {
5377 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
5378 ADD_INSN1(ret, &dummy_line_node, putobject, rb_eStandardError);
5379 ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
5380 ADD_INSN1(ret, &dummy_line_node, branchif, excep_match);
5381 }
5382 ADD_INSN1(ret, &dummy_line_node, jump, rescue_end);
5383
5384 ADD_LABEL(ret, excep_match);
5385 ADD_TRACE(ret, RUBY_EVENT_RESCUE);
5386 if (rescue_node->reference) {
5387 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
5388 PM_COMPILE((pm_node_t *)rescue_node->reference);
5389 }
5390
5391 if (rescue_node->statements) {
5392 PM_COMPILE((pm_node_t *)rescue_node->statements);
5393 }
5394 else {
5395 PM_PUTNIL;
5396 }
5397
5398 ADD_INSN(ret, &dummy_line_node, leave);
5399 ADD_LABEL(ret, rescue_end);
5400
5401 if (rescue_node->consequent) {
5402 PM_COMPILE((pm_node_t *)rescue_node->consequent);
5403 } else {
5404 ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
5405 }
5406
5407 return;
5408 }
5410 pm_scope_node_t rescue_scope_node;
5412 pm_scope_node_init((pm_node_t *)rescue_node, &rescue_scope_node, scope_node, parser);
5413
5414 rb_iseq_t *rescue_iseq = NEW_CHILD_ISEQ(rescue_scope_node,
5415 rb_str_concat(rb_str_new2("rescue in"),
5416 ISEQ_BODY(iseq)->location.label),
5417 ISEQ_TYPE_RESCUE, 1);
5418
5419 LABEL *lstart = NEW_LABEL(lineno);
5420 LABEL *lend = NEW_LABEL(lineno);
5421 LABEL *lcont = NEW_LABEL(lineno);
5422
5423 lstart->rescued = LABEL_RESCUE_BEG;
5424 lend->rescued = LABEL_RESCUE_END;
5425 ADD_LABEL(ret, lstart);
5426 PM_COMPILE_NOT_POPPED((pm_node_t *)rescue_node->expression);
5427 ADD_LABEL(ret, lend);
5428 PM_NOP;
5429 ADD_LABEL(ret, lcont);
5430
5431 PM_POP_IF_POPPED;
5432
5433 ADD_CATCH_ENTRY(CATCH_TYPE_RESCUE, lstart, lend, rescue_iseq, lcont);
5434 ADD_CATCH_ENTRY(CATCH_TYPE_RETRY, lend, lcont, NULL, lstart);
5435 return;
5436 }
5437 case PM_RETURN_NODE: {
5438 pm_arguments_node_t *arguments = ((pm_return_node_t *)node)->arguments;
5439
5440 if (iseq) {
5441 enum rb_iseq_type type = ISEQ_BODY(iseq)->type;
5442 LABEL *splabel = 0;
5443
5444 const rb_iseq_t *parent_iseq = iseq;
5445 enum rb_iseq_type parent_type = ISEQ_BODY(parent_iseq)->type;
5446 while (parent_type == ISEQ_TYPE_RESCUE || parent_type == ISEQ_TYPE_ENSURE) {
5447 if (!(parent_iseq = ISEQ_BODY(parent_iseq)->parent_iseq)) break;
5448 parent_type = ISEQ_BODY(parent_iseq)->type;
5449 }
5450
5451 switch (parent_type) {
5452 case ISEQ_TYPE_TOP:
5453 case ISEQ_TYPE_MAIN:
5454 if (arguments) {
5455 rb_warn("argument of top-level return is ignored");
5456 }
5457 if (parent_iseq == iseq) {
5458 type = ISEQ_TYPE_METHOD;
5459 }
5460 break;
5461 default:
5462 break;
5463 }
5464
5465 if (type == ISEQ_TYPE_METHOD) {
5466 splabel = NEW_LABEL(0);
5467 ADD_LABEL(ret, splabel);
5468 ADD_ADJUST(ret, &dummy_line_node, 0);
5469 }
5470
5471 if (arguments) {
5472 PM_COMPILE_NOT_POPPED((pm_node_t *)arguments);
5473 }
5474 else {
5475 PM_PUTNIL;
5476 }
5477
5478 if (type == ISEQ_TYPE_METHOD && can_add_ensure_iseq(iseq)) {
5479 pm_add_ensure_iseq(ret, iseq, 1, src, scope_node);
5480 ADD_TRACE(ret, RUBY_EVENT_RETURN);
5481 ADD_INSN(ret, &dummy_line_node, leave);
5482 ADD_ADJUST_RESTORE(ret, splabel);
5483
5484 PM_PUTNIL_UNLESS_POPPED;
5485 }
5486 else {
5487 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(TAG_RETURN));
5488 PM_POP_IF_POPPED;
5489 }
5490 }
5491
5492 return;
5493 }
5494 case PM_RETRY_NODE: {
5495 if (ISEQ_BODY(iseq)->type == ISEQ_TYPE_RESCUE) {
5496 PM_PUTNIL;
5497 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(TAG_RETRY));
5498
5499 PM_POP_IF_POPPED;
5500 } else {
5501 COMPILE_ERROR(ERROR_ARGS "Invalid retry");
5502 rb_bug("Invalid retry");
5503 }
5504 return;
5505 }
5506 case PM_SCOPE_NODE: {
5507 pm_scope_node_t *scope_node = (pm_scope_node_t *)node;
5508 pm_constant_id_list_t *locals = &scope_node->locals;
5509
5510 pm_parameters_node_t *parameters_node = NULL;
5511 pm_node_list_t *keywords_list = NULL;
5512 pm_node_list_t *optionals_list = NULL;
5513 pm_node_list_t *posts_list = NULL;
5514 pm_node_list_t *requireds_list = NULL;
5515 pm_node_list_t *block_locals = NULL;
5516 pm_node_t *block_param_keyword_rest = NULL;
5517
5518 struct rb_iseq_constant_body *body = ISEQ_BODY(iseq);
5519
5520 if (scope_node->parameters) {
5521 switch (PM_NODE_TYPE(scope_node->parameters)) {
5523 pm_block_parameters_node_t *block_parameters_node = (pm_block_parameters_node_t *)scope_node->parameters;
5524 parameters_node = block_parameters_node->parameters;
5525 block_locals = &block_parameters_node->locals;
5526 if (parameters_node) {
5527 block_param_keyword_rest = parameters_node->keyword_rest;
5528 }
5529 break;
5530 }
5531 case PM_PARAMETERS_NODE: {
5532 parameters_node = (pm_parameters_node_t *) scope_node->parameters;
5533 break;
5534 }
5536 body->param.lead_num = ((pm_numbered_parameters_node_t *) scope_node->parameters)->maximum;
5537 break;
5538 }
5539 default:
5540 rb_bug("Unexpected node type for parameters: %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
5541 }
5542 }
5543
5544 struct rb_iseq_param_keyword *keyword = NULL;
5545
5546 if (parameters_node) {
5547 optionals_list = &parameters_node->optionals;
5548 requireds_list = &parameters_node->requireds;
5549 keywords_list = &parameters_node->keywords;
5550 posts_list = &parameters_node->posts;
5551 } else if (scope_node->parameters && PM_NODE_TYPE_P(scope_node->parameters, PM_NUMBERED_PARAMETERS_NODE)) {
5552 body->param.opt_num = 0;
5553 }
5554 else {
5555 body->param.lead_num = 0;
5556 body->param.opt_num = 0;
5557 }
5558
5559 //********STEP 1**********
5560 // Goal: calculate the table size for the locals, accounting for
5561 // hidden variables and multi target nodes
5562 size_t locals_size = locals->size;
5563
5564 // Index lookup table buffer size is only the number of the locals
5565 st_table *index_lookup_table = st_init_numtable();
5566
5567 int table_size = (int) locals_size;
5568
5569 if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) {
5570 body->param.lead_num = 1;
5571 table_size++;
5572 }
5573
5574 if (keywords_list && keywords_list->size) {
5575 table_size++;
5576 }
5577
5578 if (requireds_list) {
5579 int number_of_anonymous_locals = 0;
5580 for (size_t i = 0; i < requireds_list->size; i++) {
5581 // For each MultiTargetNode, we're going to have one
5582 // additional anonymous local not represented in the locals table
5583 // We want to account for this in our table size
5584 pm_node_t *required = requireds_list->nodes[i];
5585 if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
5586 table_size++;
5587 }
5588 else if (PM_NODE_TYPE_P(required, PM_REQUIRED_PARAMETER_NODE)) {
5589 if (pm_constant_id_lookup(scope_node, ((pm_required_parameter_node_t *)required)->name) == rb_intern("_")) {
5590 number_of_anonymous_locals++;
5591 }
5592 }
5593 }
5594
5595 // For each anonymous local we also want to increase the size
5596 // of the locals table. Prism's locals table accounts for all
5597 // anonymous locals as 1, so we need to increase the table size
5598 // by the number of anonymous locals - 1
5599 if (number_of_anonymous_locals > 1) {
5600 table_size += (number_of_anonymous_locals - 1);
5601 }
5602 }
5603
5604 if (posts_list) {
5605 for (size_t i = 0; i < posts_list->size; i++) {
5606 // For each MultiTargetNode, we're going to have one
5607 // additional anonymous local not represented in the locals table
5608 // We want to account for this in our table size
5609 pm_node_t *required = posts_list->nodes[i];
5610 if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
5611 table_size++;
5612 }
5613 }
5614 }
5615
5616 if (block_param_keyword_rest) {
5617 table_size++;
5618 }
5619
5620 // When we have a `...` as the keyword_rest, it's a forwarding_parameter_node and
5621 // we need to leave space for 2 more locals on the locals table (`*` and `&`)
5622 if (parameters_node && parameters_node->keyword_rest &&
5624 table_size += 2;
5625 }
5626
5627 // We can create local_table_for_iseq with the correct size
5628 VALUE idtmp = 0;
5629 rb_ast_id_table_t *local_table_for_iseq = ALLOCV(idtmp, sizeof(rb_ast_id_table_t) + table_size * sizeof(ID));
5630 local_table_for_iseq->size = table_size;
5631
5632 //********END OF STEP 1**********
5633
5634 //********STEP 2**********
5635 // Goal: populate iv index table as well as local table, keeping the
5636 // layout of the local table consistent with the layout of the
5637 // stack when calling the method
5638 //
5639 // Do a first pass on all of the parameters, setting their values in
5640 // the local_table_for_iseq, _except_ for Multis who get a hidden
5641 // variable in this step, and will get their names inserted in step 3
5642
5643 // local_index is a cursor that keeps track of the current
5644 // index into local_table_for_iseq. The local table is actually a list,
5645 // and the order of that list must match the order of the items pushed
5646 // on the stack. We need to take in to account things pushed on the
5647 // stack that _might not have a name_ (for example array destructuring).
5648 // This index helps us know which item we're dealing with and also give
5649 // those anonymous items temporary names (as below)
5650 int local_index = 0;
5651
5652 // We will assign these values now, if applicable, and use them for
5653 // the ISEQs on these multis
5654 int required_multis_hidden_index = 0;
5655 int post_multis_hidden_index = 0;
5656
5657 // Here we figure out local table indices and insert them in to the
5658 // index lookup table and local tables.
5659 //
5660 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5661 // ^^^^^^^^^^^^^
5662 if (requireds_list && requireds_list->size) {
5663 for (size_t i = 0; i < requireds_list->size; i++, local_index++) {
5664 ID local;
5665 // For each MultiTargetNode, we're going to have one
5666 // additional anonymous local not represented in the locals table
5667 // We want to account for this in our table size
5668 pm_node_t *required = requireds_list->nodes[i];
5669 switch (PM_NODE_TYPE(required)) {
5670 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5671 // ^^^^^^^^^^
5672 case PM_MULTI_TARGET_NODE: {
5673 required_multis_hidden_index = local_index;
5674 local = rb_make_temporary_id(local_index);
5675 local_table_for_iseq->ids[local_index] = local;
5676 break;
5677 }
5678 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5679 // ^
5682
5683 pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
5684 break;
5685 }
5686 default: {
5687 rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
5688 }
5689 }
5690 }
5691
5692 body->param.lead_num = (int) requireds_list->size;
5693 body->param.flags.has_lead = true;
5694 }
5695
5696 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5697 // ^^^^^
5698 if (optionals_list && optionals_list->size) {
5699 body->param.opt_num = (int) optionals_list->size;
5700 body->param.flags.has_opt = true;
5701
5702 for (size_t i = 0; i < optionals_list->size; i++, local_index++) {
5703 pm_constant_id_t name = ((pm_optional_parameter_node_t *)optionals_list->nodes[i])->name;
5704 pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
5705 }
5706 }
5707
5708 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5709 // ^^
5710 if (parameters_node && parameters_node->rest) {
5711 body->param.rest_start = local_index;
5712 // If there's a trailing comma, we'll have an implicit rest node,
5713 // and we don't want it to impact the rest variables on param
5714 if (!(PM_NODE_TYPE_P(parameters_node->rest, PM_IMPLICIT_REST_NODE))) {
5715 body->param.flags.has_rest = true;
5716 assert(body->param.rest_start != -1);
5717
5718 pm_constant_id_t name = ((pm_rest_parameter_node_t *)parameters_node->rest)->name;
5719 if (name) {
5720 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5721 // ^^
5722 pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
5723 }
5724 else {
5725 // def foo(a, (b, *c, d), e = 1, *, g, (h, *i, j), k:, l: 1, **m, &n)
5726 // ^
5727 local_table_for_iseq->ids[local_index] = idMULT;
5728 }
5729 local_index++;
5730 }
5731 }
5732
5733 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5734 // ^^^^^^^^^^^^^
5735 if (posts_list && posts_list->size) {
5736 body->param.post_num = (int) posts_list->size;
5737 body->param.post_start = local_index;
5738 body->param.flags.has_post = true;
5739
5740 for (size_t i = 0; i < posts_list->size; i++, local_index++) {
5741 ID local;
5742 // For each MultiTargetNode, we're going to have one
5743 // additional anonymous local not represented in the locals table
5744 // We want to account for this in our table size
5745 pm_node_t *post_node = posts_list->nodes[i];
5746 switch (PM_NODE_TYPE(post_node)) {
5747 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5748 // ^^^^^^^^^^
5749 case PM_MULTI_TARGET_NODE: {
5750 post_multis_hidden_index = local_index;
5751 local = rb_make_temporary_id(local_index);
5752 local_table_for_iseq->ids[local_index] = local;
5753 break;
5754 }
5755 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5756 // ^
5759
5760 pm_insert_local_index(param->name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
5761 break;
5762 }
5763 default: {
5764 rb_bug("Unsupported node %s", pm_node_type_to_str(PM_NODE_TYPE(node)));
5765 }
5766 }
5767 }
5768 }
5769
5770 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5771 // ^^^^^^^^
5772 // Keywords create an internal variable on the parse tree
5773 if (keywords_list && keywords_list->size) {
5774 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
5775 keyword->num = (int) keywords_list->size;
5776
5777 body->param.flags.has_kw = true;
5778 const VALUE default_values = rb_ary_hidden_new(1);
5779 const VALUE complex_mark = rb_str_tmp_new(0);
5780
5781 ID *ids = xcalloc(keywords_list->size, sizeof(ID));
5782
5783 for (size_t i = 0; i < keywords_list->size; i++, local_index++) {
5784 pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
5785 pm_constant_id_t name;
5786
5787 switch (PM_NODE_TYPE(keyword_parameter_node)) {
5788 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5789 // ^^^^
5792
5793 pm_node_t *value = cast->value;
5794 name = cast->name;
5795
5796 if (pm_static_literal_p(value) &&
5797 !(PM_NODE_TYPE_P(value, PM_ARRAY_NODE) ||
5798 PM_NODE_TYPE_P(value, PM_HASH_NODE) ||
5799 PM_NODE_TYPE_P(value, PM_RANGE_NODE))) {
5800
5801 rb_ary_push(default_values, pm_static_literal_value(value, scope_node, parser));
5802 }
5803 else {
5804 rb_ary_push(default_values, complex_mark);
5805 }
5806
5807 break;
5808 }
5809 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5810 // ^^
5812 name = ((pm_required_keyword_parameter_node_t *)keyword_parameter_node)->name;
5813 keyword->required_num++;
5814 break;
5815 }
5816 default: {
5817 rb_bug("Unexpected keyword parameter node type");
5818 }
5819 }
5820
5821 ID local = pm_constant_id_lookup(scope_node, name);
5822 pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
5823 ids[i] = local;
5824 }
5825
5826 keyword->bits_start = local_index;
5827 keyword->table = ids;
5828
5829 VALUE *dvs = ALLOC_N(VALUE, RARRAY_LEN(default_values));
5830
5831 for (int i = 0; i < RARRAY_LEN(default_values); i++) {
5832 VALUE dv = RARRAY_AREF(default_values, i);
5833 if (dv == complex_mark) dv = Qundef;
5834 if (!SPECIAL_CONST_P(dv)) {
5835 RB_OBJ_WRITTEN(iseq, Qundef, dv);
5836 }
5837 dvs[i] = dv;
5838 }
5839
5840 keyword->default_values = dvs;
5841
5842 // Hidden local for keyword arguments
5843 ID local = rb_make_temporary_id(local_index);
5844 local_table_for_iseq->ids[local_index] = local;
5845 local_index++;
5846 }
5847
5848 if (body->type == ISEQ_TYPE_BLOCK && local_index == 1 && requireds_list && requireds_list->size == 1) {
5849 body->param.flags.ambiguous_param0 = true;
5850 }
5851
5852 if (parameters_node) {
5853 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5854 // ^^^
5855 if (parameters_node->keyword_rest) {
5856 switch (PM_NODE_TYPE(parameters_node->keyword_rest)) {
5857 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **nil, &n)
5858 // ^^^^^
5860
5861 body->param.flags.accepts_no_kwarg = true;
5862 break;
5863 }
5864 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5865 // ^^^
5868 if (!body->param.flags.has_kw) {
5869 body->param.keyword = keyword = ZALLOC_N(struct rb_iseq_param_keyword, 1);
5870 }
5871
5872 keyword->rest_start = local_index;
5873 body->param.flags.has_kwrest = true;
5874
5875 pm_constant_id_t constant_id = kw_rest_node->name;
5876 if (constant_id) {
5877 pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
5878 }
5879 else {
5880 local_table_for_iseq->ids[local_index] = idPow;
5881 }
5882 local_index++;
5883 break;
5884 }
5885 // def foo(...)
5886 // ^^^
5888 body->param.rest_start = local_index;
5889 body->param.flags.has_rest = true;
5890 ID local = idMULT;
5891 local_table_for_iseq->ids[local_index] = local;
5892 local_index++;
5893
5894 body->param.block_start = local_index;
5895 body->param.flags.has_block = true;
5896 local = idAnd;
5897 local_table_for_iseq->ids[local_index] = local;
5898 local_index++;
5899
5900 local = idDot3;
5901 local_table_for_iseq->ids[local_index] = local;
5902 local_index++;
5903 break;
5904 }
5905 default: {
5906 rb_raise(rb_eArgError, "node type %s not expected as keyword_rest", pm_node_type_to_str(PM_NODE_TYPE(parameters_node->keyword_rest)));
5907 }
5908 }
5909 }
5910
5911 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
5912 // ^^
5913 if (parameters_node->block) {
5914 body->param.block_start = local_index;
5915 body->param.flags.has_block = true;
5916
5917 pm_constant_id_t name = ((pm_block_parameter_node_t *)parameters_node->block)->name;
5918 pm_insert_local_index(name, local_index, index_lookup_table, local_table_for_iseq, scope_node);
5919 local_index++;
5920 }
5921 }
5922
5923 //********END OF STEP 2**********
5924 // The local table is now consistent with expected
5925 // stack layout
5926
5927 // If there's only one required element in the parameters
5928 // CRuby needs to recognize it as an ambiguous parameter
5929
5930 //********STEP 3**********
5931 // Goal: fill in the names of the parameters in MultiTargetNodes
5932 //
5933 // Go through requireds again to set the multis
5934
5935 if (requireds_list && requireds_list->size) {
5936 for (size_t i = 0; i < requireds_list->size; i++) {
5937 // For each MultiTargetNode, we're going to have one
5938 // additional anonymous local not represented in the locals table
5939 // We want to account for this in our table size
5940 pm_node_t *required = requireds_list->nodes[i];
5941 if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
5942 local_index = pm_compile_multi_assign_params((pm_multi_target_node_t *)required, index_lookup_table, local_table_for_iseq, scope_node, local_index);
5943 }
5944 }
5945 }
5946
5947 // Go through posts again to set the multis
5948 if (posts_list && posts_list->size) {
5949 for (size_t i = 0; i < posts_list->size; i++) {
5950 // For each MultiTargetNode, we're going to have one
5951 // additional anonymous local not represented in the locals table
5952 // We want to account for this in our table size
5953 pm_node_t *post= posts_list->nodes[i];
5955 local_index = pm_compile_multi_assign_params((pm_multi_target_node_t *)post, index_lookup_table, local_table_for_iseq, scope_node, local_index);
5956 }
5957 }
5958 }
5959
5960 // Set any anonymous locals for the for node
5961 if (PM_NODE_TYPE_P(scope_node->ast_node, PM_FOR_NODE)) {
5962 ID local = rb_make_temporary_id(local_index);
5963 local_table_for_iseq->ids[local_index] = local;
5964 local_index++;
5965 }
5966
5967 // Fill in any NumberedParameters, if they exist
5968 if (scope_node->parameters && PM_NODE_TYPE_P(scope_node->parameters, PM_NUMBERED_PARAMETERS_NODE)) {
5969 int maximum = ((pm_numbered_parameters_node_t *)scope_node->parameters)->maximum;
5970 for (int i = 0; i < maximum; i++, local_index++) {
5971 pm_constant_id_t constant_id = locals->ids[i];
5972 pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
5973 }
5974 }
5975 //********END OF STEP 3**********
5976
5977 //********STEP 4**********
5978 // Goal: fill in the method body locals
5979 // To be explicit, these are the non-parameter locals
5980 uint32_t locals_body_index = 0;
5981
5982 switch (PM_NODE_TYPE(scope_node->ast_node)) {
5983 case PM_BLOCK_NODE: {
5984 locals_body_index = ((pm_block_node_t *)scope_node->ast_node)->locals_body_index;
5985 break;
5986 }
5987 case PM_DEF_NODE: {
5988 locals_body_index = ((pm_def_node_t *)scope_node->ast_node)->locals_body_index;
5989 break;
5990 }
5991 case PM_LAMBDA_NODE: {
5992 locals_body_index = ((pm_lambda_node_t *)scope_node->ast_node)->locals_body_index;
5993 break;
5994 }
5995 default: {
5996 }
5997 }
5998
5999 if (scope_node->locals.size) {
6000 for (size_t i = locals_body_index; i < scope_node->locals.size; i++) {
6001 pm_constant_id_t constant_id = locals->ids[i];
6002 if (constant_id) {
6003 pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
6004 local_index++;
6005 }
6006 }
6007 }
6008
6009 // We fill in the block_locals, if they exist
6010 // lambda { |x; y| y }
6011 // ^
6012 if (block_locals && block_locals->size) {
6013 for (size_t i = 0; i < block_locals->size; i++, local_index++) {
6014 pm_constant_id_t constant_id = ((pm_block_local_variable_node_t *)block_locals->nodes[i])->name;
6015 pm_insert_local_index(constant_id, local_index, index_lookup_table, local_table_for_iseq, scope_node);
6016 }
6017 }
6018
6019 //********END OF STEP 4**********
6020
6021 // We set the index_lookup_table on the scope node so we can
6022 // refer to the parameters correctly
6023 scope_node->index_lookup_table = index_lookup_table;
6024 iseq_calc_param_size(iseq);
6025 iseq_set_local_table(iseq, local_table_for_iseq);
6026 scope_node->local_table_for_iseq_size = local_table_for_iseq->size;
6027
6028 //********STEP 5************
6029 // Goal: compile anything that needed to be compiled
6030 if (keywords_list && keywords_list->size) {
6031 for (size_t i = 0; i < keywords_list->size; i++, local_index++) {
6032 pm_node_t *keyword_parameter_node = keywords_list->nodes[i];
6033 pm_constant_id_t name;
6034
6035 switch (PM_NODE_TYPE(keyword_parameter_node)) {
6036 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
6037 // ^^^^
6040
6041 pm_node_t *value = cast->value;
6042 name = cast->name;
6043
6044 if (!(pm_static_literal_p(value)) ||
6045 PM_NODE_TYPE_P(value, PM_ARRAY_NODE) ||
6046 PM_NODE_TYPE_P(value, PM_HASH_NODE) ||
6047 PM_NODE_TYPE_P(value, PM_RANGE_NODE)) {
6048 LABEL *end_label = NEW_LABEL(nd_line(&dummy_line_node));
6049
6050 int index = pm_lookup_local_index(iseq, scope_node, name);
6051 int kw_bits_idx = table_size - body->param.keyword->bits_start;
6052 ADD_INSN2(ret, &dummy_line_node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(i));
6053 ADD_INSNL(ret, &dummy_line_node, branchif, end_label);
6054 PM_COMPILE(value);
6055 ADD_SETLOCAL(ret, &dummy_line_node, index, 0);
6056
6057 ADD_LABEL(ret, end_label);
6058 }
6059 break;
6060 }
6061 // def foo(a, (b, *c, d), e = 1, *f, g, (h, *i, j), k:, l: 1, **m, &n)
6062 // ^^
6064 break;
6065 }
6066 default: {
6067 rb_bug("Unexpected keyword parameter node type");
6068 }
6069 }
6070 }
6071 }
6072
6073 if (optionals_list && optionals_list->size) {
6074 LABEL **opt_table = (LABEL **)ALLOC_N(VALUE, optionals_list->size + 1);
6075 LABEL *label;
6076
6077 // TODO: Should we make an api for NEW_LABEL where you can pass
6078 // a pointer to the label it should fill out? We already
6079 // have a list of labels allocated above so it seems wasteful
6080 // to do the copies.
6081 for (size_t i = 0; i < optionals_list->size; i++, local_index++) {
6082 label = NEW_LABEL(lineno);
6083 opt_table[i] = label;
6084 ADD_LABEL(ret, label);
6085 pm_node_t *optional_node = optionals_list->nodes[i];
6086 PM_COMPILE_NOT_POPPED(optional_node);
6087 }
6088
6089 // Set the last label
6090 label = NEW_LABEL(lineno);
6091 opt_table[optionals_list->size] = label;
6092 ADD_LABEL(ret, label);
6093
6094 body->param.opt_table = (const VALUE *)opt_table;
6095 }
6096
6097 if (requireds_list && requireds_list->size) {
6098 for (size_t i = 0; i < requireds_list->size; i++) {
6099 // For each MultiTargetNode, we're going to have one
6100 // additional anonymous local not represented in the locals table
6101 // We want to account for this in our table size
6102 pm_node_t *required = requireds_list->nodes[i];
6103 if (PM_NODE_TYPE_P(required, PM_MULTI_TARGET_NODE)) {
6104 ADD_GETLOCAL(ret, &dummy_line_node, table_size - required_multis_hidden_index, 0);
6105 PM_COMPILE(required);
6106 }
6107 }
6108 }
6109
6110 if (posts_list && posts_list->size) {
6111 for (size_t i = 0; i < posts_list->size; i++) {
6112 // For each MultiTargetNode, we're going to have one
6113 // additional anonymous local not represented in the locals table
6114 // We want to account for this in our table size
6115 pm_node_t *post = posts_list->nodes[i];
6117 ADD_GETLOCAL(ret, &dummy_line_node, table_size - post_multis_hidden_index, 0);
6118 PM_COMPILE(post);
6119 }
6120 }
6121 }
6122
6123 switch (body->type) {
6124 case ISEQ_TYPE_BLOCK: {
6125 LABEL *start = ISEQ_COMPILE_DATA(iseq)->start_label = NEW_LABEL(0);
6126 LABEL *end = ISEQ_COMPILE_DATA(iseq)->end_label = NEW_LABEL(0);
6127
6128 start->rescued = LABEL_RESCUE_BEG;
6129 end->rescued = LABEL_RESCUE_END;
6130
6131 ADD_TRACE(ret, RUBY_EVENT_B_CALL);
6132 NODE dummy_line_node = generate_dummy_line_node(body->location.first_lineno, -1);
6133 if (ISEQ_COMPILE_DATA(iseq)->redo_label != 0) {
6134 PM_NOP;
6135 }
6136 ADD_LABEL(ret, start);
6137
6138 if (scope_node->body) {
6139 switch (PM_NODE_TYPE(scope_node->ast_node)) {
6141 pm_post_execution_node_t *post_execution_node = (pm_post_execution_node_t *)scope_node->ast_node;
6142
6143 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6144
6145 // We create another ScopeNode from the statements within the PostExecutionNode
6146 pm_scope_node_t next_scope_node;
6147 pm_scope_node_init((pm_node_t *)post_execution_node->statements, &next_scope_node, scope_node, parser);
6148
6149 const rb_iseq_t *block = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(body->parent_iseq), ISEQ_TYPE_BLOCK, lineno);
6150
6151 ADD_CALL_WITH_BLOCK(ret, &dummy_line_node, id_core_set_postexe, INT2FIX(0), block);
6152 break;
6153 }
6154 case PM_FOR_NODE: {
6155 pm_for_node_t *for_node = (pm_for_node_t *)scope_node->ast_node;
6156 LABEL *target = NEW_LABEL(lineno);
6157 LABEL *old_start = ISEQ_COMPILE_DATA(iseq)->start_label;
6158
6159 ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
6160 PM_COMPILE(for_node->index);
6161 PM_NOP;
6162 ADD_LABEL(ret, target);
6163 ISEQ_COMPILE_DATA(iseq)->start_label = target;
6164 pm_compile_node(iseq, (pm_node_t *)(scope_node->body), ret, src, popped, scope_node);
6165 ISEQ_COMPILE_DATA(iseq)->start_label = old_start;
6166 break;
6167 }
6170
6171 int parts_size = (int)cast->parts.size;
6172 if (parts_size > 0 && !PM_NODE_TYPE_P(cast->parts.nodes[0], PM_STRING_NODE)) {
6173 ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_new(0, 0));
6174 parts_size++;
6175 }
6176
6177 pm_interpolated_node_compile(&cast->parts, iseq, dummy_line_node, ret, src, false, scope_node, parser);
6178 ADD_INSN2(ret, &dummy_line_node, toregexp, INT2FIX(pm_reg_flags((pm_node_t *)cast)), INT2FIX(parts_size));
6179 break;
6180 }
6181 default: {
6182 pm_compile_node(iseq, (pm_node_t *)(scope_node->body), ret, src, popped, scope_node);
6183 }
6184 }
6185 }
6186 else {
6187 PM_PUTNIL;
6188 }
6189
6190 ADD_LABEL(ret, end);
6191 ADD_TRACE(ret, RUBY_EVENT_B_RETURN);
6192 ISEQ_COMPILE_DATA(iseq)->last_line = body->location.code_location.end_pos.lineno;
6193
6194 /* wide range catch handler must put at last */
6195 ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, NULL, start);
6196 ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, NULL, end);
6197 break;
6198 }
6199 case ISEQ_TYPE_ENSURE: {
6200 iseq_set_exception_local_table(iseq);
6201
6202 if (scope_node->body) {
6203 PM_COMPILE_POPPED((pm_node_t *)scope_node->body);
6204 }
6205
6206 ADD_GETLOCAL(ret, &dummy_line_node, 1, 0);
6207 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0));
6208 return;
6209 }
6210 case ISEQ_TYPE_RESCUE: {
6211 iseq_set_exception_local_table(iseq);
6212 if (PM_NODE_TYPE_P(scope_node->ast_node, PM_RESCUE_MODIFIER_NODE)) {
6213 LABEL *lab = NEW_LABEL(lineno);
6214 LABEL *rescue_end = NEW_LABEL(lineno);
6215 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
6216 ADD_INSN1(ret, &dummy_line_node, putobject, rb_eStandardError);
6217 ADD_INSN1(ret, &dummy_line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_RESCUE));
6218 ADD_INSN1(ret, &dummy_line_node, branchif, lab);
6219 ADD_INSN1(ret, &dummy_line_node, jump, rescue_end);
6220 ADD_LABEL(ret, lab);
6221 PM_COMPILE((pm_node_t *)scope_node->body);
6222 ADD_INSN(ret, &dummy_line_node, leave);
6223 ADD_LABEL(ret, rescue_end);
6224 ADD_GETLOCAL(ret, &dummy_line_node, LVAR_ERRINFO, 0);
6225 }
6226 else {
6227 PM_COMPILE((pm_node_t *)scope_node->ast_node);
6228 }
6229 ADD_INSN1(ret, &dummy_line_node, throw, INT2FIX(0));
6230
6231 return;
6232 }
6233 default:
6234 if (scope_node->body) {
6235 PM_COMPILE((pm_node_t *)scope_node->body);
6236 }
6237 else {
6238 PM_PUTNIL;
6239 }
6240 }
6241
6242 st_free_table(index_lookup_table);
6243
6244 if (!PM_NODE_TYPE_P(scope_node->ast_node, PM_ENSURE_NODE)) {
6245 ADD_INSN(ret, &dummy_line_node, leave);
6246 }
6247 return;
6248 }
6249 case PM_SELF_NODE:
6250 if (!popped) {
6251 PM_PUTSELF;
6252 }
6253 return;
6255 pm_singleton_class_node_t *singleton_class_node = (pm_singleton_class_node_t *)node;
6256 pm_scope_node_t next_scope_node;
6257 pm_scope_node_init((pm_node_t *)singleton_class_node, &next_scope_node, scope_node, parser);
6258
6259 const rb_iseq_t *singleton_class = NEW_ISEQ(next_scope_node, rb_fstring_lit("singleton class"), ISEQ_TYPE_CLASS, lineno);
6260
6261 PM_COMPILE_NOT_POPPED(singleton_class_node->expression);
6262 PM_PUTNIL;
6263 ID singletonclass;
6264 CONST_ID(singletonclass, "singletonclass");
6265
6266 ADD_INSN3(ret, &dummy_line_node, defineclass,
6267 ID2SYM(singletonclass), singleton_class,
6268 INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
6269 PM_POP_IF_POPPED;
6270 RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
6271
6272 return;
6273 }
6275 // Source encoding nodes are generated by the __ENCODING__ syntax. They
6276 // reference the encoding object corresponding to the encoding of the
6277 // source file, and can be changed by a magic encoding comment.
6278 if (!popped) {
6279 VALUE value = pm_static_literal_value(node, scope_node, parser);
6280 ADD_INSN1(ret, &dummy_line_node, putobject, value);
6281 RB_OBJ_WRITTEN(iseq, Qundef, value);
6282 }
6283 return;
6284 }
6285 case PM_SOURCE_FILE_NODE: {
6286 // Source file nodes are generated by the __FILE__ syntax. They
6287 // reference the file name of the source file.
6288 if (!popped) {
6289 VALUE value = pm_static_literal_value(node, scope_node, parser);
6290 ADD_INSN1(ret, &dummy_line_node, putstring, value);
6291 RB_OBJ_WRITTEN(iseq, Qundef, value);
6292 }
6293 return;
6294 }
6295 case PM_SOURCE_LINE_NODE: {
6296 // Source line nodes are generated by the __LINE__ syntax. They
6297 // reference the line number where they occur in the source file.
6298 if (!popped) {
6299 VALUE value = pm_static_literal_value(node, scope_node, parser);
6300 ADD_INSN1(ret, &dummy_line_node, putobject, value);
6301 RB_OBJ_WRITTEN(iseq, Qundef, value);
6302 }
6303 return;
6304 }
6305 case PM_SPLAT_NODE: {
6306 pm_splat_node_t *splat_node = (pm_splat_node_t *)node;
6307 if (splat_node->expression) {
6308 PM_COMPILE(splat_node->expression);
6309 }
6310
6311 if (!popped) {
6312 ADD_INSN1(ret, &dummy_line_node, splatarray, Qtrue);
6313 }
6314 return;
6315 }
6316 case PM_STATEMENTS_NODE: {
6317 pm_statements_node_t *statements_node = (pm_statements_node_t *) node;
6318 pm_node_list_t node_list = statements_node->body;
6319 if (node_list.size > 0) {
6320 for (size_t index = 0; index < node_list.size - 1; index++) {
6321 PM_COMPILE_POPPED(node_list.nodes[index]);
6322 }
6323 PM_COMPILE(node_list.nodes[node_list.size - 1]);
6324 }
6325 else {
6326 PM_PUTNIL;
6327 }
6328 return;
6329 }
6330 case PM_STRING_NODE: {
6331 if (!popped) {
6332 pm_string_node_t *cast = (pm_string_node_t *) node;
6333 VALUE value = parse_string_encoded(node, &cast->unescaped, parser);
6334 if (node->flags & PM_STRING_FLAGS_FROZEN) {
6335 ADD_INSN1(ret, &dummy_line_node, putobject, rb_str_freeze(value));
6336 }
6337 else {
6338 ADD_INSN1(ret, &dummy_line_node, putstring, value);
6339 }
6340 }
6341 return;
6342 }
6343 case PM_SUPER_NODE: {
6344 pm_super_node_t *super_node = (pm_super_node_t *) node;
6345
6346 DECL_ANCHOR(args);
6347
6348 int flags = 0;
6349 struct rb_callinfo_kwarg *keywords = NULL;
6350 const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
6351
6352 INIT_ANCHOR(args);
6353 ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
6354
6355 PM_PUTSELF;
6356
6357 int argc = pm_setup_args(super_node->arguments, &flags, &keywords, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
6358
6359 flags |= VM_CALL_SUPER | VM_CALL_FCALL;
6360
6361 if (super_node->block) {
6362 switch (PM_NODE_TYPE(super_node->block)) {
6364 PM_COMPILE_NOT_POPPED(super_node->block);
6365 flags |= VM_CALL_ARGS_BLOCKARG;
6366 break;
6367 }
6368 case PM_BLOCK_NODE: {
6369 pm_scope_node_t next_scope_node;
6370 pm_scope_node_init(super_node->block, &next_scope_node, scope_node, parser);
6371 parent_block = NEW_CHILD_ISEQ(next_scope_node, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, lineno);
6372 break;
6373 }
6374 default: {
6375 rb_bug("This node type should never occur on a SuperNode's block");
6376 }
6377 }
6378 }
6379
6380 ADD_SEQ(ret, args);
6381 ADD_INSN2(ret, &dummy_line_node, invokesuper,
6382 new_callinfo(iseq, 0, argc, flags, keywords, parent_block != NULL),
6383 parent_block);
6384
6385 PM_POP_IF_POPPED;
6386 return;
6387 }
6388 case PM_SYMBOL_NODE: {
6389 // Symbols nodes are symbol literals with no interpolation. They are
6390 // always marked as static literals.
6391 if (!popped) {
6392 VALUE value = pm_static_literal_value(node, scope_node, parser);
6393 ADD_INSN1(ret, &dummy_line_node, putobject, value);
6394 RB_OBJ_WRITTEN(iseq, Qundef, value);
6395 }
6396 return;
6397 }
6398 case PM_TRUE_NODE:
6399 if (!popped) {
6400 ADD_INSN1(ret, &dummy_line_node, putobject, Qtrue);
6401 }
6402 return;
6403 case PM_UNDEF_NODE: {
6404 pm_undef_node_t *undef_node = (pm_undef_node_t *) node;
6405
6406 for (size_t index = 0; index < undef_node->names.size; index++) {
6407 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
6408 ADD_INSN1(ret, &dummy_line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
6409
6410 PM_COMPILE_NOT_POPPED(undef_node->names.nodes[index]);
6411
6412 ADD_SEND(ret, &dummy_line_node, id_core_undef_method, INT2NUM(2));
6413
6414 if (index < undef_node->names.size - 1) {
6415 PM_POP;
6416 }
6417 }
6418
6419 PM_POP_IF_POPPED;
6420
6421 return;
6422 }
6423 case PM_UNLESS_NODE: {
6424 const int line = (int)pm_newline_list_line_column(&(parser->newline_list), node->location.start).line;
6425 pm_unless_node_t *unless_node = (pm_unless_node_t *)node;
6426 pm_node_t *node_body = (pm_node_t *)(unless_node->statements);
6427 pm_statements_node_t *node_else = NULL;
6428 if (unless_node->consequent != NULL) {
6429 node_else = ((pm_else_node_t *)unless_node->consequent)->statements;
6430 }
6431 pm_node_t *predicate = unless_node->predicate;
6432
6433 pm_compile_if(iseq, line, node_else, node_body, predicate, ret, src, popped, scope_node);
6434 return;
6435 }
6436 case PM_UNTIL_NODE: {
6437 pm_until_node_t *until_node = (pm_until_node_t *)node;
6438 pm_statements_node_t *statements = until_node->statements;
6439 pm_node_t *predicate = until_node->predicate;
6440 pm_node_flags_t flags = node->flags;
6441
6442 pm_compile_while(iseq, lineno, flags, node->type, statements, predicate, ret, src, popped, scope_node);
6443 return;
6444 }
6445 case PM_WHEN_NODE: {
6446 rb_bug("Should not ever enter a when node directly");
6447 return;
6448 }
6449 case PM_WHILE_NODE: {
6450 pm_while_node_t *while_node = (pm_while_node_t *)node;
6451 pm_statements_node_t *statements = while_node->statements;
6452 pm_node_t *predicate = while_node->predicate;
6453 pm_node_flags_t flags = node->flags;
6454
6455 pm_compile_while(iseq, lineno, flags, node->type, statements, predicate, ret, src, popped, scope_node);
6456 return;
6457 }
6458 case PM_X_STRING_NODE: {
6459 pm_x_string_node_t *cast = (pm_x_string_node_t *) node;
6460 VALUE value = parse_string_encoded(node, &cast->unescaped, parser);
6461
6462 PM_PUTSELF;
6463 ADD_INSN1(ret, &dummy_line_node, putobject, value);
6464 ADD_SEND_WITH_FLAG(ret, &dummy_line_node, idBackquote, INT2NUM(1), INT2FIX(VM_CALL_FCALL | VM_CALL_ARGS_SIMPLE));
6465
6466 PM_POP_IF_POPPED;
6467 return;
6468 }
6469 case PM_YIELD_NODE: {
6470 pm_yield_node_t *yield_node = (pm_yield_node_t *)node;
6471
6472 int flags = 0;
6473 struct rb_callinfo_kwarg *keywords = NULL;
6474
6475 int argc = 0;
6476
6477 if (yield_node->arguments) {
6478 argc = pm_setup_args(yield_node->arguments, &flags, &keywords, iseq, ret, src, popped, scope_node, dummy_line_node, parser);
6479 }
6480
6481 ADD_INSN1(ret, &dummy_line_node, invokeblock, new_callinfo(iseq, 0, argc, flags, keywords, FALSE));
6482
6483 PM_POP_IF_POPPED;
6484
6485 int level = 0;
6486 const rb_iseq_t *tmp_iseq = iseq;
6487 for (; tmp_iseq != ISEQ_BODY(iseq)->local_iseq; level++ ) {
6488 tmp_iseq = ISEQ_BODY(tmp_iseq)->parent_iseq;
6489 }
6490
6491 if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
6492
6493 return;
6494 }
6495 default:
6496 rb_raise(rb_eNotImpError, "node type %s not implemented", pm_node_type_to_str(PM_NODE_TYPE(node)));
6497 return;
6498 }
6499}
6500
6501static VALUE
6502rb_translate_prism(pm_parser_t *parser, rb_iseq_t *iseq, pm_scope_node_t *scope_node, LINK_ANCHOR *const ret)
6503{
6504 RUBY_ASSERT(ISEQ_COMPILE_DATA(iseq));
6505
6506 ID *constants = calloc(parser->constant_pool.size, sizeof(ID));
6507 rb_encoding *encoding = rb_enc_find(parser->encoding->name);
6508 for (uint32_t index = 0; index < parser->constant_pool.size; index++) {
6509 pm_constant_t *constant = &parser->constant_pool.constants[index];
6510 constants[index] = rb_intern3((const char *) constant->start, constant->length, encoding);
6511 }
6512
6513 st_table *index_lookup_table = st_init_numtable();
6514 pm_constant_id_list_t *locals = &scope_node->locals;
6515 for (size_t i = 0; i < locals->size; i++) {
6516 st_insert(index_lookup_table, locals->ids[i], i);
6517 }
6518 scope_node->constants = constants;
6519 scope_node->index_lookup_table = index_lookup_table;
6520
6521 pm_compile_node(iseq, (pm_node_t *)scope_node, ret, scope_node->base.location.start, false, (pm_scope_node_t *)scope_node);
6522 iseq_set_sequence(iseq, ret);
6523
6524 free(constants);
6525 return Qnil;
6526}
6527
6528#undef NEW_ISEQ
6529#define NEW_ISEQ OLD_ISEQ
6530
6531#undef NEW_CHILD_ISEQ
6532#define NEW_CHILD_ISEQ OLD_CHILD_ISEQ
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:177
@ PM_RANGE_FLAGS_EXCLUDE_END
... operator
Definition ast.h:4535
pm_node_type
This enum represents every type of node in the Ruby syntax tree.
Definition ast.h:570
@ PM_DEFINED_NODE
DefinedNode.
Definition ast.h:707
@ PM_PRE_EXECUTION_NODE
PreExecutionNode.
Definition ast.h:923
@ PM_RETRY_NODE
RetryNode.
Definition ast.h:956
@ PM_REDO_NODE
RedoNode.
Definition ast.h:935
@ PM_CONSTANT_PATH_WRITE_NODE
ConstantPathWriteNode.
Definition ast.h:692
@ PM_INDEX_AND_WRITE_NODE
IndexAndWriteNode.
Definition ast.h:785
@ PM_SOURCE_LINE_NODE
SourceLineNode.
Definition ast.h:974
@ PM_UNLESS_NODE
UnlessNode.
Definition ast.h:998
@ PM_EMBEDDED_VARIABLE_NODE
EmbeddedVariableNode.
Definition ast.h:716
@ PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE
GlobalVariableOperatorWriteNode.
Definition ast.h:749
@ PM_CALL_NODE
CallNode.
Definition ast.h:626
@ PM_NIL_NODE
NilNode.
Definition ast.h:887
@ PM_GLOBAL_VARIABLE_READ_NODE
GlobalVariableReadNode.
Definition ast.h:755
@ PM_RATIONAL_NODE
RationalNode.
Definition ast.h:932
@ PM_YIELD_NODE
YieldNode.
Definition ast.h:1013
@ PM_LOCAL_VARIABLE_AND_WRITE_NODE
LocalVariableAndWriteNode.
Definition ast.h:842
@ PM_CONSTANT_AND_WRITE_NODE
ConstantAndWriteNode.
Definition ast.h:668
@ PM_CLASS_NODE
ClassNode.
Definition ast.h:647
@ PM_FIND_PATTERN_NODE
FindPatternNode.
Definition ast.h:725
@ PM_CALL_OPERATOR_WRITE_NODE
CallOperatorWriteNode.
Definition ast.h:629
@ PM_MATCH_WRITE_NODE
MatchWriteNode.
Definition ast.h:869
@ PM_ARRAY_NODE
ArrayNode.
Definition ast.h:587
@ PM_CONSTANT_PATH_TARGET_NODE
ConstantPathTargetNode.
Definition ast.h:689
@ PM_PROGRAM_NODE
ProgramNode.
Definition ast.h:926
@ PM_OR_NODE
OrNode.
Definition ast.h:905
@ PM_MULTI_WRITE_NODE
MultiWriteNode.
Definition ast.h:881
@ PM_IF_NODE
IfNode.
Definition ast.h:770
@ PM_IMPLICIT_NODE
ImplicitNode.
Definition ast.h:776
@ PM_ARGUMENTS_NODE
ArgumentsNode.
Definition ast.h:584
@ PM_FORWARDING_SUPER_NODE
ForwardingSuperNode.
Definition ast.h:743
@ PM_WHILE_NODE
WhileNode.
Definition ast.h:1007
@ PM_INTERPOLATED_STRING_NODE
InterpolatedStringNode.
Definition ast.h:824
@ PM_FALSE_NODE
FalseNode.
Definition ast.h:722
@ PM_FORWARDING_PARAMETER_NODE
ForwardingParameterNode.
Definition ast.h:740
@ PM_HASH_NODE
HashNode.
Definition ast.h:764
@ PM_UNTIL_NODE
UntilNode.
Definition ast.h:1001
@ PM_MATCH_PREDICATE_NODE
MatchPredicateNode.
Definition ast.h:863
@ PM_X_STRING_NODE
XStringNode.
Definition ast.h:1010
@ PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE
LocalVariableOperatorWriteNode.
Definition ast.h:845
@ PM_LOCAL_VARIABLE_OR_WRITE_NODE
LocalVariableOrWriteNode.
Definition ast.h:848
@ PM_INSTANCE_VARIABLE_AND_WRITE_NODE
InstanceVariableAndWriteNode.
Definition ast.h:797
@ PM_GLOBAL_VARIABLE_TARGET_NODE
GlobalVariableTargetNode.
Definition ast.h:758
@ PM_AND_NODE
AndNode.
Definition ast.h:581
@ PM_CONSTANT_TARGET_NODE
ConstantTargetNode.
Definition ast.h:698
@ PM_CONSTANT_PATH_AND_WRITE_NODE
ConstantPathAndWriteNode.
Definition ast.h:677
@ PM_IN_NODE
InNode.
Definition ast.h:782
@ PM_CAPTURE_PATTERN_NODE
CapturePatternNode.
Definition ast.h:638
@ PM_SOURCE_FILE_NODE
SourceFileNode.
Definition ast.h:971
@ PM_NO_KEYWORDS_PARAMETER_NODE
NoKeywordsParameterNode.
Definition ast.h:890
@ PM_CONSTANT_PATH_OPERATOR_WRITE_NODE
ConstantPathOperatorWriteNode.
Definition ast.h:683
@ PM_MULTI_TARGET_NODE
MultiTargetNode.
Definition ast.h:878
@ PM_SPLAT_NODE
SplatNode.
Definition ast.h:977
@ PM_LAMBDA_NODE
LambdaNode.
Definition ast.h:839
@ PM_CLASS_VARIABLE_READ_NODE
ClassVariableReadNode.
Definition ast.h:659
@ PM_REQUIRED_KEYWORD_PARAMETER_NODE
RequiredKeywordParameterNode.
Definition ast.h:941
@ PM_CALL_TARGET_NODE
CallTargetNode.
Definition ast.h:635
@ PM_ELSE_NODE
ElseNode.
Definition ast.h:710
@ PM_INTERPOLATED_MATCH_LAST_LINE_NODE
InterpolatedMatchLastLineNode.
Definition ast.h:818
@ PM_WHEN_NODE
WhenNode.
Definition ast.h:1004
@ PM_NUMBERED_PARAMETERS_NODE
NumberedParametersNode.
Definition ast.h:893
@ PM_SYMBOL_NODE
SymbolNode.
Definition ast.h:989
@ PM_RESCUE_MODIFIER_NODE
RescueModifierNode.
Definition ast.h:947
@ PM_ALIAS_METHOD_NODE
AliasMethodNode.
Definition ast.h:575
@ PM_MATCH_REQUIRED_NODE
MatchRequiredNode.
Definition ast.h:866
@ PM_FORWARDING_ARGUMENTS_NODE
ForwardingArgumentsNode.
Definition ast.h:737
@ PM_BACK_REFERENCE_READ_NODE
BackReferenceReadNode.
Definition ast.h:599
@ PM_SCOPE_NODE
A special kind of node used for compilation.
Definition ast.h:1016
@ PM_BLOCK_ARGUMENT_NODE
BlockArgumentNode.
Definition ast.h:605
@ PM_MISSING_NODE
MissingNode.
Definition ast.h:872
@ PM_SELF_NODE
SelfNode.
Definition ast.h:962
@ PM_IMPLICIT_REST_NODE
ImplicitRestNode.
Definition ast.h:779
@ PM_TRUE_NODE
TrueNode.
Definition ast.h:992
@ PM_ASSOC_SPLAT_NODE
AssocSplatNode.
Definition ast.h:596
@ PM_CLASS_VARIABLE_AND_WRITE_NODE
ClassVariableAndWriteNode.
Definition ast.h:650
@ PM_RANGE_NODE
RangeNode.
Definition ast.h:929
@ PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE
InstanceVariableOperatorWriteNode.
Definition ast.h:800
@ PM_LOCAL_VARIABLE_READ_NODE
LocalVariableReadNode.
Definition ast.h:851
@ PM_NEXT_NODE
NextNode.
Definition ast.h:884
@ PM_INSTANCE_VARIABLE_OR_WRITE_NODE
InstanceVariableOrWriteNode.
Definition ast.h:803
@ PM_REGULAR_EXPRESSION_NODE
RegularExpressionNode.
Definition ast.h:938
@ PM_CLASS_VARIABLE_OR_WRITE_NODE
ClassVariableOrWriteNode.
Definition ast.h:656
@ PM_BLOCK_PARAMETERS_NODE
BlockParametersNode.
Definition ast.h:617
@ PM_CONSTANT_WRITE_NODE
ConstantWriteNode.
Definition ast.h:701
@ PM_HASH_PATTERN_NODE
HashPatternNode.
Definition ast.h:767
@ PM_INDEX_OPERATOR_WRITE_NODE
IndexOperatorWriteNode.
Definition ast.h:788
@ PM_UNDEF_NODE
UndefNode.
Definition ast.h:995
@ PM_ALTERNATION_PATTERN_NODE
AlternationPatternNode.
Definition ast.h:578
@ PM_ENSURE_NODE
EnsureNode.
Definition ast.h:719
@ PM_LOCAL_VARIABLE_WRITE_NODE
LocalVariableWriteNode.
Definition ast.h:857
@ PM_SINGLETON_CLASS_NODE
SingletonClassNode.
Definition ast.h:965
@ PM_KEYWORD_HASH_NODE
KeywordHashNode.
Definition ast.h:833
@ PM_PARENTHESES_NODE
ParenthesesNode.
Definition ast.h:911
@ PM_FOR_NODE
ForNode.
Definition ast.h:734
@ PM_CLASS_VARIABLE_WRITE_NODE
ClassVariableWriteNode.
Definition ast.h:665
@ PM_POST_EXECUTION_NODE
PostExecutionNode.
Definition ast.h:920
@ PM_CONSTANT_OPERATOR_WRITE_NODE
ConstantOperatorWriteNode.
Definition ast.h:671
@ PM_RETURN_NODE
ReturnNode.
Definition ast.h:959
@ PM_MODULE_NODE
ModuleNode.
Definition ast.h:875
@ PM_ARRAY_PATTERN_NODE
ArrayPatternNode.
Definition ast.h:590
@ PM_SUPER_NODE
SuperNode.
Definition ast.h:986
@ PM_MATCH_LAST_LINE_NODE
MatchLastLineNode.
Definition ast.h:860
@ PM_CONSTANT_PATH_NODE
ConstantPathNode.
Definition ast.h:680
@ PM_INTERPOLATED_SYMBOL_NODE
InterpolatedSymbolNode.
Definition ast.h:827
@ PM_CALL_AND_WRITE_NODE
CallAndWriteNode.
Definition ast.h:623
@ PM_OPTIONAL_KEYWORD_PARAMETER_NODE
OptionalKeywordParameterNode.
Definition ast.h:899
@ PM_CLASS_VARIABLE_TARGET_NODE
ClassVariableTargetNode.
Definition ast.h:662
@ PM_CASE_MATCH_NODE
CaseMatchNode.
Definition ast.h:641
@ PM_BREAK_NODE
BreakNode.
Definition ast.h:620
@ PM_CALL_OR_WRITE_NODE
CallOrWriteNode.
Definition ast.h:632
@ PM_IMAGINARY_NODE
ImaginaryNode.
Definition ast.h:773
@ PM_DEF_NODE
DefNode.
Definition ast.h:704
@ PM_CONSTANT_READ_NODE
ConstantReadNode.
Definition ast.h:695
@ PM_GLOBAL_VARIABLE_WRITE_NODE
GlobalVariableWriteNode.
Definition ast.h:761
@ PM_SOURCE_ENCODING_NODE
SourceEncodingNode.
Definition ast.h:968
@ PM_BEGIN_NODE
BeginNode.
Definition ast.h:602
@ PM_INTERPOLATED_X_STRING_NODE
InterpolatedXStringNode.
Definition ast.h:830
@ PM_INSTANCE_VARIABLE_READ_NODE
InstanceVariableReadNode.
Definition ast.h:806
@ PM_FLIP_FLOP_NODE
FlipFlopNode.
Definition ast.h:728
@ PM_PINNED_VARIABLE_NODE
PinnedVariableNode.
Definition ast.h:917
@ PM_REQUIRED_PARAMETER_NODE
RequiredParameterNode.
Definition ast.h:944
@ PM_INSTANCE_VARIABLE_WRITE_NODE
InstanceVariableWriteNode.
Definition ast.h:812
@ PM_INSTANCE_VARIABLE_TARGET_NODE
InstanceVariableTargetNode.
Definition ast.h:809
@ PM_GLOBAL_VARIABLE_AND_WRITE_NODE
GlobalVariableAndWriteNode.
Definition ast.h:746
@ PM_CASE_NODE
CaseNode.
Definition ast.h:644
@ PM_RESCUE_NODE
RescueNode.
Definition ast.h:950
@ PM_FLOAT_NODE
FloatNode.
Definition ast.h:731
@ PM_ASSOC_NODE
AssocNode.
Definition ast.h:593
@ PM_INTEGER_NODE
IntegerNode.
Definition ast.h:815
@ PM_LOCAL_VARIABLE_TARGET_NODE
LocalVariableTargetNode.
Definition ast.h:854
@ PM_STRING_NODE
StringNode.
Definition ast.h:983
@ PM_INDEX_OR_WRITE_NODE
IndexOrWriteNode.
Definition ast.h:791
@ PM_ALIAS_GLOBAL_VARIABLE_NODE
AliasGlobalVariableNode.
Definition ast.h:572
@ PM_PARAMETERS_NODE
ParametersNode.
Definition ast.h:908
@ PM_NUMBERED_REFERENCE_READ_NODE
NumberedReferenceReadNode.
Definition ast.h:896
@ PM_CONSTANT_PATH_OR_WRITE_NODE
ConstantPathOrWriteNode.
Definition ast.h:686
@ PM_GLOBAL_VARIABLE_OR_WRITE_NODE
GlobalVariableOrWriteNode.
Definition ast.h:752
@ PM_CONSTANT_OR_WRITE_NODE
ConstantOrWriteNode.
Definition ast.h:674
@ PM_STATEMENTS_NODE
StatementsNode.
Definition ast.h:980
@ PM_OPTIONAL_PARAMETER_NODE
OptionalParameterNode.
Definition ast.h:902
@ PM_PINNED_EXPRESSION_NODE
PinnedExpressionNode.
Definition ast.h:914
@ PM_BLOCK_NODE
BlockNode.
Definition ast.h:611
@ PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE
ClassVariableOperatorWriteNode.
Definition ast.h:653
@ PM_EMBEDDED_STATEMENTS_NODE
EmbeddedStatementsNode.
Definition ast.h:713
@ PM_INTERPOLATED_REGULAR_EXPRESSION_NODE
InterpolatedRegularExpressionNode.
Definition ast.h:821
@ PM_INDEX_TARGET_NODE
IndexTargetNode.
Definition ast.h:794
@ PM_KEYWORD_REST_PARAMETER_NODE
KeywordRestParameterNode.
Definition ast.h:836
@ PM_STRING_FLAGS_FROZEN
frozen by virtue of a frozen_string_literal comment
Definition ast.h:4587
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT
if arguments contain keyword splat
Definition ast.h:4461
#define PM_NODE_FLAG_P(node, flag)
Return true if the given flag is set on the given node.
Definition ast.h:1055
#define PM_NODE_TYPE_P(node, type)
Return true if the type of the given node matches the given type.
Definition ast.h:1050
#define PM_NODE_TYPE(node)
Cast the type to an enum to allow the compiler to provide exhaustiveness checking.
Definition ast.h:1045
@ PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT
if array contains splat nodes
Definition ast.h:4469
@ PM_INTEGER_BASE_FLAGS_HEXADECIMAL
0x prefix
Definition ast.h:4511
@ PM_INTEGER_BASE_FLAGS_OCTAL
0o or 0 prefix
Definition ast.h:4508
@ PM_INTEGER_BASE_FLAGS_DECIMAL
0d or no prefix
Definition ast.h:4505
@ PM_INTEGER_BASE_FLAGS_BINARY
0b prefix
Definition ast.h:4502
@ PM_CALL_NODE_FLAGS_SAFE_NAVIGATION
&.
Definition ast.h:4477
@ PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE
a call that is an attribute write, so the value being written should be returned
Definition ast.h:4483
@ PM_CALL_NODE_FLAGS_VARIABLE_CALL
a call that could have been a local variable
Definition ast.h:4480
uint16_t pm_node_type_t
This is the type of node embedded in the node struct.
Definition ast.h:1023
@ PM_REGULAR_EXPRESSION_FLAGS_EUC_JP
e - forces the EUC-JP encoding
Definition ast.h:4555
@ PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE
i - ignores the case of characters when matching
Definition ast.h:4543
@ PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT
n - forces the ASCII-8BIT encoding
Definition ast.h:4558
@ PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE
m - allows $ to match the end of lines within strings
Definition ast.h:4549
@ PM_REGULAR_EXPRESSION_FLAGS_EXTENDED
x - ignores whitespace and allows comments in regular expressions
Definition ast.h:4546
@ PM_REGULAR_EXPRESSION_FLAGS_ONCE
o - only interpolates values into the regular expression once
Definition ast.h:4552
@ PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J
s - forces the Windows-31J encoding
Definition ast.h:4561
@ PM_REGULAR_EXPRESSION_FLAGS_UTF_8
u - forces the UTF-8 encoding
Definition ast.h:4564
uint16_t pm_node_flags_t
These are the flags embedded in the node struct.
Definition ast.h:1029
@ PM_ENCODING_FLAGS_FORCED_BINARY_ENCODING
internal bytes forced the encoding to binary
Definition ast.h:4494
@ PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
Definition ast.h:4491
@ PM_LOOP_FLAGS_BEGIN_MODIFIER
a loop after a begin statement, so the body is executed first before the condition
Definition ast.h:4527
#define RUBY_EVENT_B_RETURN
Encountered a next statement.
Definition event.h:56
#define RUBY_EVENT_LINE
Encountered a new line.
Definition event.h:38
#define RUBY_EVENT_RETURN
Encountered a return statement.
Definition event.h:42
#define RUBY_EVENT_B_CALL
Encountered an yield statement.
Definition event.h:55
#define RUBY_EVENT_RESCUE
Encountered a rescue statement.
Definition event.h:61
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
#define ALLOCV
Old name of RB_ALLOCV.
Definition memory.h:398
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
#define ID2SYM
Old name of RB_ID2SYM.
Definition symbol.h:44
#define SPECIAL_CONST_P
Old name of RB_SPECIAL_CONST_P.
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
#define ZALLOC_N
Old name of RB_ZALLOC_N.
Definition memory.h:395
#define T_HASH
Old name of RUBY_T_HASH.
Definition value_type.h:65
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:393
#define Qtrue
Old name of RUBY_Qtrue.
#define INT2NUM
Old name of RB_INT2NUM.
Definition int.h:43
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define T_ARRAY
Old name of RUBY_T_ARRAY.
Definition value_type.h:56
#define NIL_P
Old name of RB_NIL_P.
#define DBL2NUM
Old name of rb_float_new.
Definition double.h:29
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
VALUE rb_eNotImpError
NotImplementedError exception.
Definition error.c:1354
VALUE rb_eStandardError
StandardError exception.
Definition error.c:1341
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1344
VALUE rb_eNoMatchingPatternError
NoMatchingPatternError exception.
Definition error.c:1357
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:423
VALUE rb_eNoMatchingPatternKeyError
NoMatchingPatternKeyError exception.
Definition error.c:1358
double rb_cstr_to_dbl(const char *str, int mode)
Converts a textual representation of a real number into a numeric, which is the nearest value that th...
Definition object.c:3390
#define RB_OBJ_WRITTEN(old, oldv, young)
Identical to RB_OBJ_WRITE(), except it doesn't write any values, but only a WB declaration.
Definition gc.h:631
VALUE rb_enc_reg_new(const char *ptr, long len, rb_encoding *enc, int opts)
Identical to rb_reg_new(), except it additionally takes an encoding.
Definition re.c:3394
VALUE rb_range_new(VALUE beg, VALUE end, int excl)
Creates a new Range.
Definition range.c:67
VALUE rb_rational_raw(VALUE num, VALUE den)
Identical to rb_rational_new(), except it skips argument validations.
Definition rational.c:1955
VALUE rb_reg_new(const char *src, long len, int opts)
Creates a new Regular expression.
Definition re.c:3408
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1532
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
Definition string.c:3500
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:2999
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
int len
Length of the buffer.
Definition io.h:8
VALUE type(ANYARGS)
ANYARGS-ed function type.
#define PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS
Temporary alias for the PM_NODE_FLAG_STATIC_KEYS flag.
Definition parser.h:24
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
The main header file for the prism parser.
#define RARRAY_LEN
Just another name of rb_array_len.
Definition rarray.h:51
#define RARRAY_AREF(a, i)
Definition rarray.h:403
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr.
Definition rarray.h:52
AliasGlobalVariableNode.
Definition ast.h:1088
struct pm_node * old_name
AliasGlobalVariableNode#old_name.
Definition ast.h:1096
struct pm_node * new_name
AliasGlobalVariableNode#new_name.
Definition ast.h:1093
AliasMethodNode.
Definition ast.h:1109
struct pm_node * old_name
AliasMethodNode#old_name.
Definition ast.h:1117
struct pm_node * new_name
AliasMethodNode#new_name.
Definition ast.h:1114
AlternationPatternNode.
Definition ast.h:1130
struct pm_node * left
AlternationPatternNode#left.
Definition ast.h:1135
struct pm_node * right
AlternationPatternNode#right.
Definition ast.h:1138
AndNode.
Definition ast.h:1151
struct pm_node * left
AndNode#left.
Definition ast.h:1156
struct pm_node * right
AndNode#right.
Definition ast.h:1159
ArgumentsNode.
Definition ast.h:1174
pm_node_t base
The embedded base node.
Definition ast.h:1176
struct pm_node_list arguments
ArgumentsNode#arguments.
Definition ast.h:1179
ArrayNode.
Definition ast.h:1191
pm_node_t base
The embedded base node.
Definition ast.h:1193
struct pm_node_list elements
ArrayNode#elements.
Definition ast.h:1196
ArrayPatternNode.
Definition ast.h:1212
struct pm_node_list requireds
ArrayPatternNode#requireds.
Definition ast.h:1220
struct pm_node * rest
ArrayPatternNode#rest.
Definition ast.h:1223
struct pm_node * constant
ArrayPatternNode#constant.
Definition ast.h:1217
struct pm_node_list posts
ArrayPatternNode#posts.
Definition ast.h:1226
AssocNode.
Definition ast.h:1242
struct pm_node * value
AssocNode#value.
Definition ast.h:1250
struct pm_node * key
AssocNode#key.
Definition ast.h:1247
AssocSplatNode.
Definition ast.h:1263
struct pm_node * value
AssocSplatNode#value.
Definition ast.h:1268
BeginNode.
Definition ast.h:1296
struct pm_ensure_node * ensure_clause
BeginNode#ensure_clause.
Definition ast.h:1313
struct pm_rescue_node * rescue_clause
BeginNode#rescue_clause.
Definition ast.h:1307
struct pm_statements_node * statements
BeginNode#statements.
Definition ast.h:1304
struct pm_else_node * else_clause
BeginNode#else_clause.
Definition ast.h:1310
BlockArgumentNode.
Definition ast.h:1326
struct pm_node * expression
BlockArgumentNode#expression.
Definition ast.h:1331
BlockLocalVariableNode.
Definition ast.h:1344
BlockNode.
Definition ast.h:1359
struct pm_node * parameters
BlockNode#parameters.
Definition ast.h:1370
struct pm_node * body
BlockNode#body.
Definition ast.h:1373
pm_constant_id_list_t locals
BlockNode#locals.
Definition ast.h:1364
BlockParameterNode.
Definition ast.h:1389
BlockParametersNode.
Definition ast.h:1410
BreakNode.
Definition ast.h:1434
struct pm_arguments_node * arguments
BreakNode#arguments.
Definition ast.h:1439
CallAndWriteNode.
Definition ast.h:1456
struct pm_node * value
CallAndWriteNode#value.
Definition ast.h:1479
pm_constant_id_t read_name
CallAndWriteNode#read_name.
Definition ast.h:1470
pm_constant_id_t write_name
CallAndWriteNode#write_name.
Definition ast.h:1473
struct pm_node * receiver
CallAndWriteNode#receiver.
Definition ast.h:1461
CallNode.
Definition ast.h:1493
struct pm_node * receiver
CallNode#receiver.
Definition ast.h:1498
pm_constant_id_t name
CallNode::name.
Definition ast.h:1504
struct pm_arguments_node * arguments
CallNode#arguments.
Definition ast.h:1513
struct pm_node * block
CallNode#block.
Definition ast.h:1519
CallOperatorWriteNode.
Definition ast.h:1533
pm_constant_id_t read_name
CallOperatorWriteNode#read_name.
Definition ast.h:1547
struct pm_node * receiver
CallOperatorWriteNode#receiver.
Definition ast.h:1538
pm_constant_id_t write_name
CallOperatorWriteNode#write_name.
Definition ast.h:1550
pm_constant_id_t operator
CallOperatorWriteNode#operator.
Definition ast.h:1553
struct pm_node * value
CallOperatorWriteNode#value.
Definition ast.h:1559
CallOrWriteNode.
Definition ast.h:1573
struct pm_node * receiver
CallOrWriteNode#receiver.
Definition ast.h:1578
struct pm_node * value
CallOrWriteNode#value.
Definition ast.h:1596
pm_constant_id_t write_name
CallOrWriteNode#write_name.
Definition ast.h:1590
pm_constant_id_t read_name
CallOrWriteNode#read_name.
Definition ast.h:1587
CallTargetNode.
Definition ast.h:1610
pm_constant_id_t name
CallTargetNode#name.
Definition ast.h:1621
struct pm_node * receiver
CallTargetNode#receiver.
Definition ast.h:1615
CapturePatternNode.
Definition ast.h:1634
struct pm_node * target
CapturePatternNode#target.
Definition ast.h:1642
struct pm_node * value
CapturePatternNode#value.
Definition ast.h:1639
CaseMatchNode.
Definition ast.h:1655
struct pm_node_list conditions
CaseMatchNode#conditions.
Definition ast.h:1663
struct pm_else_node * consequent
CaseMatchNode#consequent.
Definition ast.h:1666
struct pm_node * predicate
CaseMatchNode#predicate.
Definition ast.h:1660
CaseNode.
Definition ast.h:1682
struct pm_node * predicate
CaseNode#predicate.
Definition ast.h:1687
struct pm_else_node * consequent
CaseNode#consequent.
Definition ast.h:1693
struct pm_node_list conditions
CaseNode#conditions.
Definition ast.h:1690
ClassNode.
Definition ast.h:1709
struct pm_node * constant_path
ClassNode#constant_path.
Definition ast.h:1720
pm_constant_id_list_t locals
ClassNode#locals.
Definition ast.h:1714
pm_constant_id_t name
ClassNode#name.
Definition ast.h:1735
struct pm_node * body
ClassNode#body.
Definition ast.h:1729
struct pm_node * superclass
ClassNode#superclass.
Definition ast.h:1726
ClassVariableAndWriteNode.
Definition ast.h:1745
struct pm_node * value
ClassVariableAndWriteNode#value.
Definition ast.h:1759
pm_constant_id_t name
ClassVariableAndWriteNode#name.
Definition ast.h:1750
ClassVariableOperatorWriteNode.
Definition ast.h:1769
pm_constant_id_t name
ClassVariableOperatorWriteNode#name.
Definition ast.h:1774
pm_constant_id_t operator
ClassVariableOperatorWriteNode#operator.
Definition ast.h:1786
struct pm_node * value
ClassVariableOperatorWriteNode#value.
Definition ast.h:1783
ClassVariableOrWriteNode.
Definition ast.h:1796
pm_constant_id_t name
ClassVariableOrWriteNode#name.
Definition ast.h:1801
struct pm_node * value
ClassVariableOrWriteNode#value.
Definition ast.h:1810
ClassVariableReadNode.
Definition ast.h:1820
pm_constant_id_t name
ClassVariableReadNode#name.
Definition ast.h:1825
ClassVariableTargetNode.
Definition ast.h:1835
pm_constant_id_t name
ClassVariableTargetNode#name.
Definition ast.h:1840
ClassVariableWriteNode.
Definition ast.h:1850
struct pm_node * value
ClassVariableWriteNode#value.
Definition ast.h:1861
pm_constant_id_t name
ClassVariableWriteNode#name.
Definition ast.h:1855
ConstantAndWriteNode.
Definition ast.h:1874
pm_constant_id_t name
ConstantAndWriteNode#name.
Definition ast.h:1879
struct pm_node * value
ConstantAndWriteNode#value.
Definition ast.h:1888
A list of constant IDs.
size_t size
The number of constant ids in the list.
pm_constant_id_t * ids
The constant ids in the list.
ConstantOperatorWriteNode.
Definition ast.h:1898
pm_constant_id_t name
ConstantOperatorWriteNode#name.
Definition ast.h:1903
pm_constant_id_t operator
ConstantOperatorWriteNode#operator.
Definition ast.h:1915
struct pm_node * value
ConstantOperatorWriteNode#value.
Definition ast.h:1912
ConstantOrWriteNode.
Definition ast.h:1925
pm_constant_id_t name
ConstantOrWriteNode#name.
Definition ast.h:1930
struct pm_node * value
ConstantOrWriteNode#value.
Definition ast.h:1939
ConstantPathAndWriteNode.
Definition ast.h:1949
struct pm_constant_path_node * target
ConstantPathAndWriteNode#target.
Definition ast.h:1954
struct pm_node * value
ConstantPathAndWriteNode#value.
Definition ast.h:1960
ConstantPathNode.
Definition ast.h:1970
struct pm_node * child
ConstantPathNode#child.
Definition ast.h:1978
struct pm_node * parent
ConstantPathNode#parent.
Definition ast.h:1975
ConstantPathOperatorWriteNode.
Definition ast.h:1991
pm_constant_id_t operator
ConstantPathOperatorWriteNode#operator.
Definition ast.h:2005
struct pm_constant_path_node * target
ConstantPathOperatorWriteNode#target.
Definition ast.h:1996
struct pm_node * value
ConstantPathOperatorWriteNode#value.
Definition ast.h:2002
ConstantPathOrWriteNode.
Definition ast.h:2015
struct pm_node * value
ConstantPathOrWriteNode#value.
Definition ast.h:2026
struct pm_constant_path_node * target
ConstantPathOrWriteNode#target.
Definition ast.h:2020
ConstantPathTargetNode.
Definition ast.h:2036
struct pm_node * parent
ConstantPathTargetNode#parent.
Definition ast.h:2041
struct pm_node * child
ConstantPathTargetNode#child.
Definition ast.h:2044
ConstantPathWriteNode.
Definition ast.h:2057
struct pm_constant_path_node * target
ConstantPathWriteNode#target.
Definition ast.h:2062
struct pm_node * value
ConstantPathWriteNode#value.
Definition ast.h:2068
uint32_t size
The number of buckets in the hash map.
pm_constant_t * constants
The constants that are stored in the buckets.
ConstantReadNode.
Definition ast.h:2078
pm_constant_id_t name
ConstantReadNode#name.
Definition ast.h:2083
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
ConstantTargetNode.
Definition ast.h:2093
pm_constant_id_t name
ConstantTargetNode#name.
Definition ast.h:2098
ConstantWriteNode.
Definition ast.h:2108
struct pm_node * value
ConstantWriteNode#value.
Definition ast.h:2119
pm_constant_id_t name
ConstantWriteNode#name.
Definition ast.h:2113
DefNode.
Definition ast.h:2132
struct pm_parameters_node * parameters
DefNode#parameters.
Definition ast.h:2146
pm_constant_id_t name
DefNode#name.
Definition ast.h:2137
struct pm_node * receiver
DefNode#receiver.
Definition ast.h:2143
DefinedNode.
Definition ast.h:2183
struct pm_node * value
DefinedNode#value.
Definition ast.h:2191
ElseNode.
Definition ast.h:2207
struct pm_statements_node * statements
ElseNode#statements.
Definition ast.h:2215
EmbeddedStatementsNode.
Definition ast.h:2228
struct pm_statements_node * statements
EmbeddedStatementsNode#statements.
Definition ast.h:2236
EmbeddedVariableNode.
Definition ast.h:2249
struct pm_node * variable
EmbeddedVariableNode#variable.
Definition ast.h:2257
const char * name
The name of the encoding.
Definition encoding.h:56
EnsureNode.
Definition ast.h:2267
struct pm_statements_node * statements
EnsureNode#statements.
Definition ast.h:2275
FindPatternNode.
Definition ast.h:2300
struct pm_node * left
FindPatternNode#left.
Definition ast.h:2308
struct pm_node * constant
FindPatternNode#constant.
Definition ast.h:2305
struct pm_node * right
FindPatternNode#right.
Definition ast.h:2314
struct pm_node_list requireds
FindPatternNode#requireds.
Definition ast.h:2311
FlipFlopNode.
Definition ast.h:2332
pm_node_t base
The embedded base node.
Definition ast.h:2334
struct pm_node * left
FlipFlopNode#left.
Definition ast.h:2337
struct pm_node * right
FlipFlopNode#right.
Definition ast.h:2340
ForNode.
Definition ast.h:2365
struct pm_statements_node * statements
ForNode#statements.
Definition ast.h:2376
struct pm_node * index
ForNode#index.
Definition ast.h:2370
struct pm_node * collection
ForNode#collection.
Definition ast.h:2373
ForwardingSuperNode.
Definition ast.h:2422
struct pm_block_node * block
ForwardingSuperNode#block.
Definition ast.h:2427
GlobalVariableAndWriteNode.
Definition ast.h:2437
struct pm_node * value
GlobalVariableAndWriteNode#value.
Definition ast.h:2451
pm_constant_id_t name
GlobalVariableAndWriteNode#name.
Definition ast.h:2442
GlobalVariableOperatorWriteNode.
Definition ast.h:2461
pm_constant_id_t name
GlobalVariableOperatorWriteNode#name.
Definition ast.h:2466
pm_constant_id_t operator
GlobalVariableOperatorWriteNode#operator.
Definition ast.h:2478
struct pm_node * value
GlobalVariableOperatorWriteNode#value.
Definition ast.h:2475
GlobalVariableOrWriteNode.
Definition ast.h:2488
pm_constant_id_t name
GlobalVariableOrWriteNode#name.
Definition ast.h:2493
struct pm_node * value
GlobalVariableOrWriteNode#value.
Definition ast.h:2502
GlobalVariableReadNode.
Definition ast.h:2512
pm_constant_id_t name
GlobalVariableReadNode#name.
Definition ast.h:2517
GlobalVariableTargetNode.
Definition ast.h:2527
pm_constant_id_t name
GlobalVariableTargetNode#name.
Definition ast.h:2532
GlobalVariableWriteNode.
Definition ast.h:2542
struct pm_node * value
GlobalVariableWriteNode#value.
Definition ast.h:2553
pm_constant_id_t name
GlobalVariableWriteNode#name.
Definition ast.h:2547
HashNode.
Definition ast.h:2566
struct pm_node_list elements
HashNode#elements.
Definition ast.h:2574
HashPatternNode.
Definition ast.h:2587
struct pm_node_list elements
HashPatternNode#elements.
Definition ast.h:2595
struct pm_node * rest
HashPatternNode#rest.
Definition ast.h:2598
struct pm_node * constant
HashPatternNode#constant.
Definition ast.h:2592
IfNode.
Definition ast.h:2614
struct pm_node * consequent
IfNode#consequent.
Definition ast.h:2631
struct pm_node * predicate
IfNode#predicate.
Definition ast.h:2622
struct pm_statements_node * statements
IfNode#statements.
Definition ast.h:2628
ImaginaryNode.
Definition ast.h:2644
struct pm_node * numeric
ImaginaryNode#numeric.
Definition ast.h:2649
ImplicitNode.
Definition ast.h:2659
struct pm_node * value
ImplicitNode#value.
Definition ast.h:2664
InNode.
Definition ast.h:2686
struct pm_statements_node * statements
InNode#statements.
Definition ast.h:2694
struct pm_node * pattern
InNode#pattern.
Definition ast.h:2691
IndexAndWriteNode.
Definition ast.h:2714
struct pm_arguments_node * arguments
IndexAndWriteNode#arguments.
Definition ast.h:2728
struct pm_node * receiver
IndexAndWriteNode#receiver.
Definition ast.h:2719
struct pm_node * value
IndexAndWriteNode#value.
Definition ast.h:2740
struct pm_node * block
IndexAndWriteNode#block.
Definition ast.h:2734
IndexOperatorWriteNode.
Definition ast.h:2754
pm_constant_id_t operator
IndexOperatorWriteNode#operator.
Definition ast.h:2777
struct pm_node * value
IndexOperatorWriteNode#value.
Definition ast.h:2783
struct pm_node * block
IndexOperatorWriteNode#block.
Definition ast.h:2774
struct pm_arguments_node * arguments
IndexOperatorWriteNode#arguments.
Definition ast.h:2768
struct pm_node * receiver
IndexOperatorWriteNode#receiver.
Definition ast.h:2759
IndexOrWriteNode.
Definition ast.h:2797
struct pm_node * receiver
IndexOrWriteNode#receiver.
Definition ast.h:2802
struct pm_node * value
IndexOrWriteNode#value.
Definition ast.h:2823
struct pm_arguments_node * arguments
IndexOrWriteNode#arguments.
Definition ast.h:2811
struct pm_node * block
IndexOrWriteNode#block.
Definition ast.h:2817
IndexTargetNode.
Definition ast.h:2837
struct pm_node * receiver
IndexTargetNode#receiver.
Definition ast.h:2842
struct pm_arguments_node * arguments
IndexTargetNode#arguments.
Definition ast.h:2848
InstanceVariableAndWriteNode.
Definition ast.h:2864
struct pm_node * value
InstanceVariableAndWriteNode#value.
Definition ast.h:2878
pm_constant_id_t name
InstanceVariableAndWriteNode#name.
Definition ast.h:2869
InstanceVariableOperatorWriteNode.
Definition ast.h:2888
struct pm_node * value
InstanceVariableOperatorWriteNode#value.
Definition ast.h:2902
pm_constant_id_t name
InstanceVariableOperatorWriteNode#name.
Definition ast.h:2893
pm_constant_id_t operator
InstanceVariableOperatorWriteNode#operator.
Definition ast.h:2905
InstanceVariableOrWriteNode.
Definition ast.h:2915
struct pm_node * value
InstanceVariableOrWriteNode#value.
Definition ast.h:2929
pm_constant_id_t name
InstanceVariableOrWriteNode#name.
Definition ast.h:2920
InstanceVariableReadNode.
Definition ast.h:2939
pm_constant_id_t name
InstanceVariableReadNode#name.
Definition ast.h:2944
InstanceVariableTargetNode.
Definition ast.h:2954
pm_constant_id_t name
InstanceVariableTargetNode#name.
Definition ast.h:2959
InstanceVariableWriteNode.
Definition ast.h:2969
pm_constant_id_t name
InstanceVariableWriteNode#name.
Definition ast.h:2974
struct pm_node * value
InstanceVariableWriteNode#value.
Definition ast.h:2980
IntegerNode.
Definition ast.h:2998
pm_node_t base
The embedded base node.
Definition ast.h:3000
InterpolatedMatchLastLineNode.
Definition ast.h:3022
struct pm_node_list parts
InterpolatedMatchLastLineNode#parts.
Definition ast.h:3030
InterpolatedRegularExpressionNode.
Definition ast.h:3055
struct pm_node_list parts
InterpolatedRegularExpressionNode#parts.
Definition ast.h:3063
InterpolatedStringNode.
Definition ast.h:3076
struct pm_node_list parts
InterpolatedStringNode#parts.
Definition ast.h:3084
InterpolatedSymbolNode.
Definition ast.h:3097
struct pm_node_list parts
InterpolatedSymbolNode#parts.
Definition ast.h:3105
InterpolatedXStringNode.
Definition ast.h:3118
struct pm_node_list parts
InterpolatedXStringNode#parts.
Definition ast.h:3126
KeywordHashNode.
Definition ast.h:3141
struct pm_node_list elements
KeywordHashNode#elements.
Definition ast.h:3146
KeywordRestParameterNode.
Definition ast.h:3156
LambdaNode.
Definition ast.h:3177
struct pm_node * body
LambdaNode#body.
Definition ast.h:3200
struct pm_node * parameters
LambdaNode#parameters.
Definition ast.h:3197
pm_constant_id_list_t locals
LambdaNode#locals.
Definition ast.h:3182
A line and column in a string.
size_t line
The line number.
Currently, the ADD_INSN family of macros expects a NODE as the second parameter.
LocalVariableAndWriteNode.
Definition ast.h:3210
pm_constant_id_t name
LocalVariableAndWriteNode#name.
Definition ast.h:3224
uint32_t depth
LocalVariableAndWriteNode#depth.
Definition ast.h:3227
struct pm_node * value
LocalVariableAndWriteNode#value.
Definition ast.h:3221
LocalVariableOperatorWriteNode.
Definition ast.h:3237
uint32_t depth
LocalVariableOperatorWriteNode#depth.
Definition ast.h:3257
struct pm_node * value
LocalVariableOperatorWriteNode#value.
Definition ast.h:3248
pm_constant_id_t operator
LocalVariableOperatorWriteNode#operator.
Definition ast.h:3254
pm_constant_id_t name
LocalVariableOperatorWriteNode#name.
Definition ast.h:3251
LocalVariableOrWriteNode.
Definition ast.h:3267
uint32_t depth
LocalVariableOrWriteNode#depth.
Definition ast.h:3284
struct pm_node * value
LocalVariableOrWriteNode#value.
Definition ast.h:3278
pm_constant_id_t name
LocalVariableOrWriteNode#name.
Definition ast.h:3281
LocalVariableReadNode.
Definition ast.h:3294
uint32_t depth
LocalVariableReadNode#depth.
Definition ast.h:3302
pm_constant_id_t name
LocalVariableReadNode#name.
Definition ast.h:3299
LocalVariableTargetNode.
Definition ast.h:3312
uint32_t depth
LocalVariableTargetNode#depth.
Definition ast.h:3320
pm_constant_id_t name
LocalVariableTargetNode#name.
Definition ast.h:3317
LocalVariableWriteNode.
Definition ast.h:3330
struct pm_node * value
LocalVariableWriteNode#value.
Definition ast.h:3344
uint32_t depth
LocalVariableWriteNode#depth.
Definition ast.h:3338
pm_constant_id_t name
LocalVariableWriteNode#name.
Definition ast.h:3335
This represents a range of bytes in the source string to which a node or token corresponds.
Definition ast.h:543
const uint8_t * start
A pointer to the start location of the range in the source.
Definition ast.h:545
const uint8_t * end
A pointer to the end location of the range in the source.
Definition ast.h:548
MatchLastLineNode.
Definition ast.h:3369
pm_string_t unescaped
MatchLastLineNode#unescaped.
Definition ast.h:3383
MatchPredicateNode.
Definition ast.h:3393
struct pm_node * pattern
MatchPredicateNode#pattern.
Definition ast.h:3401
struct pm_node * value
MatchPredicateNode#value.
Definition ast.h:3398
MatchRequiredNode.
Definition ast.h:3414
struct pm_node * value
MatchRequiredNode#value.
Definition ast.h:3419
struct pm_node * pattern
MatchRequiredNode#pattern.
Definition ast.h:3422
MatchWriteNode.
Definition ast.h:3435
struct pm_node_list targets
MatchWriteNode#targets.
Definition ast.h:3443
struct pm_call_node * call
MatchWriteNode#call.
Definition ast.h:3440
ModuleNode.
Definition ast.h:3465
struct pm_node * constant_path
ModuleNode#constant_path.
Definition ast.h:3476
struct pm_node * body
ModuleNode#body.
Definition ast.h:3479
pm_constant_id_list_t locals
ModuleNode#locals.
Definition ast.h:3470
pm_constant_id_t name
ModuleNode#name.
Definition ast.h:3485
MultiTargetNode.
Definition ast.h:3495
struct pm_node_list lefts
MultiTargetNode#lefts.
Definition ast.h:3500
struct pm_node * rest
MultiTargetNode#rest.
Definition ast.h:3503
struct pm_node_list rights
MultiTargetNode#rights.
Definition ast.h:3506
MultiWriteNode.
Definition ast.h:3522
struct pm_node * value
MultiWriteNode#value.
Definition ast.h:3545
struct pm_node * rest
MultiWriteNode#rest.
Definition ast.h:3530
struct pm_node_list rights
MultiWriteNode#rights.
Definition ast.h:3533
struct pm_node_list lefts
MultiWriteNode#lefts.
Definition ast.h:3527
A list of offsets of newlines in a string.
NextNode.
Definition ast.h:3555
struct pm_arguments_node * arguments
NextNode#arguments.
Definition ast.h:3560
A list of nodes in the source, most often used for lists of children.
Definition ast.h:556
size_t size
The number of nodes in the list.
Definition ast.h:558
struct pm_node ** nodes
The nodes in the list.
Definition ast.h:564
This is the base structure that represents a node in the syntax tree.
Definition ast.h:1061
pm_node_type_t type
This represents the type of the node.
Definition ast.h:1066
pm_node_flags_t flags
This represents any flags on the node.
Definition ast.h:1072
pm_location_t location
This is the location of the node in the source.
Definition ast.h:1078
NumberedParametersNode.
Definition ast.h:3603
NumberedReferenceReadNode.
Definition ast.h:3618
OptionalKeywordParameterNode.
Definition ast.h:3633
pm_constant_id_t name
OptionalKeywordParameterNode#name.
Definition ast.h:3638
struct pm_node * value
OptionalKeywordParameterNode#value.
Definition ast.h:3644
OptionalParameterNode.
Definition ast.h:3654
struct pm_node * value
OptionalParameterNode#value.
Definition ast.h:3668
pm_constant_id_t name
OptionalParameterNode#name.
Definition ast.h:3659
OrNode.
Definition ast.h:3678
struct pm_node * left
OrNode#left.
Definition ast.h:3683
struct pm_node * right
OrNode#right.
Definition ast.h:3686
ParametersNode.
Definition ast.h:3699
struct pm_node * rest
ParametersNode#rest.
Definition ast.h:3710
struct pm_node_list requireds
ParametersNode#requireds.
Definition ast.h:3704
struct pm_block_parameter_node * block
ParametersNode#block.
Definition ast.h:3722
struct pm_node_list optionals
ParametersNode#optionals.
Definition ast.h:3707
struct pm_node_list posts
ParametersNode#posts.
Definition ast.h:3713
struct pm_node * keyword_rest
ParametersNode#keyword_rest.
Definition ast.h:3719
struct pm_node_list keywords
ParametersNode#keywords.
Definition ast.h:3716
ParenthesesNode.
Definition ast.h:3732
struct pm_node * body
ParenthesesNode#body.
Definition ast.h:3737
This struct represents the overall parser.
Definition parser.h:489
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
Definition parser.h:584
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
Definition parser.h:615
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
Definition parser.h:618
PinnedExpressionNode.
Definition ast.h:3753
struct pm_node * expression
PinnedExpressionNode#expression.
Definition ast.h:3758
PinnedVariableNode.
Definition ast.h:3777
struct pm_node * variable
PinnedVariableNode#variable.
Definition ast.h:3782
PostExecutionNode.
Definition ast.h:3795
struct pm_statements_node * statements
PostExecutionNode#statements.
Definition ast.h:3800
PreExecutionNode.
Definition ast.h:3819
struct pm_statements_node * statements
PreExecutionNode#statements.
Definition ast.h:3824
ProgramNode.
Definition ast.h:3843
struct pm_statements_node * statements
ProgramNode#statements.
Definition ast.h:3851
RangeNode.
Definition ast.h:3863
struct pm_node * right
RangeNode#right.
Definition ast.h:3871
pm_location_t operator_loc
RangeNode#operator_loc.
Definition ast.h:3874
struct pm_node * left
RangeNode#left.
Definition ast.h:3868
RationalNode.
Definition ast.h:3884
RegularExpressionNode.
Definition ast.h:3923
pm_node_t base
The embedded base node.
Definition ast.h:3925
pm_string_t unescaped
RegularExpressionNode#unescaped.
Definition ast.h:3937
RequiredKeywordParameterNode.
Definition ast.h:3947
RequiredParameterNode.
Definition ast.h:3965
pm_constant_id_t name
RequiredParameterNode#name.
Definition ast.h:3970
RescueModifierNode.
Definition ast.h:3980
struct pm_node * rescue_expression
RescueModifierNode#rescue_expression.
Definition ast.h:3991
struct pm_node * expression
RescueModifierNode#expression.
Definition ast.h:3985
RescueNode.
Definition ast.h:4001
struct pm_rescue_node * consequent
RescueNode#consequent.
Definition ast.h:4021
struct pm_node * reference
RescueNode#reference.
Definition ast.h:4015
struct pm_node_list exceptions
RescueNode#exceptions.
Definition ast.h:4009
struct pm_statements_node * statements
RescueNode#statements.
Definition ast.h:4018
RestParameterNode.
Definition ast.h:4031
ReturnNode.
Definition ast.h:4064
SingletonClassNode.
Definition ast.h:4094
pm_constant_id_list_t locals
SingletonClassNode#locals.
Definition ast.h:4099
struct pm_node * expression
SingletonClassNode#expression.
Definition ast.h:4108
struct pm_node * body
SingletonClassNode#body.
Definition ast.h:4111
SourceFileNode.
Definition ast.h:4136
pm_string_t filepath
SourceFileNode#filepath.
Definition ast.h:4141
SplatNode.
Definition ast.h:4163
struct pm_node * expression
SplatNode#expression.
Definition ast.h:4171
StatementsNode.
Definition ast.h:4181
struct pm_node_list body
StatementsNode#body.
Definition ast.h:4186
StringNode.
Definition ast.h:4200
pm_string_t unescaped
StringNode#unescaped.
Definition ast.h:4214
A generic string type that can have various ownership semantics.
Definition pm_string.h:30
size_t length
The length of the string in bytes of memory.
Definition pm_string.h:35
SuperNode.
Definition ast.h:4224
struct pm_arguments_node * arguments
SuperNode#arguments.
Definition ast.h:4235
struct pm_node * block
SuperNode#block.
Definition ast.h:4241
SymbolNode.
Definition ast.h:4255
UndefNode.
Definition ast.h:4291
struct pm_node_list names
UndefNode#names.
Definition ast.h:4296
UnlessNode.
Definition ast.h:4309
struct pm_else_node * consequent
UnlessNode#consequent.
Definition ast.h:4326
struct pm_statements_node * statements
UnlessNode#statements.
Definition ast.h:4323
struct pm_node * predicate
UnlessNode#predicate.
Definition ast.h:4317
UntilNode.
Definition ast.h:4341
struct pm_statements_node * statements
UntilNode#statements.
Definition ast.h:4355
struct pm_node * predicate
UntilNode#predicate.
Definition ast.h:4352
WhenNode.
Definition ast.h:4365
WhileNode.
Definition ast.h:4388
struct pm_statements_node * statements
WhileNode#statements.
Definition ast.h:4402
struct pm_node * predicate
WhileNode#predicate.
Definition ast.h:4399
XStringNode.
Definition ast.h:4415
pm_string_t unescaped
XStringNode#unescaped.
Definition ast.h:4429
YieldNode.
Definition ast.h:4439
struct pm_arguments_node * arguments
YieldNode#arguments.
Definition ast.h:4450
struct rb_iseq_constant_body::@151 param
parameter information
Definition st.h:79
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40