yarp 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -1
- data/Makefile +5 -1
- data/README.md +4 -3
- data/config.yml +461 -150
- data/docs/configuration.md +1 -0
- data/docs/encoding.md +5 -5
- data/docs/ruby_api.md +2 -0
- data/docs/serialization.md +3 -3
- data/docs/testing.md +2 -2
- data/ext/yarp/api_node.c +810 -199
- data/ext/yarp/extension.c +94 -31
- data/ext/yarp/extension.h +2 -2
- data/include/yarp/ast.h +653 -150
- data/include/yarp/defines.h +2 -1
- data/include/yarp/diagnostic.h +3 -3
- data/include/yarp/enc/yp_encoding.h +10 -10
- data/include/yarp/node.h +10 -0
- data/include/yarp/parser.h +19 -19
- data/include/yarp/regexp.h +1 -1
- data/include/yarp/unescape.h +7 -5
- data/include/yarp/util/yp_buffer.h +3 -0
- data/include/yarp/util/yp_char.h +16 -16
- data/include/yarp/util/yp_constant_pool.h +2 -2
- data/include/yarp/util/yp_newline_list.h +7 -4
- data/include/yarp/util/yp_string.h +4 -4
- data/include/yarp/util/yp_string_list.h +0 -3
- data/include/yarp/util/yp_strpbrk.h +1 -1
- data/include/yarp/version.h +2 -2
- data/include/yarp.h +14 -3
- data/lib/yarp/desugar_visitor.rb +204 -0
- data/lib/yarp/ffi.rb +27 -1
- data/lib/yarp/lex_compat.rb +93 -25
- data/lib/yarp/mutation_visitor.rb +683 -0
- data/lib/yarp/node.rb +3121 -597
- data/lib/yarp/serialize.rb +198 -126
- data/lib/yarp.rb +53 -7
- data/src/diagnostic.c +1 -1
- data/src/enc/yp_big5.c +15 -42
- data/src/enc/yp_euc_jp.c +16 -43
- data/src/enc/yp_gbk.c +19 -46
- data/src/enc/yp_shift_jis.c +16 -43
- data/src/enc/yp_tables.c +36 -38
- data/src/enc/yp_unicode.c +20 -25
- data/src/enc/yp_windows_31j.c +16 -43
- data/src/node.c +1444 -836
- data/src/prettyprint.c +324 -103
- data/src/regexp.c +21 -21
- data/src/serialize.c +429 -276
- data/src/token_type.c +2 -2
- data/src/unescape.c +184 -136
- data/src/util/yp_buffer.c +7 -2
- data/src/util/yp_char.c +34 -34
- data/src/util/yp_constant_pool.c +4 -4
- data/src/util/yp_memchr.c +1 -1
- data/src/util/yp_newline_list.c +14 -3
- data/src/util/yp_string.c +22 -20
- data/src/util/yp_string_list.c +0 -6
- data/src/util/yp_strncasecmp.c +3 -6
- data/src/util/yp_strpbrk.c +8 -8
- data/src/yarp.c +1504 -615
- data/yarp.gemspec +3 -1
- metadata +4 -2
data/src/yarp.c
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#include "yarp.h"
|
2
|
-
#include "yarp/version.h"
|
3
2
|
|
4
3
|
// The YARP version and the serialization format.
|
5
4
|
const char *
|
@@ -162,14 +161,18 @@ debug_token(yp_token_t * token) {
|
|
162
161
|
|
163
162
|
#endif
|
164
163
|
|
164
|
+
/* Macros for min/max. */
|
165
|
+
#define MIN(a,b) (((a)<(b))?(a):(b))
|
166
|
+
#define MAX(a,b) (((a)>(b))?(a):(b))
|
167
|
+
|
165
168
|
/******************************************************************************/
|
166
169
|
/* Lex mode manipulations */
|
167
170
|
/******************************************************************************/
|
168
171
|
|
169
172
|
// Returns the incrementor character that should be used to increment the
|
170
173
|
// nesting count if one is possible.
|
171
|
-
static inline
|
172
|
-
lex_mode_incrementor(const
|
174
|
+
static inline uint8_t
|
175
|
+
lex_mode_incrementor(const uint8_t start) {
|
173
176
|
switch (start) {
|
174
177
|
case '(':
|
175
178
|
case '[':
|
@@ -183,8 +186,8 @@ lex_mode_incrementor(const char start) {
|
|
183
186
|
|
184
187
|
// Returns the matching character that should be used to terminate a list
|
185
188
|
// beginning with the given character.
|
186
|
-
static inline
|
187
|
-
lex_mode_terminator(const
|
189
|
+
static inline uint8_t
|
190
|
+
lex_mode_terminator(const uint8_t start) {
|
188
191
|
switch (start) {
|
189
192
|
case '(':
|
190
193
|
return ')';
|
@@ -222,9 +225,9 @@ lex_mode_push(yp_parser_t *parser, yp_lex_mode_t lex_mode) {
|
|
222
225
|
|
223
226
|
// Push on a new list lex mode.
|
224
227
|
static inline bool
|
225
|
-
lex_mode_push_list(yp_parser_t *parser, bool interpolation,
|
226
|
-
|
227
|
-
|
228
|
+
lex_mode_push_list(yp_parser_t *parser, bool interpolation, uint8_t delimiter) {
|
229
|
+
uint8_t incrementor = lex_mode_incrementor(delimiter);
|
230
|
+
uint8_t terminator = lex_mode_terminator(delimiter);
|
228
231
|
|
229
232
|
yp_lex_mode_t lex_mode = {
|
230
233
|
.mode = YP_LEX_LIST,
|
@@ -238,7 +241,7 @@ lex_mode_push_list(yp_parser_t *parser, bool interpolation, char delimiter) {
|
|
238
241
|
|
239
242
|
// These are the places where we need to split up the content of the list.
|
240
243
|
// We'll use strpbrk to find the first of these characters.
|
241
|
-
|
244
|
+
uint8_t *breakpoints = lex_mode.as.list.breakpoints;
|
242
245
|
memcpy(breakpoints, "\\ \t\f\r\v\n\0\0\0", sizeof(lex_mode.as.list.breakpoints));
|
243
246
|
|
244
247
|
// Now we'll add the terminator to the list of breakpoints.
|
@@ -261,7 +264,7 @@ lex_mode_push_list(yp_parser_t *parser, bool interpolation, char delimiter) {
|
|
261
264
|
|
262
265
|
// Push on a new regexp lex mode.
|
263
266
|
static inline bool
|
264
|
-
lex_mode_push_regexp(yp_parser_t *parser,
|
267
|
+
lex_mode_push_regexp(yp_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
|
265
268
|
yp_lex_mode_t lex_mode = {
|
266
269
|
.mode = YP_LEX_REGEXP,
|
267
270
|
.as.regexp = {
|
@@ -274,7 +277,7 @@ lex_mode_push_regexp(yp_parser_t *parser, char incrementor, char terminator) {
|
|
274
277
|
// These are the places where we need to split up the content of the
|
275
278
|
// regular expression. We'll use strpbrk to find the first of these
|
276
279
|
// characters.
|
277
|
-
|
280
|
+
uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
|
278
281
|
memcpy(breakpoints, "\n\\#\0\0", sizeof(lex_mode.as.regexp.breakpoints));
|
279
282
|
|
280
283
|
// First we'll add the terminator.
|
@@ -290,7 +293,7 @@ lex_mode_push_regexp(yp_parser_t *parser, char incrementor, char terminator) {
|
|
290
293
|
|
291
294
|
// Push on a new string lex mode.
|
292
295
|
static inline bool
|
293
|
-
lex_mode_push_string(yp_parser_t *parser, bool interpolation, bool label_allowed,
|
296
|
+
lex_mode_push_string(yp_parser_t *parser, bool interpolation, bool label_allowed, uint8_t incrementor, uint8_t terminator) {
|
294
297
|
yp_lex_mode_t lex_mode = {
|
295
298
|
.mode = YP_LEX_STRING,
|
296
299
|
.as.string = {
|
@@ -304,7 +307,7 @@ lex_mode_push_string(yp_parser_t *parser, bool interpolation, bool label_allowed
|
|
304
307
|
|
305
308
|
// These are the places where we need to split up the content of the
|
306
309
|
// string. We'll use strpbrk to find the first of these characters.
|
307
|
-
|
310
|
+
uint8_t *breakpoints = lex_mode.as.string.breakpoints;
|
308
311
|
memcpy(breakpoints, "\n\\\0\0\0", sizeof(lex_mode.as.string.breakpoints));
|
309
312
|
|
310
313
|
// Now add in the terminator.
|
@@ -362,7 +365,7 @@ lex_state_ignored_p(yp_parser_t *parser) {
|
|
362
365
|
|
363
366
|
if (ignored) {
|
364
367
|
return YP_IGNORED_NEWLINE_ALL;
|
365
|
-
} else if (parser->lex_state == (YP_LEX_STATE_ARG | YP_LEX_STATE_LABELED)) {
|
368
|
+
} else if ((parser->lex_state & ~((unsigned int) YP_LEX_STATE_LABEL)) == (YP_LEX_STATE_ARG | YP_LEX_STATE_LABELED)) {
|
366
369
|
return YP_IGNORED_NEWLINE_PATTERN;
|
367
370
|
} else {
|
368
371
|
return YP_IGNORED_NEWLINE_NONE;
|
@@ -381,6 +384,9 @@ lex_state_arg_p(yp_parser_t *parser) {
|
|
381
384
|
|
382
385
|
static inline bool
|
383
386
|
lex_state_spcarg_p(yp_parser_t *parser, bool space_seen) {
|
387
|
+
if (parser->current.end >= parser->end) {
|
388
|
+
return false;
|
389
|
+
}
|
384
390
|
return lex_state_arg_p(parser) && space_seen && !yp_char_is_whitespace(*parser->current.end);
|
385
391
|
}
|
386
392
|
|
@@ -421,7 +427,7 @@ debug_lex_state_set(yp_parser_t *parser, yp_lex_state_t state, char const * call
|
|
421
427
|
|
422
428
|
// Retrieve the constant pool id for the given location.
|
423
429
|
static inline yp_constant_id_t
|
424
|
-
yp_parser_constant_id_location(yp_parser_t *parser, const
|
430
|
+
yp_parser_constant_id_location(yp_parser_t *parser, const uint8_t *start, const uint8_t *end) {
|
425
431
|
return yp_constant_pool_insert(&parser->constant_pool, start, (size_t) (end - start));
|
426
432
|
}
|
427
433
|
|
@@ -536,17 +542,116 @@ yp_arguments_validate(yp_parser_t *parser, yp_arguments_t *arguments) {
|
|
536
542
|
}
|
537
543
|
}
|
538
544
|
|
545
|
+
/******************************************************************************/
|
546
|
+
/* Scope node functions */
|
547
|
+
/******************************************************************************/
|
548
|
+
|
549
|
+
// Generate a scope node from the given node.
|
550
|
+
void
|
551
|
+
yp_scope_node_init(yp_node_t *node, yp_scope_node_t *scope) {
|
552
|
+
scope->base.type = YP_NODE_SCOPE_NODE;
|
553
|
+
scope->base.location.start = node->location.start;
|
554
|
+
scope->base.location.end = node->location.end;
|
555
|
+
|
556
|
+
scope->parameters = NULL;
|
557
|
+
scope->body = NULL;
|
558
|
+
yp_constant_id_list_init(&scope->locals);
|
559
|
+
|
560
|
+
switch (YP_NODE_TYPE(node)) {
|
561
|
+
case YP_NODE_BLOCK_NODE: {
|
562
|
+
yp_block_node_t *cast = (yp_block_node_t *) node;
|
563
|
+
if (cast->parameters) scope->parameters = cast->parameters->parameters;
|
564
|
+
scope->body = cast->body;
|
565
|
+
scope->locals = cast->locals;
|
566
|
+
break;
|
567
|
+
}
|
568
|
+
case YP_NODE_CLASS_NODE: {
|
569
|
+
yp_class_node_t *cast = (yp_class_node_t *) node;
|
570
|
+
scope->body = cast->body;
|
571
|
+
scope->locals = cast->locals;
|
572
|
+
break;
|
573
|
+
}
|
574
|
+
case YP_NODE_DEF_NODE: {
|
575
|
+
yp_def_node_t *cast = (yp_def_node_t *) node;
|
576
|
+
scope->parameters = cast->parameters;
|
577
|
+
scope->body = cast->body;
|
578
|
+
scope->locals = cast->locals;
|
579
|
+
break;
|
580
|
+
}
|
581
|
+
case YP_NODE_LAMBDA_NODE: {
|
582
|
+
yp_lambda_node_t *cast = (yp_lambda_node_t *) node;
|
583
|
+
if (cast->parameters) scope->parameters = cast->parameters->parameters;
|
584
|
+
scope->body = cast->body;
|
585
|
+
scope->locals = cast->locals;
|
586
|
+
break;
|
587
|
+
}
|
588
|
+
case YP_NODE_MODULE_NODE: {
|
589
|
+
yp_module_node_t *cast = (yp_module_node_t *) node;
|
590
|
+
scope->body = cast->body;
|
591
|
+
scope->locals = cast->locals;
|
592
|
+
break;
|
593
|
+
}
|
594
|
+
case YP_NODE_PROGRAM_NODE: {
|
595
|
+
yp_program_node_t *cast = (yp_program_node_t *) node;
|
596
|
+
scope->body = (yp_node_t *) cast->statements;
|
597
|
+
scope->locals = cast->locals;
|
598
|
+
break;
|
599
|
+
}
|
600
|
+
case YP_NODE_SINGLETON_CLASS_NODE: {
|
601
|
+
yp_singleton_class_node_t *cast = (yp_singleton_class_node_t *) node;
|
602
|
+
scope->body = cast->body;
|
603
|
+
scope->locals = cast->locals;
|
604
|
+
break;
|
605
|
+
}
|
606
|
+
default:
|
607
|
+
assert(false && "unreachable");
|
608
|
+
break;
|
609
|
+
}
|
610
|
+
}
|
611
|
+
|
539
612
|
/******************************************************************************/
|
540
613
|
/* Node creation functions */
|
541
614
|
/******************************************************************************/
|
542
615
|
|
616
|
+
// Parse the decimal number represented by the range of bytes. returns
|
617
|
+
// UINT32_MAX if the number fails to parse. This function assumes that the range
|
618
|
+
// of bytes has already been validated to contain only decimal digits.
|
619
|
+
static uint32_t
|
620
|
+
parse_decimal_number(yp_parser_t *parser, const uint8_t *start, const uint8_t *end) {
|
621
|
+
ptrdiff_t diff = end - start;
|
622
|
+
assert(diff > 0 && ((unsigned long) diff < SIZE_MAX));
|
623
|
+
size_t length = (size_t) diff;
|
624
|
+
|
625
|
+
char *digits = calloc(length + 1, sizeof(char));
|
626
|
+
memcpy(digits, start, length);
|
627
|
+
digits[length] = '\0';
|
628
|
+
|
629
|
+
char *endptr;
|
630
|
+
errno = 0;
|
631
|
+
unsigned long value = strtoul(digits, &endptr, 10);
|
632
|
+
|
633
|
+
if ((digits == endptr) || (*endptr != '\0') || (errno == ERANGE)) {
|
634
|
+
yp_diagnostic_list_append(&parser->error_list, start, end, "invalid decimal number");
|
635
|
+
value = UINT32_MAX;
|
636
|
+
}
|
637
|
+
|
638
|
+
free(digits);
|
639
|
+
|
640
|
+
if (value > UINT32_MAX) {
|
641
|
+
yp_diagnostic_list_append(&parser->error_list, start, end, "invalid decimal number");
|
642
|
+
value = UINT32_MAX;
|
643
|
+
}
|
644
|
+
|
645
|
+
return (uint32_t) value;
|
646
|
+
}
|
647
|
+
|
543
648
|
// Parse out the options for a regular expression.
|
544
649
|
static inline yp_node_flags_t
|
545
650
|
yp_regular_expression_flags_create(const yp_token_t *closing) {
|
546
651
|
yp_node_flags_t flags = 0;
|
547
652
|
|
548
653
|
if (closing->type == YP_TOKEN_REGEXP_END) {
|
549
|
-
for (const
|
654
|
+
for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
|
550
655
|
switch (*flag) {
|
551
656
|
case 'i': flags |= YP_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
|
552
657
|
case 'm': flags |= YP_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
|
@@ -588,7 +693,7 @@ yp_alloc_node(YP_ATTRIBUTE_UNUSED yp_parser_t *parser, size_t size) {
|
|
588
693
|
|
589
694
|
// Allocate a new MissingNode node.
|
590
695
|
static yp_missing_node_t *
|
591
|
-
yp_missing_node_create(yp_parser_t *parser, const
|
696
|
+
yp_missing_node_create(yp_parser_t *parser, const uint8_t *start, const uint8_t *end) {
|
592
697
|
yp_missing_node_t *node = YP_ALLOC_NODE(parser, yp_missing_node_t);
|
593
698
|
*node = (yp_missing_node_t) {{ .type = YP_NODE_MISSING_NODE, .location = { .start = start, .end = end } }};
|
594
699
|
return node;
|
@@ -658,27 +763,6 @@ yp_and_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *opera
|
|
658
763
|
return node;
|
659
764
|
}
|
660
765
|
|
661
|
-
// Allocate and initialize a new AndWriteNode.
|
662
|
-
static yp_and_write_node_t *
|
663
|
-
yp_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
664
|
-
yp_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_and_write_node_t);
|
665
|
-
|
666
|
-
*node = (yp_and_write_node_t) {
|
667
|
-
{
|
668
|
-
.type = YP_NODE_AND_WRITE_NODE,
|
669
|
-
.location = {
|
670
|
-
.start = target->location.start,
|
671
|
-
.end = value->location.end
|
672
|
-
},
|
673
|
-
},
|
674
|
-
.target = target,
|
675
|
-
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
676
|
-
.value = value
|
677
|
-
};
|
678
|
-
|
679
|
-
return node;
|
680
|
-
}
|
681
|
-
|
682
766
|
// Allocate an initialize a new arguments node.
|
683
767
|
static yp_arguments_node_t *
|
684
768
|
yp_arguments_node_create(yp_parser_t *parser) {
|
@@ -878,7 +962,7 @@ yp_array_pattern_node_requireds_append(yp_array_pattern_node_t *node, yp_node_t
|
|
878
962
|
static yp_assoc_node_t *
|
879
963
|
yp_assoc_node_create(yp_parser_t *parser, yp_node_t *key, const yp_token_t *operator, yp_node_t *value) {
|
880
964
|
yp_assoc_node_t *node = YP_ALLOC_NODE(parser, yp_assoc_node_t);
|
881
|
-
const
|
965
|
+
const uint8_t *end;
|
882
966
|
|
883
967
|
if (value != NULL) {
|
884
968
|
end = value->location.end;
|
@@ -1062,7 +1146,7 @@ static yp_block_parameters_node_t *
|
|
1062
1146
|
yp_block_parameters_node_create(yp_parser_t *parser, yp_parameters_node_t *parameters, const yp_token_t *opening) {
|
1063
1147
|
yp_block_parameters_node_t *node = YP_ALLOC_NODE(parser, yp_block_parameters_node_t);
|
1064
1148
|
|
1065
|
-
const
|
1149
|
+
const uint8_t *start;
|
1066
1150
|
if (opening->type != YP_TOKEN_NOT_PROVIDED) {
|
1067
1151
|
start = opening->start;
|
1068
1152
|
} else if (parameters != NULL) {
|
@@ -1071,7 +1155,7 @@ yp_block_parameters_node_create(yp_parser_t *parser, yp_parameters_node_t *param
|
|
1071
1155
|
start = NULL;
|
1072
1156
|
}
|
1073
1157
|
|
1074
|
-
const
|
1158
|
+
const uint8_t *end;
|
1075
1159
|
if (parameters != NULL) {
|
1076
1160
|
end = parameters->base.location.end;
|
1077
1161
|
} else if (opening->type != YP_TOKEN_NOT_PROVIDED) {
|
@@ -1151,7 +1235,7 @@ yp_call_node_create(yp_parser_t *parser) {
|
|
1151
1235
|
},
|
1152
1236
|
.receiver = NULL,
|
1153
1237
|
.operator_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1154
|
-
.message_loc =
|
1238
|
+
.message_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1155
1239
|
.opening_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
1156
1240
|
.arguments = NULL,
|
1157
1241
|
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
@@ -1192,8 +1276,8 @@ static yp_call_node_t *
|
|
1192
1276
|
yp_call_node_binary_create(yp_parser_t *parser, yp_node_t *receiver, yp_token_t *operator, yp_node_t *argument) {
|
1193
1277
|
yp_call_node_t *node = yp_call_node_create(parser);
|
1194
1278
|
|
1195
|
-
node->base.location.start = receiver->location.start;
|
1196
|
-
node->base.location.end = argument->location.end;
|
1279
|
+
node->base.location.start = MIN(receiver->location.start, argument->location.start);
|
1280
|
+
node->base.location.end = MAX(receiver->location.end, argument->location.end);
|
1197
1281
|
|
1198
1282
|
node->receiver = receiver;
|
1199
1283
|
node->message_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
|
@@ -1389,7 +1473,7 @@ yp_call_operator_write_node_create(yp_parser_t *parser, yp_call_node_t *target,
|
|
1389
1473
|
.target = target,
|
1390
1474
|
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1391
1475
|
.value = value,
|
1392
|
-
.
|
1476
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
1393
1477
|
};
|
1394
1478
|
|
1395
1479
|
return node;
|
@@ -1486,7 +1570,7 @@ yp_case_node_end_keyword_loc_set(yp_case_node_t *node, const yp_token_t *end_key
|
|
1486
1570
|
|
1487
1571
|
// Allocate a new ClassNode node.
|
1488
1572
|
static yp_class_node_t *
|
1489
|
-
yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, yp_node_t *constant_path, const yp_token_t *inheritance_operator, yp_node_t *superclass, yp_node_t *body, const yp_token_t *end_keyword) {
|
1573
|
+
yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *class_keyword, yp_node_t *constant_path, const yp_token_t *name, const yp_token_t *inheritance_operator, yp_node_t *superclass, yp_node_t *body, const yp_token_t *end_keyword) {
|
1490
1574
|
yp_class_node_t *node = YP_ALLOC_NODE(parser, yp_class_node_t);
|
1491
1575
|
|
1492
1576
|
*node = (yp_class_node_t) {
|
@@ -1500,7 +1584,78 @@ yp_class_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const y
|
|
1500
1584
|
.inheritance_operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
|
1501
1585
|
.superclass = superclass,
|
1502
1586
|
.body = body,
|
1503
|
-
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
|
1587
|
+
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword),
|
1588
|
+
.name = YP_EMPTY_STRING
|
1589
|
+
};
|
1590
|
+
|
1591
|
+
yp_string_shared_init(&node->name, name->start, name->end);
|
1592
|
+
return node;
|
1593
|
+
}
|
1594
|
+
|
1595
|
+
// Allocate and initialize a new ClassVariableAndWriteNode node.
|
1596
|
+
static yp_class_variable_and_write_node_t *
|
1597
|
+
yp_class_variable_and_write_node_create(yp_parser_t *parser, yp_class_variable_read_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1598
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1599
|
+
yp_class_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_and_write_node_t);
|
1600
|
+
|
1601
|
+
*node = (yp_class_variable_and_write_node_t) {
|
1602
|
+
{
|
1603
|
+
.type = YP_NODE_CLASS_VARIABLE_AND_WRITE_NODE,
|
1604
|
+
.location = {
|
1605
|
+
.start = target->base.location.start,
|
1606
|
+
.end = value->location.end
|
1607
|
+
}
|
1608
|
+
},
|
1609
|
+
.name = target->name,
|
1610
|
+
.name_loc = target->base.location,
|
1611
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1612
|
+
.value = value
|
1613
|
+
};
|
1614
|
+
|
1615
|
+
return node;
|
1616
|
+
}
|
1617
|
+
|
1618
|
+
// Allocate and initialize a new ClassVariableOperatorWriteNode node.
|
1619
|
+
static yp_class_variable_operator_write_node_t *
|
1620
|
+
yp_class_variable_operator_write_node_create(yp_parser_t *parser, yp_class_variable_read_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1621
|
+
yp_class_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_operator_write_node_t);
|
1622
|
+
|
1623
|
+
*node = (yp_class_variable_operator_write_node_t) {
|
1624
|
+
{
|
1625
|
+
.type = YP_NODE_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
|
1626
|
+
.location = {
|
1627
|
+
.start = target->base.location.start,
|
1628
|
+
.end = value->location.end
|
1629
|
+
}
|
1630
|
+
},
|
1631
|
+
.name = target->name,
|
1632
|
+
.name_loc = target->base.location,
|
1633
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1634
|
+
.value = value,
|
1635
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
1636
|
+
};
|
1637
|
+
|
1638
|
+
return node;
|
1639
|
+
}
|
1640
|
+
|
1641
|
+
// Allocate and initialize a new ClassVariableOrWriteNode node.
|
1642
|
+
static yp_class_variable_or_write_node_t *
|
1643
|
+
yp_class_variable_or_write_node_create(yp_parser_t *parser, yp_class_variable_read_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1644
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1645
|
+
yp_class_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_or_write_node_t);
|
1646
|
+
|
1647
|
+
*node = (yp_class_variable_or_write_node_t) {
|
1648
|
+
{
|
1649
|
+
.type = YP_NODE_CLASS_VARIABLE_OR_WRITE_NODE,
|
1650
|
+
.location = {
|
1651
|
+
.start = target->base.location.start,
|
1652
|
+
.end = value->location.end
|
1653
|
+
}
|
1654
|
+
},
|
1655
|
+
.name = target->name,
|
1656
|
+
.name_loc = target->base.location,
|
1657
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1658
|
+
.value = value
|
1504
1659
|
};
|
1505
1660
|
|
1506
1661
|
return node;
|
@@ -1511,13 +1666,21 @@ static yp_class_variable_read_node_t *
|
|
1511
1666
|
yp_class_variable_read_node_create(yp_parser_t *parser, const yp_token_t *token) {
|
1512
1667
|
assert(token->type == YP_TOKEN_CLASS_VARIABLE);
|
1513
1668
|
yp_class_variable_read_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_read_node_t);
|
1514
|
-
|
1669
|
+
|
1670
|
+
*node = (yp_class_variable_read_node_t) {
|
1671
|
+
{
|
1672
|
+
.type = YP_NODE_CLASS_VARIABLE_READ_NODE,
|
1673
|
+
.location = YP_LOCATION_TOKEN_VALUE(token)
|
1674
|
+
},
|
1675
|
+
.name = yp_parser_constant_id_location(parser, token->start, token->end)
|
1676
|
+
};
|
1677
|
+
|
1515
1678
|
return node;
|
1516
1679
|
}
|
1517
1680
|
|
1518
1681
|
// Initialize a new ClassVariableWriteNode node from a ClassVariableRead node.
|
1519
1682
|
static yp_class_variable_write_node_t *
|
1520
|
-
|
1683
|
+
yp_class_variable_write_node_create(yp_parser_t *parser, yp_class_variable_read_node_t *read_node, yp_token_t *operator, yp_node_t *value) {
|
1521
1684
|
yp_class_variable_write_node_t *node = YP_ALLOC_NODE(parser, yp_class_variable_write_node_t);
|
1522
1685
|
|
1523
1686
|
*node = (yp_class_variable_write_node_t) {
|
@@ -1525,10 +1688,11 @@ yp_class_variable_read_node_to_class_variable_write_node(yp_parser_t *parser, yp
|
|
1525
1688
|
.type = YP_NODE_CLASS_VARIABLE_WRITE_NODE,
|
1526
1689
|
.location = {
|
1527
1690
|
.start = read_node->base.location.start,
|
1528
|
-
.end = value
|
1691
|
+
.end = value->location.end
|
1529
1692
|
},
|
1530
1693
|
},
|
1531
|
-
.
|
1694
|
+
.name = read_node->name,
|
1695
|
+
.name_loc = YP_LOCATION_NODE_VALUE((yp_node_t *) read_node),
|
1532
1696
|
.operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
|
1533
1697
|
.value = value
|
1534
1698
|
};
|
@@ -1536,6 +1700,72 @@ yp_class_variable_read_node_to_class_variable_write_node(yp_parser_t *parser, yp
|
|
1536
1700
|
return node;
|
1537
1701
|
}
|
1538
1702
|
|
1703
|
+
// Allocate and initialize a new ConstantPathAndWriteNode node.
|
1704
|
+
static yp_constant_path_and_write_node_t *
|
1705
|
+
yp_constant_path_and_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1706
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1707
|
+
yp_constant_path_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_and_write_node_t);
|
1708
|
+
|
1709
|
+
*node = (yp_constant_path_and_write_node_t) {
|
1710
|
+
{
|
1711
|
+
.type = YP_NODE_CONSTANT_PATH_AND_WRITE_NODE,
|
1712
|
+
.location = {
|
1713
|
+
.start = target->base.location.start,
|
1714
|
+
.end = value->location.end
|
1715
|
+
}
|
1716
|
+
},
|
1717
|
+
.target = target,
|
1718
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1719
|
+
.value = value
|
1720
|
+
};
|
1721
|
+
|
1722
|
+
return node;
|
1723
|
+
}
|
1724
|
+
|
1725
|
+
// Allocate and initialize a new ConstantPathOperatorWriteNode node.
|
1726
|
+
static yp_constant_path_operator_write_node_t *
|
1727
|
+
yp_constant_path_operator_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1728
|
+
yp_constant_path_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_operator_write_node_t);
|
1729
|
+
|
1730
|
+
*node = (yp_constant_path_operator_write_node_t) {
|
1731
|
+
{
|
1732
|
+
.type = YP_NODE_CONSTANT_PATH_OPERATOR_WRITE_NODE,
|
1733
|
+
.location = {
|
1734
|
+
.start = target->base.location.start,
|
1735
|
+
.end = value->location.end
|
1736
|
+
}
|
1737
|
+
},
|
1738
|
+
.target = target,
|
1739
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1740
|
+
.value = value,
|
1741
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
1742
|
+
};
|
1743
|
+
|
1744
|
+
return node;
|
1745
|
+
}
|
1746
|
+
|
1747
|
+
// Allocate and initialize a new ConstantPathOrWriteNode node.
|
1748
|
+
static yp_constant_path_or_write_node_t *
|
1749
|
+
yp_constant_path_or_write_node_create(yp_parser_t *parser, yp_constant_path_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1750
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1751
|
+
yp_constant_path_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_path_or_write_node_t);
|
1752
|
+
|
1753
|
+
*node = (yp_constant_path_or_write_node_t) {
|
1754
|
+
{
|
1755
|
+
.type = YP_NODE_CONSTANT_PATH_OR_WRITE_NODE,
|
1756
|
+
.location = {
|
1757
|
+
.start = target->base.location.start,
|
1758
|
+
.end = value->location.end
|
1759
|
+
}
|
1760
|
+
},
|
1761
|
+
.target = target,
|
1762
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1763
|
+
.value = value
|
1764
|
+
};
|
1765
|
+
|
1766
|
+
return node;
|
1767
|
+
}
|
1768
|
+
|
1539
1769
|
// Allocate and initialize a new ConstantPathNode node.
|
1540
1770
|
static yp_constant_path_node_t *
|
1541
1771
|
yp_constant_path_node_create(yp_parser_t *parser, yp_node_t *parent, const yp_token_t *delimiter, yp_node_t *child) {
|
@@ -1567,7 +1797,7 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t
|
|
1567
1797
|
.type = YP_NODE_CONSTANT_PATH_WRITE_NODE,
|
1568
1798
|
.location = {
|
1569
1799
|
.start = target->base.location.start,
|
1570
|
-
.end =
|
1800
|
+
.end = value->location.end
|
1571
1801
|
},
|
1572
1802
|
},
|
1573
1803
|
.target = target,
|
@@ -1578,6 +1808,74 @@ yp_constant_path_write_node_create(yp_parser_t *parser, yp_constant_path_node_t
|
|
1578
1808
|
return node;
|
1579
1809
|
}
|
1580
1810
|
|
1811
|
+
// Allocate and initialize a new ConstantAndWriteNode node.
|
1812
|
+
static yp_constant_and_write_node_t *
|
1813
|
+
yp_constant_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1814
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE));
|
1815
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
1816
|
+
yp_constant_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_and_write_node_t);
|
1817
|
+
|
1818
|
+
*node = (yp_constant_and_write_node_t) {
|
1819
|
+
{
|
1820
|
+
.type = YP_NODE_CONSTANT_AND_WRITE_NODE,
|
1821
|
+
.location = {
|
1822
|
+
.start = target->location.start,
|
1823
|
+
.end = value->location.end
|
1824
|
+
}
|
1825
|
+
},
|
1826
|
+
.name_loc = target->location,
|
1827
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1828
|
+
.value = value
|
1829
|
+
};
|
1830
|
+
|
1831
|
+
return node;
|
1832
|
+
}
|
1833
|
+
|
1834
|
+
// Allocate and initialize a new ConstantOperatorWriteNode node.
|
1835
|
+
static yp_constant_operator_write_node_t *
|
1836
|
+
yp_constant_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1837
|
+
yp_constant_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_operator_write_node_t);
|
1838
|
+
|
1839
|
+
*node = (yp_constant_operator_write_node_t) {
|
1840
|
+
{
|
1841
|
+
.type = YP_NODE_CONSTANT_OPERATOR_WRITE_NODE,
|
1842
|
+
.location = {
|
1843
|
+
.start = target->location.start,
|
1844
|
+
.end = value->location.end
|
1845
|
+
}
|
1846
|
+
},
|
1847
|
+
.name_loc = target->location,
|
1848
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1849
|
+
.value = value,
|
1850
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
1851
|
+
};
|
1852
|
+
|
1853
|
+
return node;
|
1854
|
+
}
|
1855
|
+
|
1856
|
+
// Allocate and initialize a new ConstantOrWriteNode node.
|
1857
|
+
static yp_constant_or_write_node_t *
|
1858
|
+
yp_constant_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
1859
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_CONSTANT_READ_NODE));
|
1860
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
1861
|
+
yp_constant_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_constant_or_write_node_t);
|
1862
|
+
|
1863
|
+
*node = (yp_constant_or_write_node_t) {
|
1864
|
+
{
|
1865
|
+
.type = YP_NODE_CONSTANT_OR_WRITE_NODE,
|
1866
|
+
.location = {
|
1867
|
+
.start = target->location.start,
|
1868
|
+
.end = value->location.end
|
1869
|
+
}
|
1870
|
+
},
|
1871
|
+
.name_loc = target->location,
|
1872
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
1873
|
+
.value = value
|
1874
|
+
};
|
1875
|
+
|
1876
|
+
return node;
|
1877
|
+
}
|
1878
|
+
|
1581
1879
|
// Allocate and initialize a new ConstantReadNode node.
|
1582
1880
|
static yp_constant_read_node_t *
|
1583
1881
|
yp_constant_read_node_create(yp_parser_t *parser, const yp_token_t *name) {
|
@@ -1598,7 +1896,7 @@ yp_constant_write_node_create(yp_parser_t *parser, yp_location_t *name_loc, cons
|
|
1598
1896
|
.type = YP_NODE_CONSTANT_WRITE_NODE,
|
1599
1897
|
.location = {
|
1600
1898
|
.start = name_loc->start,
|
1601
|
-
.end = value
|
1899
|
+
.end = value->location.end
|
1602
1900
|
},
|
1603
1901
|
},
|
1604
1902
|
.name_loc = *name_loc,
|
@@ -1626,7 +1924,7 @@ yp_def_node_create(
|
|
1626
1924
|
const yp_token_t *end_keyword
|
1627
1925
|
) {
|
1628
1926
|
yp_def_node_t *node = YP_ALLOC_NODE(parser, yp_def_node_t);
|
1629
|
-
const
|
1927
|
+
const uint8_t *end;
|
1630
1928
|
|
1631
1929
|
if (end_keyword->type == YP_TOKEN_NOT_PROVIDED) {
|
1632
1930
|
end = body->location.end;
|
@@ -1681,7 +1979,7 @@ yp_defined_node_create(yp_parser_t *parser, const yp_token_t *lparen, yp_node_t
|
|
1681
1979
|
static yp_else_node_t *
|
1682
1980
|
yp_else_node_create(yp_parser_t *parser, const yp_token_t *else_keyword, yp_statements_node_t *statements, const yp_token_t *end_keyword) {
|
1683
1981
|
yp_else_node_t *node = YP_ALLOC_NODE(parser, yp_else_node_t);
|
1684
|
-
const
|
1982
|
+
const uint8_t *end = NULL;
|
1685
1983
|
if ((end_keyword->type == YP_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
|
1686
1984
|
end = statements->base.location.end;
|
1687
1985
|
} else {
|
@@ -2012,6 +2310,74 @@ yp_hash_pattern_node_node_list_create(yp_parser_t *parser, yp_node_list_t *assoc
|
|
2012
2310
|
return node;
|
2013
2311
|
}
|
2014
2312
|
|
2313
|
+
// Allocate and initialize a new GlobalVariableAndWriteNode node.
|
2314
|
+
static yp_global_variable_and_write_node_t *
|
2315
|
+
yp_global_variable_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2316
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_GLOBAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_NUMBERED_REFERENCE_READ_NODE));
|
2317
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
2318
|
+
yp_global_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_and_write_node_t);
|
2319
|
+
|
2320
|
+
*node = (yp_global_variable_and_write_node_t) {
|
2321
|
+
{
|
2322
|
+
.type = YP_NODE_GLOBAL_VARIABLE_AND_WRITE_NODE,
|
2323
|
+
.location = {
|
2324
|
+
.start = target->location.start,
|
2325
|
+
.end = value->location.end
|
2326
|
+
}
|
2327
|
+
},
|
2328
|
+
.name_loc = target->location,
|
2329
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2330
|
+
.value = value
|
2331
|
+
};
|
2332
|
+
|
2333
|
+
return node;
|
2334
|
+
}
|
2335
|
+
|
2336
|
+
// Allocate and initialize a new GlobalVariableOperatorWriteNode node.
|
2337
|
+
static yp_global_variable_operator_write_node_t *
|
2338
|
+
yp_global_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2339
|
+
yp_global_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_operator_write_node_t);
|
2340
|
+
|
2341
|
+
*node = (yp_global_variable_operator_write_node_t) {
|
2342
|
+
{
|
2343
|
+
.type = YP_NODE_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
|
2344
|
+
.location = {
|
2345
|
+
.start = target->location.start,
|
2346
|
+
.end = value->location.end
|
2347
|
+
}
|
2348
|
+
},
|
2349
|
+
.name_loc = target->location,
|
2350
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2351
|
+
.value = value,
|
2352
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
2353
|
+
};
|
2354
|
+
|
2355
|
+
return node;
|
2356
|
+
}
|
2357
|
+
|
2358
|
+
// Allocate and initialize a new GlobalVariableOrWriteNode node.
|
2359
|
+
static yp_global_variable_or_write_node_t *
|
2360
|
+
yp_global_variable_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2361
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_GLOBAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_BACK_REFERENCE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_NUMBERED_REFERENCE_READ_NODE));
|
2362
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
2363
|
+
yp_global_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_global_variable_or_write_node_t);
|
2364
|
+
|
2365
|
+
*node = (yp_global_variable_or_write_node_t) {
|
2366
|
+
{
|
2367
|
+
.type = YP_NODE_GLOBAL_VARIABLE_OR_WRITE_NODE,
|
2368
|
+
.location = {
|
2369
|
+
.start = target->location.start,
|
2370
|
+
.end = value->location.end
|
2371
|
+
}
|
2372
|
+
},
|
2373
|
+
.name_loc = target->location,
|
2374
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2375
|
+
.value = value
|
2376
|
+
};
|
2377
|
+
|
2378
|
+
return node;
|
2379
|
+
}
|
2380
|
+
|
2015
2381
|
// Allocate a new GlobalVariableReadNode node.
|
2016
2382
|
static yp_global_variable_read_node_t *
|
2017
2383
|
yp_global_variable_read_node_create(yp_parser_t *parser, const yp_token_t *name) {
|
@@ -2037,7 +2403,7 @@ yp_global_variable_write_node_create(yp_parser_t *parser, const yp_location_t *n
|
|
2037
2403
|
.type = YP_NODE_GLOBAL_VARIABLE_WRITE_NODE,
|
2038
2404
|
.location = {
|
2039
2405
|
.start = name_loc->start,
|
2040
|
-
.end =
|
2406
|
+
.end = value->location.end
|
2041
2407
|
},
|
2042
2408
|
},
|
2043
2409
|
.name_loc = *name_loc,
|
@@ -2093,7 +2459,7 @@ yp_if_node_create(yp_parser_t *parser,
|
|
2093
2459
|
yp_flip_flop(predicate);
|
2094
2460
|
yp_if_node_t *node = YP_ALLOC_NODE(parser, yp_if_node_t);
|
2095
2461
|
|
2096
|
-
const
|
2462
|
+
const uint8_t *end;
|
2097
2463
|
if (end_keyword->type != YP_TOKEN_NOT_PROVIDED) {
|
2098
2464
|
end = end_keyword->end;
|
2099
2465
|
} else if (consequent != NULL) {
|
@@ -2276,7 +2642,7 @@ static yp_in_node_t *
|
|
2276
2642
|
yp_in_node_create(yp_parser_t *parser, yp_node_t *pattern, yp_statements_node_t *statements, const yp_token_t *in_keyword, const yp_token_t *then_keyword) {
|
2277
2643
|
yp_in_node_t *node = YP_ALLOC_NODE(parser, yp_in_node_t);
|
2278
2644
|
|
2279
|
-
const
|
2645
|
+
const uint8_t *end;
|
2280
2646
|
if (statements != NULL) {
|
2281
2647
|
end = statements->base.location.end;
|
2282
2648
|
} else if (then_keyword->type != YP_TOKEN_NOT_PROVIDED) {
|
@@ -2302,15 +2668,88 @@ yp_in_node_create(yp_parser_t *parser, yp_node_t *pattern, yp_statements_node_t
|
|
2302
2668
|
return node;
|
2303
2669
|
}
|
2304
2670
|
|
2671
|
+
// Allocate and initialize a new InstanceVariableAndWriteNode node.
|
2672
|
+
static yp_instance_variable_and_write_node_t *
|
2673
|
+
yp_instance_variable_and_write_node_create(yp_parser_t *parser, yp_instance_variable_read_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2674
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
2675
|
+
yp_instance_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_and_write_node_t);
|
2676
|
+
|
2677
|
+
*node = (yp_instance_variable_and_write_node_t) {
|
2678
|
+
{
|
2679
|
+
.type = YP_NODE_INSTANCE_VARIABLE_AND_WRITE_NODE,
|
2680
|
+
.location = {
|
2681
|
+
.start = target->base.location.start,
|
2682
|
+
.end = value->location.end
|
2683
|
+
}
|
2684
|
+
},
|
2685
|
+
.name = target->name,
|
2686
|
+
.name_loc = target->base.location,
|
2687
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2688
|
+
.value = value
|
2689
|
+
};
|
2690
|
+
|
2691
|
+
return node;
|
2692
|
+
}
|
2693
|
+
|
2694
|
+
// Allocate and initialize a new InstanceVariableOperatorWriteNode node.
|
2695
|
+
static yp_instance_variable_operator_write_node_t *
|
2696
|
+
yp_instance_variable_operator_write_node_create(yp_parser_t *parser, yp_instance_variable_read_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2697
|
+
yp_instance_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_operator_write_node_t);
|
2698
|
+
|
2699
|
+
*node = (yp_instance_variable_operator_write_node_t) {
|
2700
|
+
{
|
2701
|
+
.type = YP_NODE_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
|
2702
|
+
.location = {
|
2703
|
+
.start = target->base.location.start,
|
2704
|
+
.end = value->location.end
|
2705
|
+
}
|
2706
|
+
},
|
2707
|
+
.name = target->name,
|
2708
|
+
.name_loc = target->base.location,
|
2709
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2710
|
+
.value = value,
|
2711
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1)
|
2712
|
+
};
|
2713
|
+
|
2714
|
+
return node;
|
2715
|
+
}
|
2716
|
+
|
2717
|
+
// Allocate and initialize a new InstanceVariableOrWriteNode node.
|
2718
|
+
static yp_instance_variable_or_write_node_t *
|
2719
|
+
yp_instance_variable_or_write_node_create(yp_parser_t *parser, yp_instance_variable_read_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2720
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
2721
|
+
yp_instance_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_or_write_node_t);
|
2722
|
+
|
2723
|
+
*node = (yp_instance_variable_or_write_node_t) {
|
2724
|
+
{
|
2725
|
+
.type = YP_NODE_INSTANCE_VARIABLE_OR_WRITE_NODE,
|
2726
|
+
.location = {
|
2727
|
+
.start = target->base.location.start,
|
2728
|
+
.end = value->location.end
|
2729
|
+
}
|
2730
|
+
},
|
2731
|
+
.name = target->name,
|
2732
|
+
.name_loc = target->base.location,
|
2733
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2734
|
+
.value = value
|
2735
|
+
};
|
2736
|
+
|
2737
|
+
return node;
|
2738
|
+
}
|
2739
|
+
|
2305
2740
|
// Allocate and initialize a new InstanceVariableReadNode node.
|
2306
2741
|
static yp_instance_variable_read_node_t *
|
2307
2742
|
yp_instance_variable_read_node_create(yp_parser_t *parser, const yp_token_t *token) {
|
2308
2743
|
assert(token->type == YP_TOKEN_INSTANCE_VARIABLE);
|
2309
2744
|
yp_instance_variable_read_node_t *node = YP_ALLOC_NODE(parser, yp_instance_variable_read_node_t);
|
2310
2745
|
|
2311
|
-
*node = (yp_instance_variable_read_node_t) {
|
2312
|
-
|
2313
|
-
|
2746
|
+
*node = (yp_instance_variable_read_node_t) {
|
2747
|
+
{
|
2748
|
+
.type = YP_NODE_INSTANCE_VARIABLE_READ_NODE,
|
2749
|
+
.location = YP_LOCATION_TOKEN_VALUE(token)
|
2750
|
+
},
|
2751
|
+
.name = yp_parser_constant_id_location(parser, token->start, token->end)
|
2752
|
+
};
|
2314
2753
|
|
2315
2754
|
return node;
|
2316
2755
|
}
|
@@ -2324,9 +2763,10 @@ yp_instance_variable_write_node_create(yp_parser_t *parser, yp_instance_variable
|
|
2324
2763
|
.type = YP_NODE_INSTANCE_VARIABLE_WRITE_NODE,
|
2325
2764
|
.location = {
|
2326
2765
|
.start = read_node->base.location.start,
|
2327
|
-
.end = value
|
2766
|
+
.end = value->location.end
|
2328
2767
|
}
|
2329
2768
|
},
|
2769
|
+
.name = read_node->name,
|
2330
2770
|
.name_loc = YP_LOCATION_NODE_BASE_VALUE(read_node),
|
2331
2771
|
.operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
|
2332
2772
|
.value = value
|
@@ -2358,8 +2798,13 @@ yp_interpolated_regular_expression_node_create(yp_parser_t *parser, const yp_tok
|
|
2358
2798
|
|
2359
2799
|
static inline void
|
2360
2800
|
yp_interpolated_regular_expression_node_append(yp_interpolated_regular_expression_node_t *node, yp_node_t *part) {
|
2801
|
+
if (node->base.location.start > part->location.start) {
|
2802
|
+
node->base.location.start = part->location.start;
|
2803
|
+
}
|
2804
|
+
if (node->base.location.end < part->location.end) {
|
2805
|
+
node->base.location.end = part->location.end;
|
2806
|
+
}
|
2361
2807
|
yp_node_list_append(&node->parts, part);
|
2362
|
-
node->base.location.end = part->location.end;
|
2363
2808
|
}
|
2364
2809
|
|
2365
2810
|
static inline void
|
@@ -2431,17 +2876,12 @@ yp_interpolated_symbol_node_create(yp_parser_t *parser, const yp_token_t *openin
|
|
2431
2876
|
|
2432
2877
|
static inline void
|
2433
2878
|
yp_interpolated_symbol_node_append(yp_interpolated_symbol_node_t *node, yp_node_t *part) {
|
2434
|
-
|
2435
|
-
if (!node->base.location.start) {
|
2879
|
+
if (node->parts.size == 0 && node->opening_loc.start == NULL) {
|
2436
2880
|
node->base.location.start = part->location.start;
|
2437
2881
|
}
|
2438
|
-
node->base.location.end = part->location.end;
|
2439
|
-
}
|
2440
2882
|
|
2441
|
-
|
2442
|
-
|
2443
|
-
node->closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
|
2444
|
-
node->base.location.end = closing->end;
|
2883
|
+
yp_node_list_append(&node->parts, part);
|
2884
|
+
node->base.location.end = part->location.end;
|
2445
2885
|
}
|
2446
2886
|
|
2447
2887
|
// Allocate a new InterpolatedXStringNode node.
|
@@ -2551,10 +2991,11 @@ static yp_lambda_node_t *
|
|
2551
2991
|
yp_lambda_node_create(
|
2552
2992
|
yp_parser_t *parser,
|
2553
2993
|
yp_constant_id_list_t *locals,
|
2994
|
+
const yp_token_t *operator,
|
2554
2995
|
const yp_token_t *opening,
|
2996
|
+
const yp_token_t *closing,
|
2555
2997
|
yp_block_parameters_node_t *parameters,
|
2556
|
-
yp_node_t *body
|
2557
|
-
const yp_token_t *closing
|
2998
|
+
yp_node_t *body
|
2558
2999
|
) {
|
2559
3000
|
yp_lambda_node_t *node = YP_ALLOC_NODE(parser, yp_lambda_node_t);
|
2560
3001
|
|
@@ -2562,12 +3003,14 @@ yp_lambda_node_create(
|
|
2562
3003
|
{
|
2563
3004
|
.type = YP_NODE_LAMBDA_NODE,
|
2564
3005
|
.location = {
|
2565
|
-
.start =
|
3006
|
+
.start = operator->start,
|
2566
3007
|
.end = closing->end
|
2567
3008
|
},
|
2568
3009
|
},
|
2569
3010
|
.locals = *locals,
|
3011
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2570
3012
|
.opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
3013
|
+
.closing_loc = YP_LOCATION_TOKEN_VALUE(closing),
|
2571
3014
|
.parameters = parameters,
|
2572
3015
|
.body = body
|
2573
3016
|
};
|
@@ -2575,6 +3018,80 @@ yp_lambda_node_create(
|
|
2575
3018
|
return node;
|
2576
3019
|
}
|
2577
3020
|
|
3021
|
+
// Allocate and initialize a new LocalVariableAndWriteNode node.
|
3022
|
+
static yp_local_variable_and_write_node_t *
|
3023
|
+
yp_local_variable_and_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t name, uint32_t depth) {
|
3024
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE));
|
3025
|
+
assert(operator->type == YP_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
|
3026
|
+
yp_local_variable_and_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_and_write_node_t);
|
3027
|
+
|
3028
|
+
*node = (yp_local_variable_and_write_node_t) {
|
3029
|
+
{
|
3030
|
+
.type = YP_NODE_LOCAL_VARIABLE_AND_WRITE_NODE,
|
3031
|
+
.location = {
|
3032
|
+
.start = target->location.start,
|
3033
|
+
.end = value->location.end
|
3034
|
+
}
|
3035
|
+
},
|
3036
|
+
.name_loc = target->location,
|
3037
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
3038
|
+
.value = value,
|
3039
|
+
.name = name,
|
3040
|
+
.depth = depth
|
3041
|
+
};
|
3042
|
+
|
3043
|
+
return node;
|
3044
|
+
}
|
3045
|
+
|
3046
|
+
// Allocate and initialize a new LocalVariableOperatorWriteNode node.
|
3047
|
+
static yp_local_variable_operator_write_node_t *
|
3048
|
+
yp_local_variable_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t name, uint32_t depth) {
|
3049
|
+
yp_local_variable_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_operator_write_node_t);
|
3050
|
+
|
3051
|
+
*node = (yp_local_variable_operator_write_node_t) {
|
3052
|
+
{
|
3053
|
+
.type = YP_NODE_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
|
3054
|
+
.location = {
|
3055
|
+
.start = target->location.start,
|
3056
|
+
.end = value->location.end
|
3057
|
+
}
|
3058
|
+
},
|
3059
|
+
.name_loc = target->location,
|
3060
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
3061
|
+
.value = value,
|
3062
|
+
.name = name,
|
3063
|
+
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1),
|
3064
|
+
.depth = depth
|
3065
|
+
};
|
3066
|
+
|
3067
|
+
return node;
|
3068
|
+
}
|
3069
|
+
|
3070
|
+
// Allocate and initialize a new LocalVariableOrWriteNode node.
|
3071
|
+
static yp_local_variable_or_write_node_t *
|
3072
|
+
yp_local_variable_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value, yp_constant_id_t name, uint32_t depth) {
|
3073
|
+
assert(YP_NODE_TYPE_P(target, YP_NODE_LOCAL_VARIABLE_READ_NODE) || YP_NODE_TYPE_P(target, YP_NODE_CALL_NODE));
|
3074
|
+
assert(operator->type == YP_TOKEN_PIPE_PIPE_EQUAL);
|
3075
|
+
yp_local_variable_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_or_write_node_t);
|
3076
|
+
|
3077
|
+
*node = (yp_local_variable_or_write_node_t) {
|
3078
|
+
{
|
3079
|
+
.type = YP_NODE_LOCAL_VARIABLE_OR_WRITE_NODE,
|
3080
|
+
.location = {
|
3081
|
+
.start = target->location.start,
|
3082
|
+
.end = value->location.end
|
3083
|
+
}
|
3084
|
+
},
|
3085
|
+
.name_loc = target->location,
|
3086
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
3087
|
+
.value = value,
|
3088
|
+
.name = name,
|
3089
|
+
.depth = depth
|
3090
|
+
};
|
3091
|
+
|
3092
|
+
return node;
|
3093
|
+
}
|
3094
|
+
|
2578
3095
|
// Allocate a new LocalVariableReadNode node.
|
2579
3096
|
static yp_local_variable_read_node_t *
|
2580
3097
|
yp_local_variable_read_node_create(yp_parser_t *parser, const yp_token_t *name, uint32_t depth) {
|
@@ -2585,7 +3102,7 @@ yp_local_variable_read_node_create(yp_parser_t *parser, const yp_token_t *name,
|
|
2585
3102
|
.type = YP_NODE_LOCAL_VARIABLE_READ_NODE,
|
2586
3103
|
.location = YP_LOCATION_TOKEN_VALUE(name)
|
2587
3104
|
},
|
2588
|
-
.
|
3105
|
+
.name = yp_parser_constant_id_token(parser, name),
|
2589
3106
|
.depth = depth
|
2590
3107
|
};
|
2591
3108
|
|
@@ -2594,7 +3111,7 @@ yp_local_variable_read_node_create(yp_parser_t *parser, const yp_token_t *name,
|
|
2594
3111
|
|
2595
3112
|
// Allocate and initialize a new LocalVariableWriteNode node.
|
2596
3113
|
static yp_local_variable_write_node_t *
|
2597
|
-
yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t
|
3114
|
+
yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t name, uint32_t depth, yp_node_t *value, const yp_location_t *name_loc, const yp_token_t *operator) {
|
2598
3115
|
yp_local_variable_write_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_write_node_t);
|
2599
3116
|
|
2600
3117
|
*node = (yp_local_variable_write_node_t) {
|
@@ -2602,10 +3119,10 @@ yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t consta
|
|
2602
3119
|
.type = YP_NODE_LOCAL_VARIABLE_WRITE_NODE,
|
2603
3120
|
.location = {
|
2604
3121
|
.start = name_loc->start,
|
2605
|
-
.end = value
|
3122
|
+
.end = value->location.end
|
2606
3123
|
}
|
2607
3124
|
},
|
2608
|
-
.
|
3125
|
+
.name = name,
|
2609
3126
|
.depth = depth,
|
2610
3127
|
.value = value,
|
2611
3128
|
.name_loc = *name_loc,
|
@@ -2615,21 +3132,18 @@ yp_local_variable_write_node_create(yp_parser_t *parser, yp_constant_id_t consta
|
|
2615
3132
|
return node;
|
2616
3133
|
}
|
2617
3134
|
|
2618
|
-
// Allocate and initialize a new
|
2619
|
-
static
|
3135
|
+
// Allocate and initialize a new LocalVariableTargetNode node.
|
3136
|
+
static yp_local_variable_target_node_t *
|
2620
3137
|
yp_local_variable_target_node_create(yp_parser_t *parser, const yp_token_t *name) {
|
2621
|
-
|
3138
|
+
yp_local_variable_target_node_t *node = YP_ALLOC_NODE(parser, yp_local_variable_target_node_t);
|
2622
3139
|
|
2623
|
-
*node = (
|
3140
|
+
*node = (yp_local_variable_target_node_t) {
|
2624
3141
|
{
|
2625
|
-
.type =
|
3142
|
+
.type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE,
|
2626
3143
|
.location = YP_LOCATION_TOKEN_VALUE(name)
|
2627
3144
|
},
|
2628
|
-
.
|
2629
|
-
.depth = 0
|
2630
|
-
.value = NULL,
|
2631
|
-
.name_loc = YP_LOCATION_TOKEN_VALUE(name),
|
2632
|
-
.operator_loc = { .start = NULL, .end = NULL }
|
3145
|
+
.name = yp_parser_constant_id_token(parser, name),
|
3146
|
+
.depth = 0
|
2633
3147
|
};
|
2634
3148
|
|
2635
3149
|
return node;
|
@@ -2679,7 +3193,7 @@ yp_match_required_node_create(yp_parser_t *parser, yp_node_t *value, yp_node_t *
|
|
2679
3193
|
|
2680
3194
|
// Allocate a new ModuleNode node.
|
2681
3195
|
static yp_module_node_t *
|
2682
|
-
yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *module_keyword, yp_node_t *constant_path, yp_node_t *body, const yp_token_t *end_keyword) {
|
3196
|
+
yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const yp_token_t *module_keyword, yp_node_t *constant_path, const yp_token_t *name, yp_node_t *body, const yp_token_t *end_keyword) {
|
2683
3197
|
yp_module_node_t *node = YP_ALLOC_NODE(parser, yp_module_node_t);
|
2684
3198
|
|
2685
3199
|
*node = (yp_module_node_t) {
|
@@ -2694,9 +3208,11 @@ yp_module_node_create(yp_parser_t *parser, yp_constant_id_list_t *locals, const
|
|
2694
3208
|
.module_keyword_loc = YP_LOCATION_TOKEN_VALUE(module_keyword),
|
2695
3209
|
.constant_path = constant_path,
|
2696
3210
|
.body = body,
|
2697
|
-
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword)
|
3211
|
+
.end_keyword_loc = YP_LOCATION_TOKEN_VALUE(end_keyword),
|
3212
|
+
.name = YP_EMPTY_STRING
|
2698
3213
|
};
|
2699
3214
|
|
3215
|
+
yp_string_shared_init(&node->name, name->start, name->end);
|
2700
3216
|
return node;
|
2701
3217
|
}
|
2702
3218
|
|
@@ -2708,7 +3224,10 @@ yp_multi_write_node_create(yp_parser_t *parser, const yp_token_t *operator, yp_n
|
|
2708
3224
|
*node = (yp_multi_write_node_t) {
|
2709
3225
|
{
|
2710
3226
|
.type = YP_NODE_MULTI_WRITE_NODE,
|
2711
|
-
.location = {
|
3227
|
+
.location = {
|
3228
|
+
.start = lparen_loc->start,
|
3229
|
+
.end = value == NULL ? rparen_loc->end : value->location.end
|
3230
|
+
},
|
2712
3231
|
},
|
2713
3232
|
.operator_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
|
2714
3233
|
.value = value,
|
@@ -2802,29 +3321,8 @@ yp_numbered_reference_read_node_create(yp_parser_t *parser, const yp_token_t *na
|
|
2802
3321
|
{
|
2803
3322
|
.type = YP_NODE_NUMBERED_REFERENCE_READ_NODE,
|
2804
3323
|
.location = YP_LOCATION_TOKEN_VALUE(name),
|
2805
|
-
}
|
2806
|
-
};
|
2807
|
-
|
2808
|
-
return node;
|
2809
|
-
}
|
2810
|
-
|
2811
|
-
// Allocate and initialize a new OperatorWriteNode.
|
2812
|
-
static yp_operator_write_node_t *
|
2813
|
-
yp_operator_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2814
|
-
yp_operator_write_node_t *node = YP_ALLOC_NODE(parser, yp_operator_write_node_t);
|
2815
|
-
|
2816
|
-
*node = (yp_operator_write_node_t) {
|
2817
|
-
{
|
2818
|
-
.type = YP_NODE_OPERATOR_WRITE_NODE,
|
2819
|
-
.location = {
|
2820
|
-
.start = target->location.start,
|
2821
|
-
.end = value->location.end
|
2822
|
-
},
|
2823
3324
|
},
|
2824
|
-
.
|
2825
|
-
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2826
|
-
.operator = yp_parser_constant_id_location(parser, operator->start, operator->end - 1),
|
2827
|
-
.value = value
|
3325
|
+
.number = parse_decimal_number(parser, name->start + 1, name->end)
|
2828
3326
|
};
|
2829
3327
|
|
2830
3328
|
return node;
|
@@ -2843,7 +3341,7 @@ yp_optional_parameter_node_create(yp_parser_t *parser, const yp_token_t *name, c
|
|
2843
3341
|
.end = value->location.end
|
2844
3342
|
}
|
2845
3343
|
},
|
2846
|
-
.
|
3344
|
+
.name = yp_parser_constant_id_token(parser, name),
|
2847
3345
|
.name_loc = YP_LOCATION_TOKEN_VALUE(name),
|
2848
3346
|
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator),
|
2849
3347
|
.value = value
|
@@ -2863,32 +3361,11 @@ yp_or_node_create(yp_parser_t *parser, yp_node_t *left, const yp_token_t *operat
|
|
2863
3361
|
.location = {
|
2864
3362
|
.start = left->location.start,
|
2865
3363
|
.end = right->location.end
|
2866
|
-
}
|
2867
|
-
},
|
2868
|
-
.left = left,
|
2869
|
-
.right = right,
|
2870
|
-
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator)
|
2871
|
-
};
|
2872
|
-
|
2873
|
-
return node;
|
2874
|
-
}
|
2875
|
-
|
2876
|
-
// Allocate and initialize a new OrWriteNode.
|
2877
|
-
static yp_or_write_node_t *
|
2878
|
-
yp_or_write_node_create(yp_parser_t *parser, yp_node_t *target, const yp_token_t *operator, yp_node_t *value) {
|
2879
|
-
yp_or_write_node_t *node = YP_ALLOC_NODE(parser, yp_or_write_node_t);
|
2880
|
-
|
2881
|
-
*node = (yp_or_write_node_t) {
|
2882
|
-
{
|
2883
|
-
.type = YP_NODE_OR_WRITE_NODE,
|
2884
|
-
.location = {
|
2885
|
-
.start = target->location.start,
|
2886
|
-
.end = value->location.end
|
2887
|
-
},
|
3364
|
+
}
|
2888
3365
|
},
|
2889
|
-
.
|
2890
|
-
.
|
2891
|
-
.
|
3366
|
+
.left = left,
|
3367
|
+
.right = right,
|
3368
|
+
.operator_loc = YP_LOCATION_TOKEN_VALUE(operator)
|
2892
3369
|
};
|
2893
3370
|
|
2894
3371
|
return node;
|
@@ -3161,8 +3638,8 @@ yp_regular_expression_node_create(yp_parser_t *parser, const yp_token_t *opening
|
|
3161
3638
|
.type = YP_NODE_REGULAR_EXPRESSION_NODE,
|
3162
3639
|
.flags = yp_regular_expression_flags_create(closing),
|
3163
3640
|
.location = {
|
3164
|
-
.start = opening->start,
|
3165
|
-
.end = closing->end
|
3641
|
+
.start = MIN(opening->start, closing->start),
|
3642
|
+
.end = MAX(opening->end, closing->end)
|
3166
3643
|
}
|
3167
3644
|
},
|
3168
3645
|
.opening_loc = YP_LOCATION_TOKEN_VALUE(opening),
|
@@ -3215,7 +3692,7 @@ yp_required_parameter_node_create(yp_parser_t *parser, const yp_token_t *token)
|
|
3215
3692
|
.type = YP_NODE_REQUIRED_PARAMETER_NODE,
|
3216
3693
|
.location = YP_LOCATION_TOKEN_VALUE(token)
|
3217
3694
|
},
|
3218
|
-
.
|
3695
|
+
.name = yp_parser_constant_id_token(parser, token)
|
3219
3696
|
};
|
3220
3697
|
|
3221
3698
|
return node;
|
@@ -3466,19 +3943,21 @@ yp_statements_node_body_length(yp_statements_node_t *node) {
|
|
3466
3943
|
|
3467
3944
|
// Set the location of the given StatementsNode.
|
3468
3945
|
static void
|
3469
|
-
yp_statements_node_location_set(yp_statements_node_t *node, const
|
3946
|
+
yp_statements_node_location_set(yp_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
|
3470
3947
|
node->base.location = (yp_location_t) { .start = start, .end = end };
|
3471
3948
|
}
|
3472
3949
|
|
3473
3950
|
// Append a new node to the given StatementsNode node's body.
|
3474
3951
|
static void
|
3475
3952
|
yp_statements_node_body_append(yp_statements_node_t *node, yp_node_t *statement) {
|
3476
|
-
if (yp_statements_node_body_length(node) == 0) {
|
3953
|
+
if (yp_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
|
3477
3954
|
node->base.location.start = statement->location.start;
|
3478
3955
|
}
|
3956
|
+
if (statement->location.end > node->base.location.end) {
|
3957
|
+
node->base.location.end = statement->location.end;
|
3958
|
+
}
|
3479
3959
|
|
3480
3960
|
yp_node_list_append(&node->body, statement);
|
3481
|
-
node->base.location.end = statement->location.end;
|
3482
3961
|
|
3483
3962
|
// Every statement gets marked as a place where a newline can occur.
|
3484
3963
|
statement->flags |= YP_NODE_FLAG_NEWLINE;
|
@@ -3532,7 +4011,7 @@ yp_super_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_argument
|
|
3532
4011
|
assert(keyword->type == YP_TOKEN_KEYWORD_SUPER);
|
3533
4012
|
yp_super_node_t *node = YP_ALLOC_NODE(parser, yp_super_node_t);
|
3534
4013
|
|
3535
|
-
const
|
4014
|
+
const uint8_t *end;
|
3536
4015
|
if (arguments->block != NULL) {
|
3537
4016
|
end = arguments->block->base.location.end;
|
3538
4017
|
} else if (arguments->closing_loc.start != NULL) {
|
@@ -3600,7 +4079,7 @@ yp_symbol_node_label_create(yp_parser_t *parser, const yp_token_t *token) {
|
|
3600
4079
|
assert((label.end - label.start) >= 0);
|
3601
4080
|
yp_string_shared_init(&node->unescaped, label.start, label.end);
|
3602
4081
|
|
3603
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL
|
4082
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL);
|
3604
4083
|
break;
|
3605
4084
|
}
|
3606
4085
|
case YP_TOKEN_MISSING: {
|
@@ -3623,7 +4102,7 @@ yp_symbol_node_label_create(yp_parser_t *parser, const yp_token_t *token) {
|
|
3623
4102
|
// Check if the given node is a label in a hash.
|
3624
4103
|
static bool
|
3625
4104
|
yp_symbol_node_label_p(yp_node_t *node) {
|
3626
|
-
const
|
4105
|
+
const uint8_t *end = NULL;
|
3627
4106
|
|
3628
4107
|
switch (YP_NODE_TYPE(node)) {
|
3629
4108
|
case YP_NODE_SYMBOL_NODE:
|
@@ -3641,20 +4120,20 @@ yp_symbol_node_label_p(yp_node_t *node) {
|
|
3641
4120
|
|
3642
4121
|
// Convert the given StringNode node to a SymbolNode node.
|
3643
4122
|
static yp_symbol_node_t *
|
3644
|
-
yp_string_node_to_symbol_node(yp_parser_t *parser, yp_string_node_t *node) {
|
4123
|
+
yp_string_node_to_symbol_node(yp_parser_t *parser, yp_string_node_t *node, const yp_token_t *opening, const yp_token_t *closing) {
|
3645
4124
|
yp_symbol_node_t *new_node = YP_ALLOC_NODE(parser, yp_symbol_node_t);
|
3646
4125
|
|
3647
4126
|
*new_node = (yp_symbol_node_t) {
|
3648
4127
|
{
|
3649
4128
|
.type = YP_NODE_SYMBOL_NODE,
|
3650
4129
|
.location = {
|
3651
|
-
.start =
|
3652
|
-
.end =
|
4130
|
+
.start = opening->start,
|
4131
|
+
.end = closing->end
|
3653
4132
|
}
|
3654
4133
|
},
|
3655
|
-
.opening_loc =
|
4134
|
+
.opening_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
|
3656
4135
|
.value_loc = node->content_loc,
|
3657
|
-
.closing_loc =
|
4136
|
+
.closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
|
3658
4137
|
.unescaped = node->unescaped
|
3659
4138
|
};
|
3660
4139
|
|
@@ -3731,7 +4210,7 @@ yp_unless_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t
|
|
3731
4210
|
yp_flip_flop(predicate);
|
3732
4211
|
yp_unless_node_t *node = YP_ALLOC_NODE(parser, yp_unless_node_t);
|
3733
4212
|
|
3734
|
-
const
|
4213
|
+
const uint8_t *end;
|
3735
4214
|
if (statements != NULL) {
|
3736
4215
|
end = statements->base.location.end;
|
3737
4216
|
} else {
|
@@ -3793,34 +4272,43 @@ yp_unless_node_end_keyword_loc_set(yp_unless_node_t *node, const yp_token_t *end
|
|
3793
4272
|
|
3794
4273
|
// Allocate a new UntilNode node.
|
3795
4274
|
static yp_until_node_t *
|
3796
|
-
yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4275
|
+
yp_until_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_token_t *closing, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
3797
4276
|
yp_until_node_t *node = YP_ALLOC_NODE(parser, yp_until_node_t);
|
3798
|
-
bool has_statements = (statements != NULL) && (statements->body.size != 0);
|
3799
4277
|
|
3800
|
-
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
3804
|
-
|
3805
|
-
|
4278
|
+
*node = (yp_until_node_t) {
|
4279
|
+
{
|
4280
|
+
.type = YP_NODE_UNTIL_NODE,
|
4281
|
+
.flags = flags,
|
4282
|
+
.location = {
|
4283
|
+
.start = keyword->start,
|
4284
|
+
.end = closing->end,
|
4285
|
+
},
|
4286
|
+
},
|
4287
|
+
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4288
|
+
.closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
|
4289
|
+
.predicate = predicate,
|
4290
|
+
.statements = statements
|
4291
|
+
};
|
3806
4292
|
|
3807
|
-
|
3808
|
-
|
3809
|
-
|
3810
|
-
|
3811
|
-
|
3812
|
-
|
4293
|
+
return node;
|
4294
|
+
}
|
4295
|
+
|
4296
|
+
// Allocate a new UntilNode node.
|
4297
|
+
static yp_until_node_t *
|
4298
|
+
yp_until_node_modifier_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4299
|
+
yp_until_node_t *node = YP_ALLOC_NODE(parser, yp_until_node_t);
|
3813
4300
|
|
3814
4301
|
*node = (yp_until_node_t) {
|
3815
4302
|
{
|
3816
4303
|
.type = YP_NODE_UNTIL_NODE,
|
3817
4304
|
.flags = flags,
|
3818
4305
|
.location = {
|
3819
|
-
.start = start,
|
3820
|
-
.end = end,
|
4306
|
+
.start = statements->base.location.start,
|
4307
|
+
.end = predicate->location.end,
|
3821
4308
|
},
|
3822
4309
|
},
|
3823
4310
|
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4311
|
+
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
3824
4312
|
.predicate = predicate,
|
3825
4313
|
.statements = statements
|
3826
4314
|
};
|
@@ -3868,34 +4356,43 @@ yp_when_node_statements_set(yp_when_node_t *node, yp_statements_node_t *statemen
|
|
3868
4356
|
|
3869
4357
|
// Allocate a new WhileNode node.
|
3870
4358
|
static yp_while_node_t *
|
3871
|
-
yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4359
|
+
yp_while_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_token_t *closing, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
3872
4360
|
yp_while_node_t *node = YP_ALLOC_NODE(parser, yp_while_node_t);
|
3873
4361
|
|
3874
|
-
|
3875
|
-
|
3876
|
-
|
3877
|
-
|
3878
|
-
|
3879
|
-
|
3880
|
-
|
4362
|
+
*node = (yp_while_node_t) {
|
4363
|
+
{
|
4364
|
+
.type = YP_NODE_WHILE_NODE,
|
4365
|
+
.flags = flags,
|
4366
|
+
.location = {
|
4367
|
+
.start = keyword->start,
|
4368
|
+
.end = closing->end
|
4369
|
+
},
|
4370
|
+
},
|
4371
|
+
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4372
|
+
.closing_loc = YP_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
|
4373
|
+
.predicate = predicate,
|
4374
|
+
.statements = statements
|
4375
|
+
};
|
3881
4376
|
|
3882
|
-
|
3883
|
-
|
3884
|
-
|
3885
|
-
|
3886
|
-
|
3887
|
-
|
4377
|
+
return node;
|
4378
|
+
}
|
4379
|
+
|
4380
|
+
// Allocate a new WhileNode node.
|
4381
|
+
static yp_while_node_t *
|
4382
|
+
yp_while_node_modifier_create(yp_parser_t *parser, const yp_token_t *keyword, yp_node_t *predicate, yp_statements_node_t *statements, yp_node_flags_t flags) {
|
4383
|
+
yp_while_node_t *node = YP_ALLOC_NODE(parser, yp_while_node_t);
|
3888
4384
|
|
3889
4385
|
*node = (yp_while_node_t) {
|
3890
4386
|
{
|
3891
4387
|
.type = YP_NODE_WHILE_NODE,
|
3892
4388
|
.flags = flags,
|
3893
4389
|
.location = {
|
3894
|
-
.start = start,
|
3895
|
-
.end = end
|
4390
|
+
.start = statements->base.location.start,
|
4391
|
+
.end = predicate->location.end
|
3896
4392
|
},
|
3897
4393
|
},
|
3898
4394
|
.keyword_loc = YP_LOCATION_TOKEN_VALUE(keyword),
|
4395
|
+
.closing_loc = YP_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
|
3899
4396
|
.predicate = predicate,
|
3900
4397
|
.statements = statements
|
3901
4398
|
};
|
@@ -3930,7 +4427,7 @@ static yp_yield_node_t *
|
|
3930
4427
|
yp_yield_node_create(yp_parser_t *parser, const yp_token_t *keyword, const yp_location_t *lparen_loc, yp_arguments_node_t *arguments, const yp_location_t *rparen_loc) {
|
3931
4428
|
yp_yield_node_t *node = YP_ALLOC_NODE(parser, yp_yield_node_t);
|
3932
4429
|
|
3933
|
-
const
|
4430
|
+
const uint8_t *end;
|
3934
4431
|
if (rparen_loc->start != NULL) {
|
3935
4432
|
end = rparen_loc->end;
|
3936
4433
|
} else if (arguments != NULL) {
|
@@ -4003,13 +4500,15 @@ yp_parser_local_depth(yp_parser_t *parser, yp_token_t *token) {
|
|
4003
4500
|
}
|
4004
4501
|
|
4005
4502
|
// Add a local variable from a location to the current scope.
|
4006
|
-
static
|
4007
|
-
yp_parser_local_add_location(yp_parser_t *parser, const
|
4503
|
+
static yp_constant_id_t
|
4504
|
+
yp_parser_local_add_location(yp_parser_t *parser, const uint8_t *start, const uint8_t *end) {
|
4008
4505
|
yp_constant_id_t constant_id = yp_parser_constant_id_location(parser, start, end);
|
4009
4506
|
|
4010
4507
|
if (!yp_constant_id_list_includes(&parser->current_scope->locals, constant_id)) {
|
4011
4508
|
yp_constant_id_list_append(&parser->current_scope->locals, constant_id);
|
4012
4509
|
}
|
4510
|
+
|
4511
|
+
return constant_id;
|
4013
4512
|
}
|
4014
4513
|
|
4015
4514
|
// Add a local variable from a token to the current scope.
|
@@ -4051,15 +4550,13 @@ yp_parser_scope_pop(yp_parser_t *parser) {
|
|
4051
4550
|
// reason we have the encoding_changed boolean to check if we need to go through
|
4052
4551
|
// the function pointer or can just directly use the UTF-8 functions.
|
4053
4552
|
static inline size_t
|
4054
|
-
char_is_identifier_start(yp_parser_t *parser, const
|
4055
|
-
const unsigned char uc = (unsigned char) *c;
|
4056
|
-
|
4553
|
+
char_is_identifier_start(yp_parser_t *parser, const uint8_t *b) {
|
4057
4554
|
if (parser->encoding_changed) {
|
4058
|
-
return parser->encoding.alpha_char(
|
4059
|
-
} else if (
|
4060
|
-
return (yp_encoding_unicode_table[
|
4555
|
+
return parser->encoding.alpha_char(b, parser->end - b) || (*b == '_') || (*b >= 0x80);
|
4556
|
+
} else if (*b < 0x80) {
|
4557
|
+
return (yp_encoding_unicode_table[*b] & YP_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b == '_');
|
4061
4558
|
} else {
|
4062
|
-
return (size_t) (yp_encoding_utf_8_alpha_char(
|
4559
|
+
return (size_t) (yp_encoding_utf_8_alpha_char(b, parser->end - b) || 1u);
|
4063
4560
|
}
|
4064
4561
|
}
|
4065
4562
|
|
@@ -4067,15 +4564,13 @@ char_is_identifier_start(yp_parser_t *parser, const char *c) {
|
|
4067
4564
|
// the identifiers in a source file once the first character has been found. So
|
4068
4565
|
// it's important that it be as fast as possible.
|
4069
4566
|
static inline size_t
|
4070
|
-
char_is_identifier(yp_parser_t *parser, const
|
4071
|
-
const unsigned char uc = (unsigned char) *c;
|
4072
|
-
|
4567
|
+
char_is_identifier(yp_parser_t *parser, const uint8_t *b) {
|
4073
4568
|
if (parser->encoding_changed) {
|
4074
|
-
return parser->encoding.alnum_char(
|
4075
|
-
} else if (
|
4076
|
-
return (yp_encoding_unicode_table[
|
4569
|
+
return parser->encoding.alnum_char(b, parser->end - b) || (*b == '_') || (*b >= 0x80);
|
4570
|
+
} else if (*b < 0x80) {
|
4571
|
+
return (yp_encoding_unicode_table[*b] & YP_ENCODING_ALPHANUMERIC_BIT ? 1 : 0) || (*b == '_');
|
4077
4572
|
} else {
|
4078
|
-
return (size_t) (yp_encoding_utf_8_alnum_char(
|
4573
|
+
return (size_t) (yp_encoding_utf_8_alnum_char(b, parser->end - b) || 1u);
|
4079
4574
|
}
|
4080
4575
|
}
|
4081
4576
|
|
@@ -4097,15 +4592,15 @@ const unsigned int yp_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = {
|
|
4097
4592
|
#undef PUNCT
|
4098
4593
|
|
4099
4594
|
static inline bool
|
4100
|
-
char_is_global_name_punctuation(const
|
4101
|
-
const unsigned int i = (const unsigned int)
|
4595
|
+
char_is_global_name_punctuation(const uint8_t b) {
|
4596
|
+
const unsigned int i = (const unsigned int) b;
|
4102
4597
|
if (i <= 0x20 || 0x7e < i) return false;
|
4103
4598
|
|
4104
|
-
return (yp_global_name_punctuation_hash[(i - 0x20) / 32] >> (
|
4599
|
+
return (yp_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
|
4105
4600
|
}
|
4106
4601
|
|
4107
4602
|
static inline bool
|
4108
|
-
token_is_numbered_parameter(const
|
4603
|
+
token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
|
4109
4604
|
return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (yp_char_is_decimal_digit(start[1]));
|
4110
4605
|
}
|
4111
4606
|
|
@@ -4157,44 +4652,47 @@ yp_do_loop_stack_p(yp_parser_t *parser) {
|
|
4157
4652
|
/* Lexer check helpers */
|
4158
4653
|
/******************************************************************************/
|
4159
4654
|
|
4160
|
-
// Get the next character in the source starting from
|
4161
|
-
//
|
4162
|
-
|
4163
|
-
|
4164
|
-
|
4165
|
-
|
4166
|
-
return parser->current.end[offset];
|
4655
|
+
// Get the next character in the source starting from +cursor+. If that position
|
4656
|
+
// is beyond the end of the source then return '\0'.
|
4657
|
+
static inline uint8_t
|
4658
|
+
peek_at(yp_parser_t *parser, const uint8_t *cursor) {
|
4659
|
+
if (cursor < parser->end) {
|
4660
|
+
return *cursor;
|
4167
4661
|
} else {
|
4168
4662
|
return '\0';
|
4169
4663
|
}
|
4170
4664
|
}
|
4171
4665
|
|
4666
|
+
// Get the next character in the source starting from parser->current.end and
|
4667
|
+
// adding the given offset. If that position is beyond the end of the source
|
4668
|
+
// then return '\0'.
|
4669
|
+
static inline uint8_t
|
4670
|
+
peek_offset(yp_parser_t *parser, ptrdiff_t offset) {
|
4671
|
+
return peek_at(parser, parser->current.end + offset);
|
4672
|
+
}
|
4673
|
+
|
4172
4674
|
// Get the next character in the source starting from parser->current.end. If
|
4173
4675
|
// that position is beyond the end of the source then return '\0'.
|
4174
|
-
static inline
|
4676
|
+
static inline uint8_t
|
4175
4677
|
peek(yp_parser_t *parser) {
|
4176
|
-
|
4177
|
-
return *parser->current.end;
|
4178
|
-
} else {
|
4179
|
-
return '\0';
|
4180
|
-
}
|
4678
|
+
return peek_at(parser, parser->current.end);
|
4181
4679
|
}
|
4182
4680
|
|
4183
4681
|
// Get the next string of length len in the source starting from parser->current.end.
|
4184
4682
|
// If the string extends beyond the end of the source, return the empty string ""
|
4185
|
-
static inline const
|
4683
|
+
static inline const uint8_t *
|
4186
4684
|
peek_string(yp_parser_t *parser, size_t len) {
|
4187
4685
|
if (parser->current.end + len <= parser->end) {
|
4188
4686
|
return parser->current.end;
|
4189
4687
|
} else {
|
4190
|
-
return "";
|
4688
|
+
return (const uint8_t *) "";
|
4191
4689
|
}
|
4192
4690
|
}
|
4193
4691
|
|
4194
4692
|
// If the character to be read matches the given value, then returns true and
|
4195
4693
|
// advanced the current pointer.
|
4196
4694
|
static inline bool
|
4197
|
-
match(yp_parser_t *parser,
|
4695
|
+
match(yp_parser_t *parser, uint8_t value) {
|
4198
4696
|
if (peek(parser) == value) {
|
4199
4697
|
parser->current.end++;
|
4200
4698
|
return true;
|
@@ -4202,9 +4700,38 @@ match(yp_parser_t *parser, char value) {
|
|
4202
4700
|
return false;
|
4203
4701
|
}
|
4204
4702
|
|
4703
|
+
// Return the length of the line ending string starting at +cursor+, or 0 if it
|
4704
|
+
// is not a line ending. This function is intended to be CRLF/LF agnostic.
|
4705
|
+
static inline size_t
|
4706
|
+
match_eol_at(yp_parser_t *parser, const uint8_t *cursor) {
|
4707
|
+
if (peek_at(parser, cursor) == '\n') {
|
4708
|
+
return 1;
|
4709
|
+
}
|
4710
|
+
if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
|
4711
|
+
return 2;
|
4712
|
+
}
|
4713
|
+
return 0;
|
4714
|
+
}
|
4715
|
+
|
4716
|
+
// Return the length of the line ending string starting at
|
4717
|
+
// parser->current.end + offset, or 0 if it is not a line ending. This function
|
4718
|
+
// is intended to be CRLF/LF agnostic.
|
4719
|
+
static inline size_t
|
4720
|
+
match_eol_offset(yp_parser_t *parser, ptrdiff_t offset) {
|
4721
|
+
return match_eol_at(parser, parser->current.end + offset);
|
4722
|
+
}
|
4723
|
+
|
4724
|
+
// Return the length of the line ending string starting at parser->current.end,
|
4725
|
+
// or 0 if it is not a line ending. This function is intended to be CRLF/LF
|
4726
|
+
// agnostic.
|
4727
|
+
static inline size_t
|
4728
|
+
match_eol(yp_parser_t *parser) {
|
4729
|
+
return match_eol_at(parser, parser->current.end);
|
4730
|
+
}
|
4731
|
+
|
4205
4732
|
// Skip to the next newline character or NUL byte.
|
4206
|
-
static inline const
|
4207
|
-
next_newline(const
|
4733
|
+
static inline const uint8_t *
|
4734
|
+
next_newline(const uint8_t *cursor, ptrdiff_t length) {
|
4208
4735
|
assert(length >= 0);
|
4209
4736
|
|
4210
4737
|
// Note that it's okay for us to use memchr here to look for \n because none
|
@@ -4215,21 +4742,23 @@ next_newline(const char *cursor, ptrdiff_t length) {
|
|
4215
4742
|
|
4216
4743
|
// Find the start of the encoding comment. This is effectively an inlined
|
4217
4744
|
// version of strnstr with some modifications.
|
4218
|
-
static inline const
|
4219
|
-
parser_lex_encoding_comment_start(yp_parser_t *parser, const
|
4745
|
+
static inline const uint8_t *
|
4746
|
+
parser_lex_encoding_comment_start(yp_parser_t *parser, const uint8_t *cursor, ptrdiff_t remaining) {
|
4220
4747
|
assert(remaining >= 0);
|
4221
4748
|
size_t length = (size_t) remaining;
|
4222
4749
|
|
4223
4750
|
size_t key_length = strlen("coding:");
|
4224
4751
|
if (key_length > length) return NULL;
|
4225
4752
|
|
4226
|
-
const
|
4753
|
+
const uint8_t *cursor_limit = cursor + length - key_length + 1;
|
4227
4754
|
while ((cursor = yp_memchr(cursor, 'c', (size_t) (cursor_limit - cursor), parser->encoding_changed, &parser->encoding)) != NULL) {
|
4228
|
-
if (
|
4229
|
-
(
|
4230
|
-
|
4231
|
-
|
4232
|
-
|
4755
|
+
if (memcmp(cursor, "coding", key_length - 1) == 0) {
|
4756
|
+
size_t whitespace_after_coding = yp_strspn_inline_whitespace(cursor + key_length - 1, parser->end - (cursor + key_length - 1));
|
4757
|
+
size_t cur_pos = key_length + whitespace_after_coding;
|
4758
|
+
|
4759
|
+
if (cursor[cur_pos - 1] == ':' || cursor[cur_pos - 1] == '=') {
|
4760
|
+
return cursor + cur_pos;
|
4761
|
+
}
|
4233
4762
|
}
|
4234
4763
|
|
4235
4764
|
cursor++;
|
@@ -4242,13 +4771,13 @@ parser_lex_encoding_comment_start(yp_parser_t *parser, const char *cursor, ptrdi
|
|
4242
4771
|
// actions are necessary for it here.
|
4243
4772
|
static void
|
4244
4773
|
parser_lex_encoding_comment(yp_parser_t *parser) {
|
4245
|
-
const
|
4246
|
-
const
|
4774
|
+
const uint8_t *start = parser->current.start + 1;
|
4775
|
+
const uint8_t *end = next_newline(start, parser->end - start);
|
4247
4776
|
if (end == NULL) end = parser->end;
|
4248
4777
|
|
4249
4778
|
// These are the patterns we're going to match to find the encoding comment.
|
4250
4779
|
// This is definitely not complete or even really correct.
|
4251
|
-
const
|
4780
|
+
const uint8_t *encoding_start = parser_lex_encoding_comment_start(parser, start, end - start);
|
4252
4781
|
|
4253
4782
|
// If we didn't find anything that matched our patterns, then return. Note
|
4254
4783
|
// that this does a _very_ poor job of actually finding the encoding, and
|
@@ -4261,7 +4790,7 @@ parser_lex_encoding_comment(yp_parser_t *parser) {
|
|
4261
4790
|
|
4262
4791
|
// Now determine the end of the encoding string. This is either the end of
|
4263
4792
|
// the line, the first whitespace character, or a punctuation mark.
|
4264
|
-
const
|
4793
|
+
const uint8_t *encoding_end = yp_strpbrk(parser, encoding_start, (const uint8_t *) " \t\f\r\v\n;,", end - encoding_start);
|
4265
4794
|
encoding_end = encoding_end == NULL ? end : encoding_end;
|
4266
4795
|
|
4267
4796
|
// Finally, we can determine the width of the encoding string.
|
@@ -4283,7 +4812,7 @@ parser_lex_encoding_comment(yp_parser_t *parser) {
|
|
4283
4812
|
// Extensions like utf-8 can contain extra encoding details like,
|
4284
4813
|
// utf-8-dos, utf-8-linux, utf-8-mac. We treat these all as utf-8 should
|
4285
4814
|
// treat any encoding starting utf-8 as utf-8.
|
4286
|
-
if ((encoding_start + 5 <= parser->end) && (yp_strncasecmp(encoding_start, "utf-8", 5) == 0)) {
|
4815
|
+
if ((encoding_start + 5 <= parser->end) && (yp_strncasecmp(encoding_start, (const uint8_t *) "utf-8", 5) == 0)) {
|
4287
4816
|
// We don't need to do anything here because the default encoding is
|
4288
4817
|
// already UTF-8. We'll just return.
|
4289
4818
|
return;
|
@@ -4292,7 +4821,7 @@ parser_lex_encoding_comment(yp_parser_t *parser) {
|
|
4292
4821
|
// Next, we're going to loop through each of the encodings that we handle
|
4293
4822
|
// explicitly. If we found one that we understand, we'll use that value.
|
4294
4823
|
#define ENCODING(value, prebuilt) \
|
4295
|
-
if (width == sizeof(value) - 1 && encoding_start + width <= parser->end && yp_strncasecmp(encoding_start, value, width) == 0) { \
|
4824
|
+
if (width == sizeof(value) - 1 && encoding_start + width <= parser->end && yp_strncasecmp(encoding_start, (const uint8_t *) value, width) == 0) { \
|
4296
4825
|
parser->encoding = prebuilt; \
|
4297
4826
|
parser->encoding_changed |= true; \
|
4298
4827
|
if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser); \
|
@@ -4432,14 +4961,9 @@ context_push(yp_parser_t *parser, yp_context_t context) {
|
|
4432
4961
|
|
4433
4962
|
static void
|
4434
4963
|
context_pop(yp_parser_t *parser) {
|
4435
|
-
|
4436
|
-
|
4437
|
-
|
4438
|
-
} else {
|
4439
|
-
yp_context_node_t *prev = parser->current_context->prev;
|
4440
|
-
free(parser->current_context);
|
4441
|
-
parser->current_context = prev;
|
4442
|
-
}
|
4964
|
+
yp_context_node_t *prev = parser->current_context->prev;
|
4965
|
+
free(parser->current_context);
|
4966
|
+
parser->current_context = prev;
|
4443
4967
|
}
|
4444
4968
|
|
4445
4969
|
static bool
|
@@ -4485,7 +5009,7 @@ lex_optional_float_suffix(yp_parser_t *parser) {
|
|
4485
5009
|
// Here we're going to attempt to parse the optional decimal portion of a
|
4486
5010
|
// float. If it's not there, then it's okay and we'll just continue on.
|
4487
5011
|
if (peek(parser) == '.') {
|
4488
|
-
if (yp_char_is_decimal_digit(
|
5012
|
+
if (yp_char_is_decimal_digit(peek_offset(parser, 1))) {
|
4489
5013
|
parser->current.end += 2;
|
4490
5014
|
parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end);
|
4491
5015
|
type = YP_TOKEN_FLOAT;
|
@@ -4518,12 +5042,13 @@ static yp_token_type_t
|
|
4518
5042
|
lex_numeric_prefix(yp_parser_t *parser) {
|
4519
5043
|
yp_token_type_t type = YP_TOKEN_INTEGER;
|
4520
5044
|
|
4521
|
-
if (parser
|
5045
|
+
if (peek_offset(parser, -1) == '0') {
|
4522
5046
|
switch (*parser->current.end) {
|
4523
5047
|
// 0d1111 is a decimal number
|
4524
5048
|
case 'd':
|
4525
5049
|
case 'D':
|
4526
|
-
|
5050
|
+
parser->current.end++;
|
5051
|
+
if (yp_char_is_decimal_digit(peek(parser))) {
|
4527
5052
|
parser->current.end += yp_strspn_decimal_number(parser->current.end, parser->end - parser->current.end);
|
4528
5053
|
} else {
|
4529
5054
|
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid decimal number.");
|
@@ -4534,7 +5059,8 @@ lex_numeric_prefix(yp_parser_t *parser) {
|
|
4534
5059
|
// 0b1111 is a binary number
|
4535
5060
|
case 'b':
|
4536
5061
|
case 'B':
|
4537
|
-
|
5062
|
+
parser->current.end++;
|
5063
|
+
if (yp_char_is_binary_digit(peek(parser))) {
|
4538
5064
|
parser->current.end += yp_strspn_binary_number(parser->current.end, parser->end - parser->current.end);
|
4539
5065
|
} else {
|
4540
5066
|
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid binary number.");
|
@@ -4545,7 +5071,8 @@ lex_numeric_prefix(yp_parser_t *parser) {
|
|
4545
5071
|
// 0o1111 is an octal number
|
4546
5072
|
case 'o':
|
4547
5073
|
case 'O':
|
4548
|
-
|
5074
|
+
parser->current.end++;
|
5075
|
+
if (yp_char_is_octal_digit(peek(parser))) {
|
4549
5076
|
parser->current.end += yp_strspn_octal_number(parser->current.end, parser->end - parser->current.end);
|
4550
5077
|
} else {
|
4551
5078
|
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid octal number.");
|
@@ -4569,7 +5096,8 @@ lex_numeric_prefix(yp_parser_t *parser) {
|
|
4569
5096
|
// 0x1111 is a hexadecimal number
|
4570
5097
|
case 'x':
|
4571
5098
|
case 'X':
|
4572
|
-
|
5099
|
+
parser->current.end++;
|
5100
|
+
if (yp_char_is_hexadecimal_digit(peek(parser))) {
|
4573
5101
|
parser->current.end += yp_strspn_hexadecimal_number(parser->current.end, parser->end - parser->current.end);
|
4574
5102
|
} else {
|
4575
5103
|
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid hexadecimal number.");
|
@@ -4601,7 +5129,7 @@ lex_numeric_prefix(yp_parser_t *parser) {
|
|
4601
5129
|
|
4602
5130
|
// If the last character that we consumed was an underscore, then this is
|
4603
5131
|
// actually an invalid integer value, and we should return an invalid token.
|
4604
|
-
if (parser
|
5132
|
+
if (peek_offset(parser, -1) == '_') {
|
4605
5133
|
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Number literal cannot end with a `_`.");
|
4606
5134
|
}
|
4607
5135
|
|
@@ -4615,7 +5143,7 @@ lex_numeric(yp_parser_t *parser) {
|
|
4615
5143
|
if (parser->current.end < parser->end) {
|
4616
5144
|
type = lex_numeric_prefix(parser);
|
4617
5145
|
|
4618
|
-
const
|
5146
|
+
const uint8_t *end = parser->current.end;
|
4619
5147
|
yp_token_type_t suffix_type = type;
|
4620
5148
|
|
4621
5149
|
if (type == YP_TOKEN_INTEGER) {
|
@@ -4640,8 +5168,8 @@ lex_numeric(yp_parser_t *parser) {
|
|
4640
5168
|
}
|
4641
5169
|
}
|
4642
5170
|
|
4643
|
-
const
|
4644
|
-
if (
|
5171
|
+
const uint8_t b = peek(parser);
|
5172
|
+
if (b != '\0' && (b >= 0x80 || ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z')) || b == '_')) {
|
4645
5173
|
parser->current.end = end;
|
4646
5174
|
} else {
|
4647
5175
|
type = suffix_type;
|
@@ -4653,6 +5181,11 @@ lex_numeric(yp_parser_t *parser) {
|
|
4653
5181
|
|
4654
5182
|
static yp_token_type_t
|
4655
5183
|
lex_global_variable(yp_parser_t *parser) {
|
5184
|
+
if (parser->current.end >= parser->end) {
|
5185
|
+
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid global variable.");
|
5186
|
+
return YP_TOKEN_GLOBAL_VARIABLE;
|
5187
|
+
}
|
5188
|
+
|
4656
5189
|
switch (*parser->current.end) {
|
4657
5190
|
case '~': // $~: match-data
|
4658
5191
|
case '*': // $*: argv
|
@@ -4741,7 +5274,7 @@ lex_keyword(yp_parser_t *parser, const char *value, yp_lex_state_t state, yp_tok
|
|
4741
5274
|
yp_lex_state_t last_state = parser->lex_state;
|
4742
5275
|
|
4743
5276
|
const size_t vlen = strlen(value);
|
4744
|
-
if (parser->current.start + vlen <= parser->end &&
|
5277
|
+
if (parser->current.start + vlen <= parser->end && memcmp(parser->current.start, value, vlen) == 0) {
|
4745
5278
|
if (parser->lex_state & YP_LEX_STATE_FNAME) {
|
4746
5279
|
lex_state_set(parser, YP_LEX_STATE_ENDFN);
|
4747
5280
|
} else {
|
@@ -4782,7 +5315,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
4782
5315
|
|
4783
5316
|
if (
|
4784
5317
|
((lex_state_p(parser, YP_LEX_STATE_LABEL | YP_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
|
4785
|
-
(peek(parser) == ':') && (
|
5318
|
+
(peek(parser) == ':') && (peek_offset(parser, 1) != ':')
|
4786
5319
|
) {
|
4787
5320
|
// If we're in a position where we can accept a : at the end of an
|
4788
5321
|
// identifier, then we'll optionally accept it.
|
@@ -4798,7 +5331,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
4798
5331
|
}
|
4799
5332
|
|
4800
5333
|
return YP_TOKEN_IDENTIFIER;
|
4801
|
-
} else if (lex_state_p(parser, YP_LEX_STATE_FNAME) &&
|
5334
|
+
} else if (lex_state_p(parser, YP_LEX_STATE_FNAME) && peek_offset(parser, 1) != '~' && peek_offset(parser, 1) != '>' && (peek_offset(parser, 1) != '=' || peek_offset(parser, 2) == '>') && match(parser, '=')) {
|
4802
5335
|
// If we're in a position where we can accept a = at the end of an
|
4803
5336
|
// identifier, then we'll optionally accept it.
|
4804
5337
|
return YP_TOKEN_IDENTIFIER;
|
@@ -4806,7 +5339,7 @@ lex_identifier(yp_parser_t *parser, bool previous_command_start) {
|
|
4806
5339
|
|
4807
5340
|
if (
|
4808
5341
|
((lex_state_p(parser, YP_LEX_STATE_LABEL | YP_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
|
4809
|
-
peek(parser) == ':' &&
|
5342
|
+
peek(parser) == ':' && peek_offset(parser, 1) != ':'
|
4810
5343
|
) {
|
4811
5344
|
// If we're in a position where we can accept a : at the end of an
|
4812
5345
|
// identifier, then we'll optionally accept it.
|
@@ -4907,7 +5440,7 @@ current_token_starts_line(yp_parser_t *parser) {
|
|
4907
5440
|
// this token type.
|
4908
5441
|
//
|
4909
5442
|
static yp_token_type_t
|
4910
|
-
lex_interpolation(yp_parser_t *parser, const
|
5443
|
+
lex_interpolation(yp_parser_t *parser, const uint8_t *pound) {
|
4911
5444
|
// If there is no content following this #, then we're at the end of
|
4912
5445
|
// the string and we can safely return string content.
|
4913
5446
|
if (pound + 1 >= parser->end) {
|
@@ -4928,7 +5461,7 @@ lex_interpolation(yp_parser_t *parser, const char *pound) {
|
|
4928
5461
|
|
4929
5462
|
// If we're looking at a @ and there's another @, then we'll skip past the
|
4930
5463
|
// second @.
|
4931
|
-
const
|
5464
|
+
const uint8_t *variable = pound + 2;
|
4932
5465
|
if (*variable == '@' && pound + 3 < parser->end) variable++;
|
4933
5466
|
|
4934
5467
|
if (char_is_identifier_start(parser, variable)) {
|
@@ -4964,7 +5497,7 @@ lex_interpolation(yp_parser_t *parser, const char *pound) {
|
|
4964
5497
|
// This is the character that we're going to check to see if it is the
|
4965
5498
|
// start of an identifier that would indicate that this is a global
|
4966
5499
|
// variable.
|
4967
|
-
const
|
5500
|
+
const uint8_t *check = pound + 2;
|
4968
5501
|
|
4969
5502
|
if (pound[2] == '-') {
|
4970
5503
|
if (pound + 3 >= parser->end) {
|
@@ -5074,7 +5607,7 @@ lex_question_mark(yp_parser_t *parser) {
|
|
5074
5607
|
|
5075
5608
|
if (parser->current.start[1] == '\\') {
|
5076
5609
|
lex_state_set(parser, YP_LEX_STATE_END);
|
5077
|
-
parser->current.end += yp_unescape_calculate_difference(parser->current.start + 1,
|
5610
|
+
parser->current.end += yp_unescape_calculate_difference(parser, parser->current.start + 1, YP_UNESCAPE_ALL, true);
|
5078
5611
|
return YP_TOKEN_CHARACTER_LITERAL;
|
5079
5612
|
} else {
|
5080
5613
|
size_t encoding_width = parser->encoding.char_width(parser->current.end, parser->end - parser->current.end);
|
@@ -5083,7 +5616,7 @@ lex_question_mark(yp_parser_t *parser) {
|
|
5083
5616
|
// an underscore. We check for this case
|
5084
5617
|
if (
|
5085
5618
|
!(parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end) ||
|
5086
|
-
|
5619
|
+
peek(parser) == '_') ||
|
5087
5620
|
(
|
5088
5621
|
(parser->current.end + encoding_width >= parser->end) ||
|
5089
5622
|
!char_is_identifier(parser, parser->current.end + encoding_width)
|
@@ -5155,7 +5688,7 @@ parser_comment(yp_parser_t *parser, yp_comment_type_t type) {
|
|
5155
5688
|
static yp_token_type_t
|
5156
5689
|
lex_embdoc(yp_parser_t *parser) {
|
5157
5690
|
// First, lex out the EMBDOC_BEGIN token.
|
5158
|
-
const
|
5691
|
+
const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
|
5159
5692
|
|
5160
5693
|
if (newline == NULL) {
|
5161
5694
|
parser->current.end = parser->end;
|
@@ -5178,9 +5711,9 @@ lex_embdoc(yp_parser_t *parser) {
|
|
5178
5711
|
|
5179
5712
|
// If we've hit the end of the embedded documentation then we'll return that
|
5180
5713
|
// token here.
|
5181
|
-
if (
|
5714
|
+
if (memcmp(parser->current.end, "=end", 4) == 0 &&
|
5182
5715
|
(parser->current.end + 4 == parser->end || yp_char_is_whitespace(parser->current.end[4]))) {
|
5183
|
-
const
|
5716
|
+
const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
|
5184
5717
|
|
5185
5718
|
if (newline == NULL) {
|
5186
5719
|
parser->current.end = parser->end;
|
@@ -5200,7 +5733,7 @@ lex_embdoc(yp_parser_t *parser) {
|
|
5200
5733
|
|
5201
5734
|
// Otherwise, we'll parse until the end of the line and return a line of
|
5202
5735
|
// embedded documentation.
|
5203
|
-
const
|
5736
|
+
const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
|
5204
5737
|
|
5205
5738
|
if (newline == NULL) {
|
5206
5739
|
parser->current.end = parser->end;
|
@@ -5299,30 +5832,22 @@ parser_lex(yp_parser_t *parser) {
|
|
5299
5832
|
space_seen = true;
|
5300
5833
|
break;
|
5301
5834
|
case '\r':
|
5302
|
-
if (
|
5835
|
+
if (match_eol_offset(parser, 1)) {
|
5303
5836
|
chomping = false;
|
5304
5837
|
} else {
|
5305
5838
|
parser->current.end++;
|
5306
5839
|
space_seen = true;
|
5307
5840
|
}
|
5308
5841
|
break;
|
5309
|
-
case '\\':
|
5310
|
-
|
5311
|
-
|
5312
|
-
parser->current.end = parser->heredoc_end;
|
5313
|
-
parser->heredoc_end = NULL;
|
5314
|
-
} else {
|
5315
|
-
yp_newline_list_append(&parser->newline_list, parser->current.end + 1);
|
5316
|
-
parser->current.end += 2;
|
5317
|
-
space_seen = true;
|
5318
|
-
}
|
5319
|
-
} else if (peek_at(parser, 1) == '\r' && peek_at(parser, 2) == '\n') {
|
5842
|
+
case '\\': {
|
5843
|
+
size_t eol_length = match_eol_offset(parser, 1);
|
5844
|
+
if (eol_length) {
|
5320
5845
|
if (parser->heredoc_end) {
|
5321
5846
|
parser->current.end = parser->heredoc_end;
|
5322
5847
|
parser->heredoc_end = NULL;
|
5323
5848
|
} else {
|
5324
|
-
|
5325
|
-
parser->current.end
|
5849
|
+
parser->current.end += eol_length + 1;
|
5850
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
5326
5851
|
space_seen = true;
|
5327
5852
|
}
|
5328
5853
|
} else if (yp_char_is_inline_whitespace(*parser->current.end)) {
|
@@ -5330,7 +5855,9 @@ parser_lex(yp_parser_t *parser) {
|
|
5330
5855
|
} else {
|
5331
5856
|
chomping = false;
|
5332
5857
|
}
|
5858
|
+
|
5333
5859
|
break;
|
5860
|
+
}
|
5334
5861
|
default:
|
5335
5862
|
chomping = false;
|
5336
5863
|
break;
|
@@ -5340,13 +5867,14 @@ parser_lex(yp_parser_t *parser) {
|
|
5340
5867
|
// Next, we'll set to start of this token to be the current end.
|
5341
5868
|
parser->current.start = parser->current.end;
|
5342
5869
|
|
5343
|
-
// We'll check if we're at the end of the file. If we are, then we
|
5344
|
-
// return the EOF token.
|
5870
|
+
// We'll check if we're at the end of the file. If we are, then we
|
5871
|
+
// need to return the EOF token.
|
5345
5872
|
if (parser->current.end >= parser->end) {
|
5346
5873
|
LEX(YP_TOKEN_EOF);
|
5347
5874
|
}
|
5348
5875
|
|
5349
|
-
// Finally, we'll check the current character to determine the next
|
5876
|
+
// Finally, we'll check the current character to determine the next
|
5877
|
+
// token.
|
5350
5878
|
switch (*parser->current.end++) {
|
5351
5879
|
case '\0': // NUL or end of script
|
5352
5880
|
case '\004': // ^D
|
@@ -5355,17 +5883,15 @@ parser_lex(yp_parser_t *parser) {
|
|
5355
5883
|
LEX(YP_TOKEN_EOF);
|
5356
5884
|
|
5357
5885
|
case '#': { // comments
|
5358
|
-
const
|
5359
|
-
while (ending && ending < parser->end && *ending != '\n') {
|
5360
|
-
ending = next_newline(ending + 1, parser->end - ending);
|
5361
|
-
}
|
5886
|
+
const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
|
5362
5887
|
|
5363
5888
|
parser->current.end = ending == NULL ? parser->end : ending + 1;
|
5364
5889
|
parser->current.type = YP_TOKEN_COMMENT;
|
5365
5890
|
parser_lex_callback(parser);
|
5366
5891
|
|
5367
|
-
// If we found a comment while lexing, then we're going to
|
5368
|
-
// list of comments in the file and keep
|
5892
|
+
// If we found a comment while lexing, then we're going to
|
5893
|
+
// add it to the list of comments in the file and keep
|
5894
|
+
// lexing.
|
5369
5895
|
yp_comment_t *comment = parser_comment(parser, YP_COMMENT_INLINE);
|
5370
5896
|
yp_list_append(&parser->comment_list, (yp_list_node_t *) comment);
|
5371
5897
|
|
@@ -5376,21 +5902,29 @@ parser_lex(yp_parser_t *parser) {
|
|
5376
5902
|
lexed_comment = true;
|
5377
5903
|
}
|
5378
5904
|
/* fallthrough */
|
5379
|
-
case '\r':
|
5380
|
-
// The only way you can have carriage returns in this particular loop
|
5381
|
-
// is if you have a carriage return followed by a newline. In that
|
5382
|
-
// case we'll just skip over the carriage return and continue lexing,
|
5383
|
-
// in order to make it so that the newline token encapsulates both the
|
5384
|
-
// carriage return and the newline. Note that we need to check that
|
5385
|
-
// we haven't already lexed a comment here because that falls through
|
5386
|
-
// into here as well.
|
5387
|
-
if (!lexed_comment) parser->current.end++;
|
5388
|
-
}
|
5389
|
-
/* fallthrough */
|
5905
|
+
case '\r':
|
5390
5906
|
case '\n': {
|
5391
|
-
|
5392
|
-
|
5393
|
-
|
5907
|
+
size_t eol_length = match_eol_at(parser, parser->current.end - 1);
|
5908
|
+
if (eol_length) {
|
5909
|
+
// The only way you can have carriage returns in this
|
5910
|
+
// particular loop is if you have a carriage return
|
5911
|
+
// followed by a newline. In that case we'll just skip
|
5912
|
+
// over the carriage return and continue lexing, in
|
5913
|
+
// order to make it so that the newline token
|
5914
|
+
// encapsulates both the carriage return and the
|
5915
|
+
// newline. Note that we need to check that we haven't
|
5916
|
+
// already lexed a comment here because that falls
|
5917
|
+
// through into here as well.
|
5918
|
+
if (!lexed_comment) {
|
5919
|
+
parser->current.end += eol_length - 1; // skip CR
|
5920
|
+
}
|
5921
|
+
|
5922
|
+
if (parser->heredoc_end == NULL) {
|
5923
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
5924
|
+
}
|
5925
|
+
}
|
5926
|
+
|
5927
|
+
if (parser->heredoc_end) {
|
5394
5928
|
parser_flush_heredoc_end(parser);
|
5395
5929
|
}
|
5396
5930
|
|
@@ -5418,7 +5952,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5418
5952
|
// (either . or &.) that starts the next line. If there is, then this
|
5419
5953
|
// is going to become an ignored newline and we're going to instead
|
5420
5954
|
// return the call operator.
|
5421
|
-
const
|
5955
|
+
const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
|
5422
5956
|
next_content += yp_strspn_inline_whitespace(next_content, parser->end - next_content);
|
5423
5957
|
|
5424
5958
|
if (next_content < parser->end) {
|
@@ -5429,15 +5963,15 @@ parser_lex(yp_parser_t *parser) {
|
|
5429
5963
|
// Otherwise we'll return a regular newline.
|
5430
5964
|
if (next_content[0] == '#') {
|
5431
5965
|
// Here we look for a "." or "&." following a "\n".
|
5432
|
-
const
|
5966
|
+
const uint8_t *following = next_newline(next_content, parser->end - next_content);
|
5433
5967
|
|
5434
|
-
while (following && (following < parser->end)) {
|
5968
|
+
while (following && (following + 1 < parser->end)) {
|
5435
5969
|
following++;
|
5436
5970
|
following += yp_strspn_inline_whitespace(following, parser->end - following);
|
5437
5971
|
|
5438
5972
|
// If this is not followed by a comment, then we can break out
|
5439
5973
|
// of this loop.
|
5440
|
-
if (
|
5974
|
+
if (peek_at(parser, following) != '#') break;
|
5441
5975
|
|
5442
5976
|
// If there is a comment, then we need to find the end of the
|
5443
5977
|
// comment and continue searching from there.
|
@@ -5446,7 +5980,13 @@ parser_lex(yp_parser_t *parser) {
|
|
5446
5980
|
|
5447
5981
|
// If the lex state was ignored, or we hit a '.' or a '&.',
|
5448
5982
|
// we will lex the ignored newline
|
5449
|
-
if (
|
5983
|
+
if (
|
5984
|
+
lex_state_ignored_p(parser) ||
|
5985
|
+
(following && (
|
5986
|
+
(peek_at(parser, following) == '.') ||
|
5987
|
+
(peek_at(parser, following) == '&' && peek_at(parser, following + 1) == '.')
|
5988
|
+
))
|
5989
|
+
) {
|
5450
5990
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5451
5991
|
lexed_comment = false;
|
5452
5992
|
goto lex_next_token;
|
@@ -5459,7 +5999,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5459
5999
|
// To match ripper, we need to emit an ignored newline even though
|
5460
6000
|
// its a real newline in the case that we have a beginless range
|
5461
6001
|
// on a subsequent line.
|
5462
|
-
if ((next_content + 1
|
6002
|
+
if (peek_at(parser, next_content + 1) == '.') {
|
5463
6003
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5464
6004
|
lex_state_set(parser, YP_LEX_STATE_BEG);
|
5465
6005
|
parser->command_start = true;
|
@@ -5477,7 +6017,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5477
6017
|
|
5478
6018
|
// If we hit a &. after a newline, then we're in a call chain and
|
5479
6019
|
// we need to return the call operator.
|
5480
|
-
if (
|
6020
|
+
if (peek_at(parser, next_content) == '&' && peek_at(parser, next_content + 1) == '.') {
|
5481
6021
|
if (!lexed_comment) parser_lex_ignored_newline(parser);
|
5482
6022
|
lex_state_set(parser, YP_LEX_STATE_DOT);
|
5483
6023
|
parser->current.start = next_content;
|
@@ -5674,7 +6214,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5674
6214
|
|
5675
6215
|
// = => =~ == === =begin
|
5676
6216
|
case '=':
|
5677
|
-
if (current_token_starts_line(parser) &&
|
6217
|
+
if (current_token_starts_line(parser) && memcmp(peek_string(parser, 5), "begin", 5) == 0 && yp_char_is_whitespace(peek_offset(parser, 5))) {
|
5678
6218
|
yp_token_type_t type = lex_embdoc(parser);
|
5679
6219
|
|
5680
6220
|
if (type == YP_TOKEN_EOF) {
|
@@ -5712,7 +6252,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5712
6252
|
!lex_state_end_p(parser) &&
|
5713
6253
|
(!lex_state_p(parser, YP_LEX_STATE_ARG_ANY) || lex_state_p(parser, YP_LEX_STATE_LABELED) || space_seen)
|
5714
6254
|
) {
|
5715
|
-
const
|
6255
|
+
const uint8_t *end = parser->current.end;
|
5716
6256
|
|
5717
6257
|
yp_heredoc_quote_t quote = YP_HEREDOC_QUOTE_NONE;
|
5718
6258
|
yp_heredoc_indent_t indent = YP_HEREDOC_INDENT_NONE;
|
@@ -5734,7 +6274,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5734
6274
|
quote = YP_HEREDOC_QUOTE_SINGLE;
|
5735
6275
|
}
|
5736
6276
|
|
5737
|
-
const
|
6277
|
+
const uint8_t *ident_start = parser->current.end;
|
5738
6278
|
size_t width = 0;
|
5739
6279
|
|
5740
6280
|
if (parser->current.end >= parser->end) {
|
@@ -5757,7 +6297,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5757
6297
|
}
|
5758
6298
|
|
5759
6299
|
size_t ident_length = (size_t) (parser->current.end - ident_start);
|
5760
|
-
if (quote != YP_HEREDOC_QUOTE_NONE && !match(parser, (
|
6300
|
+
if (quote != YP_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
|
5761
6301
|
// TODO: handle unterminated heredoc
|
5762
6302
|
}
|
5763
6303
|
|
@@ -5773,7 +6313,7 @@ parser_lex(yp_parser_t *parser) {
|
|
5773
6313
|
});
|
5774
6314
|
|
5775
6315
|
if (parser->heredoc_end == NULL) {
|
5776
|
-
const
|
6316
|
+
const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
|
5777
6317
|
|
5778
6318
|
if (body_start == NULL) {
|
5779
6319
|
// If there is no newline after the heredoc identifier, then
|
@@ -6098,13 +6638,13 @@ parser_lex(yp_parser_t *parser) {
|
|
6098
6638
|
LEX(YP_TOKEN_COLON_COLON);
|
6099
6639
|
}
|
6100
6640
|
|
6101
|
-
if (lex_state_end_p(parser) || yp_char_is_whitespace(
|
6641
|
+
if (lex_state_end_p(parser) || yp_char_is_whitespace(peek(parser)) || peek(parser) == '#') {
|
6102
6642
|
lex_state_set(parser, YP_LEX_STATE_BEG);
|
6103
6643
|
LEX(YP_TOKEN_COLON);
|
6104
6644
|
}
|
6105
6645
|
|
6106
|
-
if ((
|
6107
|
-
lex_mode_push_string(parser,
|
6646
|
+
if (peek(parser) == '"' || peek(parser) == '\'') {
|
6647
|
+
lex_mode_push_string(parser, peek(parser) == '"', false, '\0', *parser->current.end);
|
6108
6648
|
parser->current.end++;
|
6109
6649
|
}
|
6110
6650
|
|
@@ -6173,25 +6713,26 @@ parser_lex(yp_parser_t *parser) {
|
|
6173
6713
|
}
|
6174
6714
|
else if(
|
6175
6715
|
lex_state_beg_p(parser) ||
|
6176
|
-
(lex_state_p(parser, YP_LEX_STATE_FITEM) && (
|
6716
|
+
(lex_state_p(parser, YP_LEX_STATE_FITEM) && (peek(parser) == 's')) ||
|
6177
6717
|
lex_state_spcarg_p(parser, space_seen)
|
6178
6718
|
) {
|
6179
6719
|
if (!parser->encoding.alnum_char(parser->current.end, parser->end - parser->current.end)) {
|
6180
6720
|
lex_mode_push_string(parser, true, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6181
6721
|
|
6182
|
-
|
6722
|
+
size_t eol_length = match_eol(parser);
|
6723
|
+
if (eol_length) {
|
6724
|
+
parser->current.end += eol_length;
|
6725
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
6726
|
+
} else {
|
6183
6727
|
parser->current.end++;
|
6184
6728
|
}
|
6185
6729
|
|
6186
|
-
if (
|
6187
|
-
|
6730
|
+
if (parser->current.end < parser->end) {
|
6731
|
+
LEX(YP_TOKEN_STRING_BEGIN);
|
6188
6732
|
}
|
6189
|
-
|
6190
|
-
parser->current.end++;
|
6191
|
-
LEX(YP_TOKEN_STRING_BEGIN);
|
6192
6733
|
}
|
6193
6734
|
|
6194
|
-
switch (
|
6735
|
+
switch (peek(parser)) {
|
6195
6736
|
case 'i': {
|
6196
6737
|
parser->current.end++;
|
6197
6738
|
|
@@ -6215,6 +6756,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6215
6756
|
|
6216
6757
|
if (parser->current.end < parser->end) {
|
6217
6758
|
lex_mode_push_regexp(parser, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6759
|
+
yp_newline_list_check_append(&parser->newline_list, parser->current.end);
|
6218
6760
|
parser->current.end++;
|
6219
6761
|
}
|
6220
6762
|
|
@@ -6225,6 +6767,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6225
6767
|
|
6226
6768
|
if (parser->current.end < parser->end) {
|
6227
6769
|
lex_mode_push_string(parser, false, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6770
|
+
yp_newline_list_check_append(&parser->newline_list, parser->current.end);
|
6228
6771
|
parser->current.end++;
|
6229
6772
|
}
|
6230
6773
|
|
@@ -6235,6 +6778,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6235
6778
|
|
6236
6779
|
if (parser->current.end < parser->end) {
|
6237
6780
|
lex_mode_push_string(parser, true, false, lex_mode_incrementor(*parser->current.end), lex_mode_terminator(*parser->current.end));
|
6781
|
+
yp_newline_list_check_append(&parser->newline_list, parser->current.end);
|
6238
6782
|
parser->current.end++;
|
6239
6783
|
}
|
6240
6784
|
|
@@ -6284,7 +6828,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6284
6828
|
// unparseable. In this case we'll just drop it from the parser
|
6285
6829
|
// and skip past it and hope that the next token is something
|
6286
6830
|
// that we can parse.
|
6287
|
-
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "
|
6831
|
+
yp_diagnostic_list_append(&parser->error_list, parser->current.start, parser->current.end, "Invalid %% token");
|
6288
6832
|
goto lex_next_token;
|
6289
6833
|
}
|
6290
6834
|
}
|
@@ -6335,9 +6879,10 @@ parser_lex(yp_parser_t *parser) {
|
|
6335
6879
|
if (
|
6336
6880
|
((parser->current.end - parser->current.start) == 7) &&
|
6337
6881
|
current_token_starts_line(parser) &&
|
6338
|
-
(
|
6339
|
-
(parser->current.end == parser->end ||
|
6340
|
-
|
6882
|
+
(memcmp(parser->current.start, "__END__", 7) == 0) &&
|
6883
|
+
(parser->current.end == parser->end || match_eol(parser))
|
6884
|
+
)
|
6885
|
+
{
|
6341
6886
|
parser->current.end = parser->end;
|
6342
6887
|
parser->current.type = YP_TOKEN___END__;
|
6343
6888
|
parser_lex_callback(parser);
|
@@ -6394,7 +6939,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6394
6939
|
|
6395
6940
|
if ((whitespace = yp_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->newline_list, should_stop)) > 0) {
|
6396
6941
|
parser->current.end += whitespace;
|
6397
|
-
if (parser
|
6942
|
+
if (peek_offset(parser, -1) == '\n') {
|
6398
6943
|
// mutates next_start
|
6399
6944
|
parser_flush_heredoc_end(parser);
|
6400
6945
|
}
|
@@ -6410,8 +6955,8 @@ parser_lex(yp_parser_t *parser) {
|
|
6410
6955
|
// Here we'll get a list of the places where strpbrk should break,
|
6411
6956
|
// and then find the first one.
|
6412
6957
|
yp_lex_mode_t *lex_mode = parser->lex_modes.current;
|
6413
|
-
const
|
6414
|
-
const
|
6958
|
+
const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
|
6959
|
+
const uint8_t *breakpoint = yp_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
6415
6960
|
|
6416
6961
|
while (breakpoint != NULL) {
|
6417
6962
|
// If we hit a null byte, skip directly past it.
|
@@ -6458,12 +7003,25 @@ parser_lex(yp_parser_t *parser) {
|
|
6458
7003
|
// and find the next breakpoint.
|
6459
7004
|
if (*breakpoint == '\\') {
|
6460
7005
|
yp_unescape_type_t unescape_type = lex_mode->as.list.interpolation ? YP_UNESCAPE_ALL : YP_UNESCAPE_MINIMAL;
|
6461
|
-
size_t difference = yp_unescape_calculate_difference(
|
7006
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
7007
|
+
if (difference == 0) {
|
7008
|
+
// we're at the end of the file
|
7009
|
+
breakpoint = NULL;
|
7010
|
+
continue;
|
7011
|
+
}
|
6462
7012
|
|
6463
|
-
// If the result is an escaped newline
|
6464
|
-
// track that newline.
|
7013
|
+
// If the result is an escaped newline ...
|
6465
7014
|
if (breakpoint[difference - 1] == '\n') {
|
6466
|
-
|
7015
|
+
if (parser->heredoc_end) {
|
7016
|
+
// ... if we are on the same line as a heredoc, flush the heredoc and
|
7017
|
+
// continue parsing after heredoc_end.
|
7018
|
+
parser->current.end = breakpoint + difference;
|
7019
|
+
parser_flush_heredoc_end(parser);
|
7020
|
+
LEX(YP_TOKEN_STRING_CONTENT);
|
7021
|
+
} else {
|
7022
|
+
// ... else track the newline.
|
7023
|
+
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
7024
|
+
}
|
6467
7025
|
}
|
6468
7026
|
|
6469
7027
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
@@ -6499,7 +7057,13 @@ parser_lex(yp_parser_t *parser) {
|
|
6499
7057
|
|
6500
7058
|
case YP_LEX_REGEXP: {
|
6501
7059
|
// First, we'll set to start of this token to be the current end.
|
6502
|
-
parser->
|
7060
|
+
if (parser->next_start == NULL) {
|
7061
|
+
parser->current.start = parser->current.end;
|
7062
|
+
} else {
|
7063
|
+
parser->current.start = parser->next_start;
|
7064
|
+
parser->current.end = parser->next_start;
|
7065
|
+
parser->next_start = NULL;
|
7066
|
+
}
|
6503
7067
|
|
6504
7068
|
// We'll check if we're at the end of the file. If we are, then we need to
|
6505
7069
|
// return the EOF token.
|
@@ -6513,8 +7077,8 @@ parser_lex(yp_parser_t *parser) {
|
|
6513
7077
|
// These are the places where we need to split up the content of the
|
6514
7078
|
// regular expression. We'll use strpbrk to find the first of these
|
6515
7079
|
// characters.
|
6516
|
-
const
|
6517
|
-
const
|
7080
|
+
const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
|
7081
|
+
const uint8_t *breakpoint = yp_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
6518
7082
|
|
6519
7083
|
while (breakpoint != NULL) {
|
6520
7084
|
// If we hit a null byte, skip directly past it.
|
@@ -6526,7 +7090,16 @@ parser_lex(yp_parser_t *parser) {
|
|
6526
7090
|
// If we've hit a newline, then we need to track that in the
|
6527
7091
|
// list of newlines.
|
6528
7092
|
if (*breakpoint == '\n') {
|
6529
|
-
|
7093
|
+
// For the special case of a newline-terminated regular expression, we will pass
|
7094
|
+
// through this branch twice -- once with YP_TOKEN_REGEXP_BEGIN and then again
|
7095
|
+
// with YP_TOKEN_STRING_CONTENT. Let's avoid tracking the newline twice, by
|
7096
|
+
// tracking it only in the REGEXP_BEGIN case.
|
7097
|
+
if (
|
7098
|
+
!(lex_mode->as.regexp.terminator == '\n' && parser->current.type != YP_TOKEN_REGEXP_BEGIN)
|
7099
|
+
&& parser->heredoc_end == NULL
|
7100
|
+
) {
|
7101
|
+
yp_newline_list_append(&parser->newline_list, breakpoint);
|
7102
|
+
}
|
6530
7103
|
|
6531
7104
|
if (lex_mode->as.regexp.terminator != '\n') {
|
6532
7105
|
// If the terminator is not a newline, then we can set
|
@@ -6567,12 +7140,25 @@ parser_lex(yp_parser_t *parser) {
|
|
6567
7140
|
// literally. In this case we'll skip past the next character
|
6568
7141
|
// and find the next breakpoint.
|
6569
7142
|
if (*breakpoint == '\\') {
|
6570
|
-
size_t difference = yp_unescape_calculate_difference(
|
7143
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, YP_UNESCAPE_ALL, false);
|
7144
|
+
if (difference == 0) {
|
7145
|
+
// we're at the end of the file
|
7146
|
+
breakpoint = NULL;
|
7147
|
+
continue;
|
7148
|
+
}
|
6571
7149
|
|
6572
|
-
// If the result is an escaped newline
|
6573
|
-
// track that newline.
|
7150
|
+
// If the result is an escaped newline ...
|
6574
7151
|
if (breakpoint[difference - 1] == '\n') {
|
6575
|
-
|
7152
|
+
if (parser->heredoc_end) {
|
7153
|
+
// ... if we are on the same line as a heredoc, flush the heredoc and
|
7154
|
+
// continue parsing after heredoc_end.
|
7155
|
+
parser->current.end = breakpoint + difference;
|
7156
|
+
parser_flush_heredoc_end(parser);
|
7157
|
+
LEX(YP_TOKEN_STRING_CONTENT);
|
7158
|
+
} else {
|
7159
|
+
// ... else track the newline.
|
7160
|
+
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
7161
|
+
}
|
6576
7162
|
}
|
6577
7163
|
|
6578
7164
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
@@ -6624,8 +7210,8 @@ parser_lex(yp_parser_t *parser) {
|
|
6624
7210
|
|
6625
7211
|
// These are the places where we need to split up the content of the
|
6626
7212
|
// string. We'll use strpbrk to find the first of these characters.
|
6627
|
-
const
|
6628
|
-
const
|
7213
|
+
const uint8_t *breakpoints = parser->lex_modes.current->as.string.breakpoints;
|
7214
|
+
const uint8_t *breakpoint = yp_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
6629
7215
|
|
6630
7216
|
while (breakpoint != NULL) {
|
6631
7217
|
// If we hit the incrementor, then we'll increment then nesting and
|
@@ -6660,21 +7246,18 @@ parser_lex(yp_parser_t *parser) {
|
|
6660
7246
|
|
6661
7247
|
// Otherwise we need to switch back to the parent lex mode and
|
6662
7248
|
// return the end of the string.
|
6663
|
-
|
6664
|
-
|
6665
|
-
|
7249
|
+
size_t eol_length = match_eol_at(parser, breakpoint);
|
7250
|
+
if (eol_length) {
|
7251
|
+
parser->current.end = breakpoint + eol_length;
|
7252
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
6666
7253
|
} else {
|
6667
|
-
if (*parser->current.end == '\n') {
|
6668
|
-
yp_newline_list_append(&parser->newline_list, parser->current.end);
|
6669
|
-
}
|
6670
|
-
|
6671
7254
|
parser->current.end = breakpoint + 1;
|
6672
7255
|
}
|
6673
7256
|
|
6674
7257
|
if (
|
6675
7258
|
parser->lex_modes.current->as.string.label_allowed &&
|
6676
7259
|
(peek(parser) == ':') &&
|
6677
|
-
(
|
7260
|
+
(peek_offset(parser, 1) != ':')
|
6678
7261
|
) {
|
6679
7262
|
parser->current.end++;
|
6680
7263
|
lex_state_set(parser, YP_LEX_STATE_ARG | YP_LEX_STATE_LABELED);
|
@@ -6712,12 +7295,25 @@ parser_lex(yp_parser_t *parser) {
|
|
6712
7295
|
// literally. In this case we'll skip past the next character and
|
6713
7296
|
// find the next breakpoint.
|
6714
7297
|
yp_unescape_type_t unescape_type = parser->lex_modes.current->as.string.interpolation ? YP_UNESCAPE_ALL : YP_UNESCAPE_MINIMAL;
|
6715
|
-
size_t difference = yp_unescape_calculate_difference(
|
7298
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
7299
|
+
if (difference == 0) {
|
7300
|
+
// we're at the end of the file
|
7301
|
+
breakpoint = NULL;
|
7302
|
+
break;
|
7303
|
+
}
|
6716
7304
|
|
6717
|
-
// If the result is an escaped newline
|
6718
|
-
// track that newline.
|
7305
|
+
// If the result is an escaped newline ...
|
6719
7306
|
if (breakpoint[difference - 1] == '\n') {
|
6720
|
-
|
7307
|
+
if (parser->heredoc_end) {
|
7308
|
+
// ... if we are on the same line as a heredoc, flush the heredoc and
|
7309
|
+
// continue parsing after heredoc_end.
|
7310
|
+
parser->current.end = breakpoint + difference;
|
7311
|
+
parser_flush_heredoc_end(parser);
|
7312
|
+
LEX(YP_TOKEN_STRING_CONTENT);
|
7313
|
+
} else {
|
7314
|
+
// ... else track the newline.
|
7315
|
+
yp_newline_list_append(&parser->newline_list, breakpoint + difference - 1);
|
7316
|
+
}
|
6721
7317
|
}
|
6722
7318
|
|
6723
7319
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
@@ -6765,27 +7361,25 @@ parser_lex(yp_parser_t *parser) {
|
|
6765
7361
|
|
6766
7362
|
// Now let's grab the information about the identifier off of the current
|
6767
7363
|
// lex mode.
|
6768
|
-
const
|
7364
|
+
const uint8_t *ident_start = parser->lex_modes.current->as.heredoc.ident_start;
|
6769
7365
|
size_t ident_length = parser->lex_modes.current->as.heredoc.ident_length;
|
6770
7366
|
|
6771
7367
|
// If we are immediately following a newline and we have hit the
|
6772
7368
|
// terminator, then we need to return the ending of the heredoc.
|
6773
|
-
if (parser
|
6774
|
-
const
|
7369
|
+
if (current_token_starts_line(parser)) {
|
7370
|
+
const uint8_t *start = parser->current.start;
|
6775
7371
|
if (parser->lex_modes.current->as.heredoc.indent != YP_HEREDOC_INDENT_NONE) {
|
6776
7372
|
start += yp_strspn_inline_whitespace(start, parser->end - start);
|
6777
7373
|
}
|
6778
7374
|
|
6779
|
-
if ((start + ident_length <= parser->end) && (
|
7375
|
+
if ((start + ident_length <= parser->end) && (memcmp(start, ident_start, ident_length) == 0)) {
|
6780
7376
|
bool matched = true;
|
6781
7377
|
bool at_end = false;
|
6782
7378
|
|
6783
|
-
|
6784
|
-
|
6785
|
-
|
6786
|
-
|
6787
|
-
parser->current.end = start + ident_length + 2;
|
6788
|
-
yp_newline_list_append(&parser->newline_list, start + ident_length + 1);
|
7379
|
+
size_t eol_length = match_eol_at(parser, start + ident_length);
|
7380
|
+
if (eol_length) {
|
7381
|
+
parser->current.end = start + ident_length + eol_length;
|
7382
|
+
yp_newline_list_append(&parser->newline_list, parser->current.end - 1);
|
6789
7383
|
} else if (parser->end == (start + ident_length)) {
|
6790
7384
|
parser->current.end = start + ident_length;
|
6791
7385
|
at_end = true;
|
@@ -6813,14 +7407,14 @@ parser_lex(yp_parser_t *parser) {
|
|
6813
7407
|
// Otherwise we'll be parsing string content. These are the places where
|
6814
7408
|
// we need to split up the content of the heredoc. We'll use strpbrk to
|
6815
7409
|
// find the first of these characters.
|
6816
|
-
|
7410
|
+
uint8_t breakpoints[] = "\n\\#";
|
6817
7411
|
|
6818
7412
|
yp_heredoc_quote_t quote = parser->lex_modes.current->as.heredoc.quote;
|
6819
7413
|
if (quote == YP_HEREDOC_QUOTE_SINGLE) {
|
6820
7414
|
breakpoints[2] = '\0';
|
6821
7415
|
}
|
6822
7416
|
|
6823
|
-
const
|
7417
|
+
const uint8_t *breakpoint = yp_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end);
|
6824
7418
|
|
6825
7419
|
while (breakpoint != NULL) {
|
6826
7420
|
switch (*breakpoint) {
|
@@ -6837,7 +7431,7 @@ parser_lex(yp_parser_t *parser) {
|
|
6837
7431
|
|
6838
7432
|
yp_newline_list_append(&parser->newline_list, breakpoint);
|
6839
7433
|
|
6840
|
-
const
|
7434
|
+
const uint8_t *start = breakpoint + 1;
|
6841
7435
|
if (parser->lex_modes.current->as.heredoc.indent != YP_HEREDOC_INDENT_NONE) {
|
6842
7436
|
start += yp_strspn_inline_whitespace(start, parser->end - start);
|
6843
7437
|
}
|
@@ -6848,21 +7442,12 @@ parser_lex(yp_parser_t *parser) {
|
|
6848
7442
|
// again and return the end of the heredoc.
|
6849
7443
|
if (
|
6850
7444
|
(start + ident_length <= parser->end) &&
|
6851
|
-
(
|
7445
|
+
(memcmp(start, ident_start, ident_length) == 0)
|
6852
7446
|
) {
|
6853
|
-
// Heredoc terminators must be followed by a newline or EOF to be valid.
|
6854
|
-
if (start + ident_length == parser->end || start[ident_length] == '\n') {
|
6855
|
-
parser->current.end = breakpoint + 1;
|
6856
|
-
LEX(YP_TOKEN_STRING_CONTENT);
|
6857
|
-
}
|
6858
|
-
|
6859
|
-
// They can also be followed by a carriage return and then a
|
6860
|
-
// newline. Be sure here that we don't accidentally read off the
|
6861
|
-
// end.
|
7447
|
+
// Heredoc terminators must be followed by a newline, CRLF, or EOF to be valid.
|
6862
7448
|
if (
|
6863
|
-
|
6864
|
-
(start
|
6865
|
-
(start[ident_length + 1] == '\n')
|
7449
|
+
start + ident_length == parser->end ||
|
7450
|
+
match_eol_at(parser, start + ident_length)
|
6866
7451
|
) {
|
6867
7452
|
parser->current.end = breakpoint + 1;
|
6868
7453
|
LEX(YP_TOKEN_STRING_CONTENT);
|
@@ -6881,18 +7466,20 @@ parser_lex(yp_parser_t *parser) {
|
|
6881
7466
|
// stop looping before the newline and not after the
|
6882
7467
|
// newline so that we can still potentially find the
|
6883
7468
|
// terminator of the heredoc.
|
6884
|
-
|
6885
|
-
|
6886
|
-
|
6887
|
-
breakpoint += 2;
|
7469
|
+
size_t eol_length = match_eol_at(parser, breakpoint + 1);
|
7470
|
+
if (eol_length) {
|
7471
|
+
breakpoint += eol_length;
|
6888
7472
|
} else {
|
6889
7473
|
yp_unescape_type_t unescape_type = (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL;
|
6890
|
-
size_t difference = yp_unescape_calculate_difference(
|
6891
|
-
|
6892
|
-
|
6893
|
-
|
7474
|
+
size_t difference = yp_unescape_calculate_difference(parser, breakpoint, unescape_type, false);
|
7475
|
+
if (difference == 0) {
|
7476
|
+
// we're at the end of the file
|
7477
|
+
breakpoint = NULL;
|
7478
|
+
break;
|
6894
7479
|
}
|
6895
7480
|
|
7481
|
+
yp_newline_list_check_append(&parser->newline_list, breakpoint + difference - 1);
|
7482
|
+
|
6896
7483
|
breakpoint = yp_strpbrk(parser, breakpoint + difference, breakpoints, parser->end - (breakpoint + difference));
|
6897
7484
|
}
|
6898
7485
|
|
@@ -6945,7 +7532,7 @@ yp_regular_expression_node_create_and_unescape(yp_parser_t *parser, const yp_tok
|
|
6945
7532
|
assert((content->end - content->start) >= 0);
|
6946
7533
|
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
6947
7534
|
|
6948
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type
|
7535
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
6949
7536
|
return node;
|
6950
7537
|
}
|
6951
7538
|
|
@@ -6956,7 +7543,18 @@ yp_symbol_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *openin
|
|
6956
7543
|
assert((content->end - content->start) >= 0);
|
6957
7544
|
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
6958
7545
|
|
6959
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type
|
7546
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
7547
|
+
return node;
|
7548
|
+
}
|
7549
|
+
|
7550
|
+
static yp_string_node_t *
|
7551
|
+
yp_char_literal_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *opening, const yp_token_t *content, const yp_token_t *closing, yp_unescape_type_t unescape_type) {
|
7552
|
+
yp_string_node_t *node = yp_string_node_create(parser, opening, content, closing);
|
7553
|
+
|
7554
|
+
assert((content->end - content->start) >= 0);
|
7555
|
+
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
7556
|
+
|
7557
|
+
yp_unescape_manipulate_char_literal(parser, &node->unescaped, unescape_type);
|
6960
7558
|
return node;
|
6961
7559
|
}
|
6962
7560
|
|
@@ -6967,7 +7565,7 @@ yp_string_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *openin
|
|
6967
7565
|
assert((content->end - content->start) >= 0);
|
6968
7566
|
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
6969
7567
|
|
6970
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type
|
7568
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, unescape_type);
|
6971
7569
|
return node;
|
6972
7570
|
}
|
6973
7571
|
|
@@ -6978,7 +7576,7 @@ yp_xstring_node_create_and_unescape(yp_parser_t *parser, const yp_token_t *openi
|
|
6978
7576
|
assert((content->end - content->start) >= 0);
|
6979
7577
|
yp_string_shared_init(&node->unescaped, content->start, content->end);
|
6980
7578
|
|
6981
|
-
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL
|
7579
|
+
yp_unescape_manipulate_string(parser, &node->unescaped, YP_UNESCAPE_ALL);
|
6982
7580
|
return node;
|
6983
7581
|
}
|
6984
7582
|
|
@@ -7315,27 +7913,162 @@ token_begins_expression_p(yp_token_type_t type) {
|
|
7315
7913
|
}
|
7316
7914
|
}
|
7317
7915
|
|
7318
|
-
// Parse an expression with the given binding power that may be optionally
|
7319
|
-
// prefixed by the * operator.
|
7320
|
-
static yp_node_t *
|
7321
|
-
parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message) {
|
7322
|
-
if (accept(parser, YP_TOKEN_USTAR)) {
|
7323
|
-
yp_token_t operator = parser->previous;
|
7324
|
-
yp_node_t *expression = parse_expression(parser, binding_power, "Expected expression after `*'.");
|
7325
|
-
return (yp_node_t *) yp_splat_node_create(parser, &operator, expression);
|
7326
|
-
}
|
7916
|
+
// Parse an expression with the given binding power that may be optionally
|
7917
|
+
// prefixed by the * operator.
|
7918
|
+
static yp_node_t *
|
7919
|
+
parse_starred_expression(yp_parser_t *parser, yp_binding_power_t binding_power, const char *message) {
|
7920
|
+
if (accept(parser, YP_TOKEN_USTAR)) {
|
7921
|
+
yp_token_t operator = parser->previous;
|
7922
|
+
yp_node_t *expression = parse_expression(parser, binding_power, "Expected expression after `*'.");
|
7923
|
+
return (yp_node_t *) yp_splat_node_create(parser, &operator, expression);
|
7924
|
+
}
|
7925
|
+
|
7926
|
+
return parse_expression(parser, binding_power, message);
|
7927
|
+
}
|
7928
|
+
|
7929
|
+
// Convert the given node into a valid target node.
|
7930
|
+
static yp_node_t *
|
7931
|
+
parse_target(yp_parser_t *parser, yp_node_t *target) {
|
7932
|
+
switch (YP_NODE_TYPE(target)) {
|
7933
|
+
case YP_NODE_MISSING_NODE:
|
7934
|
+
return target;
|
7935
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE:
|
7936
|
+
assert(sizeof(yp_class_variable_target_node_t) == sizeof(yp_class_variable_read_node_t));
|
7937
|
+
target->type = YP_NODE_CLASS_VARIABLE_TARGET_NODE;
|
7938
|
+
return target;
|
7939
|
+
case YP_NODE_CONSTANT_PATH_NODE:
|
7940
|
+
assert(sizeof(yp_constant_path_target_node_t) == sizeof(yp_constant_path_node_t));
|
7941
|
+
target->type = YP_NODE_CONSTANT_PATH_TARGET_NODE;
|
7942
|
+
return target;
|
7943
|
+
case YP_NODE_CONSTANT_READ_NODE:
|
7944
|
+
assert(sizeof(yp_constant_target_node_t) == sizeof(yp_constant_read_node_t));
|
7945
|
+
target->type = YP_NODE_CONSTANT_TARGET_NODE;
|
7946
|
+
return target;
|
7947
|
+
case YP_NODE_BACK_REFERENCE_READ_NODE:
|
7948
|
+
assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_back_reference_read_node_t));
|
7949
|
+
/* fallthrough */
|
7950
|
+
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
7951
|
+
assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_numbered_reference_read_node_t));
|
7952
|
+
yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Can't set variable");
|
7953
|
+
/* fallthrough */
|
7954
|
+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE:
|
7955
|
+
assert(sizeof(yp_global_variable_target_node_t) == sizeof(yp_global_variable_read_node_t));
|
7956
|
+
target->type = YP_NODE_GLOBAL_VARIABLE_TARGET_NODE;
|
7957
|
+
return target;
|
7958
|
+
case YP_NODE_LOCAL_VARIABLE_READ_NODE:
|
7959
|
+
assert(sizeof(yp_local_variable_target_node_t) == sizeof(yp_local_variable_read_node_t));
|
7960
|
+
target->type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE;
|
7961
|
+
return target;
|
7962
|
+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE:
|
7963
|
+
assert(sizeof(yp_instance_variable_target_node_t) == sizeof(yp_instance_variable_read_node_t));
|
7964
|
+
target->type = YP_NODE_INSTANCE_VARIABLE_TARGET_NODE;
|
7965
|
+
return target;
|
7966
|
+
case YP_NODE_MULTI_WRITE_NODE:
|
7967
|
+
return target;
|
7968
|
+
case YP_NODE_SPLAT_NODE: {
|
7969
|
+
yp_splat_node_t *splat = (yp_splat_node_t *) target;
|
7970
|
+
|
7971
|
+
if (splat->expression != NULL) {
|
7972
|
+
splat->expression = parse_target(parser, splat->expression);
|
7973
|
+
}
|
7974
|
+
|
7975
|
+
yp_token_t operator = not_provided(parser);
|
7976
|
+
yp_location_t location = { .start = NULL, .end = NULL };
|
7977
|
+
|
7978
|
+
yp_multi_write_node_t *multi_write = yp_multi_write_node_create(parser, &operator, NULL, &location, &location);
|
7979
|
+
yp_multi_write_node_targets_append(multi_write, (yp_node_t *) splat);
|
7980
|
+
|
7981
|
+
return (yp_node_t *) multi_write;
|
7982
|
+
}
|
7983
|
+
case YP_NODE_CALL_NODE: {
|
7984
|
+
yp_call_node_t *call = (yp_call_node_t *) target;
|
7985
|
+
|
7986
|
+
// If we have no arguments to the call node and we need this to be a
|
7987
|
+
// target then this is either a method call or a local variable write.
|
7988
|
+
if (
|
7989
|
+
(call->opening_loc.start == NULL) &&
|
7990
|
+
(call->arguments == NULL) &&
|
7991
|
+
(call->block == NULL)
|
7992
|
+
) {
|
7993
|
+
if (call->receiver == NULL) {
|
7994
|
+
// When we get here, we have a local variable write, because it
|
7995
|
+
// was previously marked as a method call but now we have an =.
|
7996
|
+
// This looks like:
|
7997
|
+
//
|
7998
|
+
// foo = 1
|
7999
|
+
//
|
8000
|
+
// When it was parsed in the prefix position, foo was seen as a
|
8001
|
+
// method call with no receiver and no arguments. Now we have an
|
8002
|
+
// =, so we know it's a local variable write.
|
8003
|
+
const yp_location_t message = call->message_loc;
|
8004
|
+
|
8005
|
+
yp_parser_local_add_location(parser, message.start, message.end);
|
8006
|
+
yp_node_destroy(parser, target);
|
7327
8007
|
|
7328
|
-
|
8008
|
+
const yp_token_t name = { .type = YP_TOKEN_IDENTIFIER, .start = message.start, .end = message.end };
|
8009
|
+
target = (yp_node_t *) yp_local_variable_read_node_create(parser, &name, 0);
|
8010
|
+
|
8011
|
+
assert(sizeof(yp_local_variable_target_node_t) == sizeof(yp_local_variable_read_node_t));
|
8012
|
+
target->type = YP_NODE_LOCAL_VARIABLE_TARGET_NODE;
|
8013
|
+
|
8014
|
+
if (token_is_numbered_parameter(message.start, message.end)) {
|
8015
|
+
yp_diagnostic_list_append(&parser->error_list, message.start, message.end, "reserved for numbered parameter");
|
8016
|
+
}
|
8017
|
+
|
8018
|
+
return target;
|
8019
|
+
}
|
8020
|
+
|
8021
|
+
// The method name needs to change. If we previously had foo, we now
|
8022
|
+
// need foo=. In this case we'll allocate a new owned string, copy
|
8023
|
+
// the previous method name in, and append an =.
|
8024
|
+
size_t length = yp_string_length(&call->name);
|
8025
|
+
|
8026
|
+
uint8_t *name = calloc(length + 1, sizeof(uint8_t));
|
8027
|
+
if (name == NULL) return NULL;
|
8028
|
+
|
8029
|
+
memcpy(name, yp_string_source(&call->name), length);
|
8030
|
+
name[length] = '=';
|
8031
|
+
|
8032
|
+
// Now switch the name to the new string.
|
8033
|
+
yp_string_free(&call->name);
|
8034
|
+
yp_string_owned_init(&call->name, name, length + 1);
|
8035
|
+
|
8036
|
+
return target;
|
8037
|
+
}
|
8038
|
+
|
8039
|
+
// If there is no call operator and the message is "[]" then this is
|
8040
|
+
// an aref expression, and we can transform it into an aset
|
8041
|
+
// expression.
|
8042
|
+
if (
|
8043
|
+
(call->operator_loc.start == NULL) &&
|
8044
|
+
(call->message_loc.start[0] == '[') &&
|
8045
|
+
(call->message_loc.end[-1] == ']') &&
|
8046
|
+
(call->block == NULL)
|
8047
|
+
) {
|
8048
|
+
// Free the previous name and replace it with "[]=".
|
8049
|
+
yp_string_free(&call->name);
|
8050
|
+
yp_string_constant_init(&call->name, "[]=", 3);
|
8051
|
+
return target;
|
8052
|
+
}
|
8053
|
+
}
|
8054
|
+
/* fallthrough */
|
8055
|
+
default:
|
8056
|
+
// In this case we have a node that we don't know how to convert
|
8057
|
+
// into a target. We need to treat it as an error. For now, we'll
|
8058
|
+
// mark it as an error and just skip right past it.
|
8059
|
+
yp_diagnostic_list_append(&parser->error_list, target->location.start, target->location.end, "Unexpected write target.");
|
8060
|
+
return target;
|
8061
|
+
}
|
7329
8062
|
}
|
7330
8063
|
|
7331
|
-
// Convert the given node into a valid
|
8064
|
+
// Convert the given node into a valid write node.
|
7332
8065
|
static yp_node_t *
|
7333
|
-
|
8066
|
+
parse_write(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_node_t *value) {
|
7334
8067
|
switch (YP_NODE_TYPE(target)) {
|
7335
8068
|
case YP_NODE_MISSING_NODE:
|
7336
8069
|
return target;
|
7337
8070
|
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
7338
|
-
yp_class_variable_write_node_t *write_node =
|
8071
|
+
yp_class_variable_write_node_t *write_node = yp_class_variable_write_node_create(parser, (yp_class_variable_read_node_t *) target, operator, value);
|
7339
8072
|
yp_node_destroy(parser, target);
|
7340
8073
|
return (yp_node_t *) write_node;
|
7341
8074
|
}
|
@@ -7360,7 +8093,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7360
8093
|
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
7361
8094
|
yp_local_variable_read_node_t *local_read = (yp_local_variable_read_node_t *) target;
|
7362
8095
|
|
7363
|
-
yp_constant_id_t constant_id = local_read->
|
8096
|
+
yp_constant_id_t constant_id = local_read->name;
|
7364
8097
|
uint32_t depth = local_read->depth;
|
7365
8098
|
|
7366
8099
|
yp_location_t name_loc = target->location;
|
@@ -7377,18 +8110,15 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7377
8110
|
yp_multi_write_node_t *multi_write = (yp_multi_write_node_t *) target;
|
7378
8111
|
yp_multi_write_node_operator_loc_set(multi_write, operator);
|
7379
8112
|
|
7380
|
-
|
7381
|
-
|
7382
|
-
multi_write->base.location.end = value->location.end;
|
7383
|
-
}
|
7384
|
-
|
8113
|
+
multi_write->value = value;
|
8114
|
+
multi_write->base.location.end = value->location.end;
|
7385
8115
|
return (yp_node_t *) multi_write;
|
7386
8116
|
}
|
7387
8117
|
case YP_NODE_SPLAT_NODE: {
|
7388
8118
|
yp_splat_node_t *splat = (yp_splat_node_t *) target;
|
7389
8119
|
|
7390
8120
|
if (splat->expression != NULL) {
|
7391
|
-
splat->expression =
|
8121
|
+
splat->expression = parse_write(parser, splat->expression, operator, value);
|
7392
8122
|
}
|
7393
8123
|
|
7394
8124
|
yp_location_t location = { .start = NULL, .end = NULL };
|
@@ -7441,22 +8171,21 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7441
8171
|
// method call with no arguments. Now we have an =, so we know it's
|
7442
8172
|
// a method call with an argument. In this case we will create the
|
7443
8173
|
// arguments node, parse the argument, and add it to the list.
|
7444
|
-
|
7445
|
-
|
7446
|
-
|
7447
|
-
|
7448
|
-
target->location.end = arguments->base.location.end;
|
7449
|
-
}
|
8174
|
+
yp_arguments_node_t *arguments = yp_arguments_node_create(parser);
|
8175
|
+
call->arguments = arguments;
|
8176
|
+
yp_arguments_node_arguments_append(arguments, value);
|
8177
|
+
target->location.end = arguments->base.location.end;
|
7450
8178
|
|
7451
8179
|
// The method name needs to change. If we previously had foo, we now
|
7452
8180
|
// need foo=. In this case we'll allocate a new owned string, copy
|
7453
8181
|
// the previous method name in, and append an =.
|
7454
8182
|
size_t length = yp_string_length(&call->name);
|
7455
8183
|
|
7456
|
-
|
8184
|
+
uint8_t *name = calloc(length + 1, sizeof(uint8_t));
|
7457
8185
|
if (name == NULL) return NULL;
|
7458
8186
|
|
7459
|
-
|
8187
|
+
memcpy(name, yp_string_source(&call->name), length);
|
8188
|
+
name[length] = '=';
|
7460
8189
|
|
7461
8190
|
// Now switch the name to the new string.
|
7462
8191
|
yp_string_free(&call->name);
|
@@ -7474,15 +8203,13 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7474
8203
|
(call->message_loc.end[-1] == ']') &&
|
7475
8204
|
(call->block == NULL)
|
7476
8205
|
) {
|
7477
|
-
if (
|
7478
|
-
|
7479
|
-
call->arguments = yp_arguments_node_create(parser);
|
7480
|
-
}
|
7481
|
-
|
7482
|
-
yp_arguments_node_arguments_append(call->arguments, value);
|
7483
|
-
target->location.end = value->location.end;
|
8206
|
+
if (call->arguments == NULL) {
|
8207
|
+
call->arguments = yp_arguments_node_create(parser);
|
7484
8208
|
}
|
7485
8209
|
|
8210
|
+
yp_arguments_node_arguments_append(call->arguments, value);
|
8211
|
+
target->location.end = value->location.end;
|
8212
|
+
|
7486
8213
|
// Free the previous name and replace it with "[]=".
|
7487
8214
|
yp_string_free(&call->name);
|
7488
8215
|
yp_string_constant_init(&call->name, "[]=", 3);
|
@@ -7494,9 +8221,7 @@ parse_target(yp_parser_t *parser, yp_node_t *target, yp_token_t *operator, yp_no
|
|
7494
8221
|
// syntax error. In this case we'll fall through to our default
|
7495
8222
|
// handling. We need to free the value that we parsed because there
|
7496
8223
|
// is no way for us to attach it to the tree at this point.
|
7497
|
-
|
7498
|
-
yp_node_destroy(parser, value);
|
7499
|
-
}
|
8224
|
+
yp_node_destroy(parser, value);
|
7500
8225
|
}
|
7501
8226
|
/* fallthrough */
|
7502
8227
|
default:
|
@@ -7524,7 +8249,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7524
8249
|
// location that we know requires a multi write, as in the case of a for loop.
|
7525
8250
|
// In this case we will set up the parsing loop slightly differently.
|
7526
8251
|
if (first_target != NULL) {
|
7527
|
-
first_target = parse_target(parser, first_target
|
8252
|
+
first_target = parse_target(parser, first_target);
|
7528
8253
|
|
7529
8254
|
if (!match_type_p(parser, YP_TOKEN_COMMA)) {
|
7530
8255
|
return first_target;
|
@@ -7555,9 +8280,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7555
8280
|
yp_node_t *name = NULL;
|
7556
8281
|
|
7557
8282
|
if (token_begins_expression_p(parser->current.type)) {
|
7558
|
-
yp_token_t operator = not_provided(parser);
|
7559
8283
|
name = parse_expression(parser, binding_power, "Expected an expression after '*'.");
|
7560
|
-
name = parse_target(parser, name
|
8284
|
+
name = parse_target(parser, name);
|
7561
8285
|
}
|
7562
8286
|
|
7563
8287
|
yp_node_t *splat = (yp_node_t *) yp_splat_node_create(parser, &star_operator, name);
|
@@ -7587,6 +8311,8 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7587
8311
|
|
7588
8312
|
if (YP_NODE_TYPE_P(child_target, YP_NODE_MULTI_WRITE_NODE)) {
|
7589
8313
|
target = (yp_multi_write_node_t *) child_target;
|
8314
|
+
target->base.location.start = lparen.start;
|
8315
|
+
target->base.location.end = rparen.end;
|
7590
8316
|
target->lparen_loc = (yp_location_t) { .start = lparen.start, .end = lparen.end };
|
7591
8317
|
target->rparen_loc = (yp_location_t) { .start = rparen.start, .end = rparen.end };
|
7592
8318
|
} else {
|
@@ -7603,6 +8329,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7603
8329
|
yp_multi_write_node_targets_append(target, child_target);
|
7604
8330
|
}
|
7605
8331
|
|
8332
|
+
target->base.location.start = lparen.start;
|
7606
8333
|
target->base.location.end = rparen.end;
|
7607
8334
|
yp_multi_write_node_targets_append(result, (yp_node_t *) target);
|
7608
8335
|
}
|
@@ -7625,7 +8352,7 @@ parse_targets(yp_parser_t *parser, yp_node_t *first_target, yp_binding_power_t b
|
|
7625
8352
|
}
|
7626
8353
|
|
7627
8354
|
yp_node_t *target = parse_expression(parser, binding_power, "Expected another expression after ','.");
|
7628
|
-
target = parse_target(parser, target
|
8355
|
+
target = parse_target(parser, target);
|
7629
8356
|
|
7630
8357
|
yp_multi_write_node_targets_append(result, target);
|
7631
8358
|
}
|
@@ -8085,7 +8812,6 @@ parse_parameters(
|
|
8085
8812
|
bool looping = true;
|
8086
8813
|
|
8087
8814
|
yp_do_loop_stack_push(parser, false);
|
8088
|
-
|
8089
8815
|
yp_parameters_order_t order = YP_PARAMETERS_ORDER_NONE;
|
8090
8816
|
|
8091
8817
|
do {
|
@@ -8377,8 +9103,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8377
9103
|
yp_rescue_node_operator_set(rescue, &parser->previous);
|
8378
9104
|
|
8379
9105
|
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
8380
|
-
|
8381
|
-
reference = parse_target(parser, reference, &operator, NULL);
|
9106
|
+
reference = parse_target(parser, reference);
|
8382
9107
|
|
8383
9108
|
yp_rescue_node_reference_set(rescue, reference);
|
8384
9109
|
break;
|
@@ -8408,8 +9133,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8408
9133
|
yp_rescue_node_operator_set(rescue, &parser->previous);
|
8409
9134
|
|
8410
9135
|
yp_node_t *reference = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected an exception variable after `=>` in rescue statement.");
|
8411
|
-
|
8412
|
-
reference = parse_target(parser, reference, &operator, NULL);
|
9136
|
+
reference = parse_target(parser, reference);
|
8413
9137
|
|
8414
9138
|
yp_rescue_node_reference_set(rescue, reference);
|
8415
9139
|
break;
|
@@ -8426,10 +9150,12 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8426
9150
|
}
|
8427
9151
|
|
8428
9152
|
if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) {
|
9153
|
+
yp_accepts_block_stack_push(parser, true);
|
8429
9154
|
yp_statements_node_t *statements = parse_statements(parser, YP_CONTEXT_RESCUE);
|
8430
9155
|
if (statements) {
|
8431
9156
|
yp_rescue_node_statements_set(rescue, statements);
|
8432
9157
|
}
|
9158
|
+
yp_accepts_block_stack_pop(parser);
|
8433
9159
|
accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON);
|
8434
9160
|
}
|
8435
9161
|
|
@@ -8446,7 +9172,7 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8446
9172
|
// since we won't know the end until we've found all consequent
|
8447
9173
|
// clauses. This sets the end location on all rescues once we know it
|
8448
9174
|
if (current) {
|
8449
|
-
const
|
9175
|
+
const uint8_t *end_to_set = current->base.location.end;
|
8450
9176
|
current = parent_node->rescue_clause;
|
8451
9177
|
while (current) {
|
8452
9178
|
current->base.location.end = end_to_set;
|
@@ -8460,7 +9186,9 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8460
9186
|
|
8461
9187
|
yp_statements_node_t *else_statements = NULL;
|
8462
9188
|
if (!match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_ENSURE)) {
|
9189
|
+
yp_accepts_block_stack_push(parser, true);
|
8463
9190
|
else_statements = parse_statements(parser, YP_CONTEXT_RESCUE_ELSE);
|
9191
|
+
yp_accepts_block_stack_pop(parser);
|
8464
9192
|
accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON);
|
8465
9193
|
}
|
8466
9194
|
|
@@ -8474,7 +9202,9 @@ parse_rescues(yp_parser_t *parser, yp_begin_node_t *parent_node) {
|
|
8474
9202
|
|
8475
9203
|
yp_statements_node_t *ensure_statements = NULL;
|
8476
9204
|
if (!match_type_p(parser, YP_TOKEN_KEYWORD_END)) {
|
9205
|
+
yp_accepts_block_stack_push(parser, true);
|
8477
9206
|
ensure_statements = parse_statements(parser, YP_CONTEXT_ENSURE);
|
9207
|
+
yp_accepts_block_stack_pop(parser);
|
8478
9208
|
accept_any(parser, 2, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON);
|
8479
9209
|
}
|
8480
9210
|
|
@@ -8499,7 +9229,7 @@ parse_rescues_as_begin(yp_parser_t *parser, yp_statements_node_t *statements) {
|
|
8499
9229
|
// All nodes within a begin node are optional, so we look
|
8500
9230
|
// for the earliest possible node that we can use to set
|
8501
9231
|
// the BeginNode's start location
|
8502
|
-
const
|
9232
|
+
const uint8_t *start = begin_node->base.location.start;
|
8503
9233
|
if (begin_node->statements) {
|
8504
9234
|
start = begin_node->statements->base.location.start;
|
8505
9235
|
} else if (begin_node->rescue_clause) {
|
@@ -8584,7 +9314,9 @@ parse_block(yp_parser_t *parser) {
|
|
8584
9314
|
} else {
|
8585
9315
|
if (!match_type_p(parser, YP_TOKEN_KEYWORD_END)) {
|
8586
9316
|
if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ELSE, YP_TOKEN_KEYWORD_ENSURE)) {
|
9317
|
+
yp_accepts_block_stack_push(parser, true);
|
8587
9318
|
statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_BLOCK_KEYWORDS);
|
9319
|
+
yp_accepts_block_stack_pop(parser);
|
8588
9320
|
}
|
8589
9321
|
|
8590
9322
|
if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) {
|
@@ -8961,14 +9693,10 @@ parse_string_part(yp_parser_t *parser) {
|
|
8961
9693
|
|
8962
9694
|
static yp_node_t *
|
8963
9695
|
parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_state) {
|
8964
|
-
bool lex_string = lex_mode->mode == YP_LEX_STRING;
|
8965
|
-
bool can_be_interpolated = lex_string && lex_mode->as.string.interpolation;
|
8966
9696
|
yp_token_t opening = parser->previous;
|
8967
9697
|
|
8968
|
-
if (
|
8969
|
-
if (next_state != YP_LEX_STATE_NONE)
|
8970
|
-
lex_state_set(parser, next_state);
|
8971
|
-
}
|
9698
|
+
if (lex_mode->mode != YP_LEX_STRING) {
|
9699
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
8972
9700
|
yp_token_t symbol;
|
8973
9701
|
|
8974
9702
|
switch (parser->current.type) {
|
@@ -8998,37 +9726,44 @@ parse_symbol(yp_parser_t *parser, yp_lex_mode_t *lex_mode, yp_lex_state_t next_s
|
|
8998
9726
|
return (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &symbol, &closing, YP_UNESCAPE_ALL);
|
8999
9727
|
}
|
9000
9728
|
|
9001
|
-
if (
|
9002
|
-
//
|
9003
|
-
|
9729
|
+
if (lex_mode->as.string.interpolation) {
|
9730
|
+
// If we have the end of the symbol, then we can return an empty symbol.
|
9731
|
+
if (match_type_p(parser, YP_TOKEN_STRING_END)) {
|
9732
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
9733
|
+
parser_lex(parser);
|
9734
|
+
|
9735
|
+
yp_token_t content = not_provided(parser);
|
9736
|
+
yp_token_t closing = parser->previous;
|
9737
|
+
return (yp_node_t *) yp_symbol_node_create_and_unescape(parser, &opening, &content, &closing, YP_UNESCAPE_NONE);
|
9738
|
+
}
|
9739
|
+
|
9740
|
+
// Now we can parse the first part of the symbol.
|
9741
|
+
yp_node_t *part = parse_string_part(parser);
|
9742
|
+
|
9743
|
+
// If we got a string part, then it's possible that we could transform
|
9744
|
+
// what looks like an interpolated symbol into a regular symbol.
|
9745
|
+
if (part && YP_NODE_TYPE_P(part, YP_NODE_STRING_NODE) && match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) {
|
9746
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
9747
|
+
parser_lex(parser);
|
9748
|
+
|
9749
|
+
return (yp_node_t *) yp_string_node_to_symbol_node(parser, (yp_string_node_t *) part, &opening, &parser->previous);
|
9750
|
+
}
|
9751
|
+
|
9752
|
+
// Create a node_list first. We'll use this to check if it should be an
|
9753
|
+
// InterpolatedSymbolNode or a SymbolNode.
|
9004
9754
|
yp_node_list_t node_list = YP_EMPTY_NODE_LIST;
|
9755
|
+
if (part) yp_node_list_append(&node_list, part);
|
9005
9756
|
|
9006
9757
|
while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) {
|
9007
|
-
|
9008
|
-
if (part != NULL) {
|
9758
|
+
if ((part = parse_string_part(parser)) != NULL) {
|
9009
9759
|
yp_node_list_append(&node_list, part);
|
9010
9760
|
}
|
9011
9761
|
}
|
9012
9762
|
|
9013
|
-
|
9014
|
-
// If the only element on the node_list is a StringNode, we know this is a SymbolNode
|
9015
|
-
// and not an InterpolatedSymbolNode
|
9016
|
-
if (node_list.size == 1 && YP_NODE_TYPE_P(node_list.nodes[0], YP_NODE_STRING_NODE)) {
|
9017
|
-
res = (yp_node_t *)yp_string_node_to_symbol_node(parser, (yp_string_node_t *)node_list.nodes[0]);
|
9018
|
-
free(node_list.nodes);
|
9019
|
-
}
|
9020
|
-
else {
|
9021
|
-
yp_interpolated_symbol_node_t *interpolated = yp_interpolated_symbol_node_create(parser, &opening, &node_list, &opening);
|
9022
|
-
yp_interpolated_symbol_node_closing_set(interpolated, &parser->current);
|
9023
|
-
res = (yp_node_t *) interpolated;
|
9024
|
-
}
|
9025
|
-
|
9026
|
-
if (next_state != YP_LEX_STATE_NONE) {
|
9027
|
-
lex_state_set(parser, next_state);
|
9028
|
-
}
|
9763
|
+
if (next_state != YP_LEX_STATE_NONE) lex_state_set(parser, next_state);
|
9029
9764
|
expect(parser, YP_TOKEN_STRING_END, "Expected a closing delimiter for an interpolated symbol.");
|
9030
9765
|
|
9031
|
-
return
|
9766
|
+
return (yp_node_t *) yp_interpolated_symbol_node_create(parser, &opening, &node_list, &parser->previous);
|
9032
9767
|
}
|
9033
9768
|
|
9034
9769
|
yp_token_t content;
|
@@ -9162,19 +9897,22 @@ parse_heredoc_common_whitespace(yp_parser_t *parser, yp_node_list_t *nodes) {
|
|
9162
9897
|
yp_node_t *node = nodes->nodes[index];
|
9163
9898
|
|
9164
9899
|
if (!YP_NODE_TYPE_P(node, YP_NODE_STRING_NODE)) continue;
|
9165
|
-
yp_location_t *content_loc = &((yp_string_node_t *) node)->content_loc;
|
9900
|
+
const yp_location_t *content_loc = &((yp_string_node_t *) node)->content_loc;
|
9166
9901
|
|
9167
9902
|
// If the previous node wasn't a string node, we don't want to trim
|
9168
9903
|
// whitespace. This could happen after an interpolated expression or
|
9169
9904
|
// variable.
|
9170
9905
|
if (index == 0 || YP_NODE_TYPE_P(nodes->nodes[index - 1], YP_NODE_STRING_NODE)) {
|
9171
9906
|
int cur_whitespace;
|
9172
|
-
const
|
9907
|
+
const uint8_t *cur_char = content_loc->start;
|
9173
9908
|
|
9174
9909
|
while (cur_char && cur_char < content_loc->end) {
|
9175
|
-
// Any empty newlines aren't included in the minimum whitespace
|
9176
|
-
|
9177
|
-
|
9910
|
+
// Any empty newlines aren't included in the minimum whitespace
|
9911
|
+
// calculation.
|
9912
|
+
size_t eol_length;
|
9913
|
+
while ((eol_length = match_eol_at(parser, cur_char))) {
|
9914
|
+
cur_char += eol_length;
|
9915
|
+
}
|
9178
9916
|
|
9179
9917
|
if (cur_char == content_loc->end) break;
|
9180
9918
|
|
@@ -9189,11 +9927,12 @@ parse_heredoc_common_whitespace(yp_parser_t *parser, yp_node_list_t *nodes) {
|
|
9189
9927
|
cur_char++;
|
9190
9928
|
}
|
9191
9929
|
|
9192
|
-
// If we hit a newline, then we have encountered a line that
|
9193
|
-
// only whitespace, and it shouldn't be considered in
|
9194
|
-
// common leading whitespace.
|
9195
|
-
|
9196
|
-
|
9930
|
+
// If we hit a newline, then we have encountered a line that
|
9931
|
+
// contains only whitespace, and it shouldn't be considered in
|
9932
|
+
// the calculation of common leading whitespace.
|
9933
|
+
eol_length = match_eol_at(parser, cur_char);
|
9934
|
+
if (eol_length) {
|
9935
|
+
cur_char += eol_length;
|
9197
9936
|
continue;
|
9198
9937
|
}
|
9199
9938
|
|
@@ -9256,15 +9995,15 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
|
|
9256
9995
|
// destination to move bytes into. We'll also use it for bounds checking
|
9257
9996
|
// since we don't require that these strings be null terminated.
|
9258
9997
|
size_t dest_length = yp_string_length(string);
|
9259
|
-
|
9998
|
+
uint8_t *source_start = (uint8_t *) string->source;
|
9260
9999
|
|
9261
|
-
const
|
9262
|
-
const
|
10000
|
+
const uint8_t *source_cursor = source_start;
|
10001
|
+
const uint8_t *source_end = source_cursor + dest_length;
|
9263
10002
|
|
9264
10003
|
// We're going to move bytes backward in the string when we get leading
|
9265
10004
|
// whitespace, so we'll maintain a pointer to the current position in the
|
9266
10005
|
// string that we're writing to.
|
9267
|
-
|
10006
|
+
uint8_t *dest_cursor = source_start;
|
9268
10007
|
|
9269
10008
|
while (source_cursor < source_end) {
|
9270
10009
|
// If we need to dedent the next element within the heredoc or the next
|
@@ -9291,7 +10030,7 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
|
|
9291
10030
|
|
9292
10031
|
// At this point we have dedented all that we need to, so we need to find
|
9293
10032
|
// the next newline.
|
9294
|
-
const
|
10033
|
+
const uint8_t *breakpoint = next_newline(source_cursor, source_end - source_cursor);
|
9295
10034
|
|
9296
10035
|
if (breakpoint == NULL) {
|
9297
10036
|
// If there isn't another newline, then we can just move the rest of the
|
@@ -9314,7 +10053,7 @@ parse_heredoc_dedent(yp_parser_t *parser, yp_node_t *node, yp_heredoc_quote_t qu
|
|
9314
10053
|
yp_node_destroy(parser, node);
|
9315
10054
|
} else {
|
9316
10055
|
string->length = dest_length;
|
9317
|
-
yp_unescape_manipulate_string(parser, string, (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL
|
10056
|
+
yp_unescape_manipulate_string(parser, string, (quote == YP_HEREDOC_QUOTE_SINGLE) ? YP_UNESCAPE_MINIMAL : YP_UNESCAPE_ALL);
|
9318
10057
|
nodes->nodes[write_index++] = node;
|
9319
10058
|
}
|
9320
10059
|
|
@@ -9503,7 +10242,7 @@ parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) {
|
|
9503
10242
|
yp_node_t *key = ((yp_assoc_node_t *) first_assoc)->key;
|
9504
10243
|
|
9505
10244
|
if (YP_NODE_TYPE_P(key, YP_NODE_SYMBOL_NODE)) {
|
9506
|
-
yp_location_t *value_loc = &((yp_symbol_node_t *) key)->value_loc;
|
10245
|
+
const yp_location_t *value_loc = &((yp_symbol_node_t *) key)->value_loc;
|
9507
10246
|
yp_parser_local_add_location(parser, value_loc->start, value_loc->end);
|
9508
10247
|
}
|
9509
10248
|
}
|
@@ -9531,7 +10270,7 @@ parse_pattern_hash(yp_parser_t *parser, yp_node_t *first_assoc) {
|
|
9531
10270
|
if (!match_any_type_p(parser, 7, YP_TOKEN_COMMA, YP_TOKEN_KEYWORD_THEN, YP_TOKEN_BRACE_RIGHT, YP_TOKEN_BRACKET_RIGHT, YP_TOKEN_PARENTHESIS_RIGHT, YP_TOKEN_NEWLINE, YP_TOKEN_SEMICOLON)) {
|
9532
10271
|
value = parse_pattern(parser, false, "Expected a pattern expression after the key.");
|
9533
10272
|
} else {
|
9534
|
-
yp_location_t *value_loc = &((yp_symbol_node_t *) key)->value_loc;
|
10273
|
+
const yp_location_t *value_loc = &((yp_symbol_node_t *) key)->value_loc;
|
9535
10274
|
yp_parser_local_add_location(parser, value_loc->start, value_loc->end);
|
9536
10275
|
}
|
9537
10276
|
|
@@ -10071,10 +10810,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10071
10810
|
}
|
10072
10811
|
case YP_TOKEN_PARENTHESIS_LEFT:
|
10073
10812
|
case YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
|
10074
|
-
|
10813
|
+
yp_token_t opening = parser->current;
|
10075
10814
|
parser_lex(parser);
|
10076
|
-
|
10077
|
-
yp_token_t opening = parser->previous;
|
10078
10815
|
while (accept_any(parser, 2, YP_TOKEN_SEMICOLON, YP_TOKEN_NEWLINE));
|
10079
10816
|
|
10080
10817
|
// If this is the end of the file or we match a right parenthesis, then
|
@@ -10093,7 +10830,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10093
10830
|
// If we hit a right parenthesis, then we're done parsing the parentheses
|
10094
10831
|
// node, and we can check which kind of node we should return.
|
10095
10832
|
if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
|
10096
|
-
if (
|
10833
|
+
if (opening.type == YP_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
|
10097
10834
|
lex_state_set(parser, YP_LEX_STATE_ENDARG);
|
10098
10835
|
}
|
10099
10836
|
parser_lex(parser);
|
@@ -10111,6 +10848,8 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10111
10848
|
|
10112
10849
|
if (multi_statement->lparen_loc.start == NULL) {
|
10113
10850
|
multi_write = (yp_multi_write_node_t *) statement;
|
10851
|
+
multi_write->base.location.start = lparen_loc.start;
|
10852
|
+
multi_write->base.location.end = rparen_loc.end;
|
10114
10853
|
multi_write->lparen_loc = lparen_loc;
|
10115
10854
|
multi_write->rparen_loc = rparen_loc;
|
10116
10855
|
} else {
|
@@ -10193,7 +10932,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10193
10932
|
|
10194
10933
|
yp_token_t closing = not_provided(parser);
|
10195
10934
|
|
10196
|
-
return (yp_node_t *)
|
10935
|
+
return (yp_node_t *) yp_char_literal_node_create_and_unescape(parser, &opening, &content, &closing, YP_UNESCAPE_ALL);
|
10197
10936
|
}
|
10198
10937
|
case YP_TOKEN_CLASS_VARIABLE: {
|
10199
10938
|
parser_lex(parser);
|
@@ -10213,7 +10952,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10213
10952
|
// fact a method call, not a constant read.
|
10214
10953
|
if (
|
10215
10954
|
match_type_p(parser, YP_TOKEN_PARENTHESIS_LEFT) ||
|
10216
|
-
(binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser,
|
10955
|
+
(binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))) ||
|
10217
10956
|
(yp_accepts_block_stack_p(parser) && match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT))
|
10218
10957
|
) {
|
10219
10958
|
yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
|
@@ -10336,7 +11075,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10336
11075
|
// can still be a method call if it is followed by arguments or
|
10337
11076
|
// a block, so we need to check for that here.
|
10338
11077
|
if (
|
10339
|
-
(binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser,
|
11078
|
+
(binding_power <= YP_BINDING_POWER_ASSIGNMENT && (token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))) ||
|
10340
11079
|
(yp_accepts_block_stack_p(parser) && match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_DO, YP_TOKEN_BRACE_LEFT))
|
10341
11080
|
) {
|
10342
11081
|
yp_arguments_t arguments = YP_EMPTY_ARGUMENTS;
|
@@ -10738,7 +11477,9 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10738
11477
|
|
10739
11478
|
yp_node_t *statements = NULL;
|
10740
11479
|
if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) {
|
11480
|
+
yp_accepts_block_stack_push(parser, true);
|
10741
11481
|
statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_SCLASS);
|
11482
|
+
yp_accepts_block_stack_pop(parser);
|
10742
11483
|
}
|
10743
11484
|
|
10744
11485
|
if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) {
|
@@ -10754,7 +11495,12 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10754
11495
|
return (yp_node_t *) yp_singleton_class_node_create(parser, &locals, &class_keyword, &operator, expression, statements, &parser->previous);
|
10755
11496
|
}
|
10756
11497
|
|
10757
|
-
yp_node_t *
|
11498
|
+
yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected to find a class name after `class`.");
|
11499
|
+
yp_token_t name = parser->previous;
|
11500
|
+
if (name.type != YP_TOKEN_CONSTANT) {
|
11501
|
+
yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Expected a constant name after `class`.");
|
11502
|
+
}
|
11503
|
+
|
10758
11504
|
yp_token_t inheritance_operator;
|
10759
11505
|
yp_node_t *superclass;
|
10760
11506
|
|
@@ -10795,7 +11541,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10795
11541
|
yp_constant_id_list_t locals = parser->current_scope->locals;
|
10796
11542
|
yp_parser_scope_pop(parser);
|
10797
11543
|
yp_do_loop_stack_pop(parser);
|
10798
|
-
return (yp_node_t *) yp_class_node_create(parser, &locals, &class_keyword, name, &inheritance_operator, superclass, statements, &parser->previous);
|
11544
|
+
return (yp_node_t *) yp_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->previous);
|
10799
11545
|
}
|
10800
11546
|
case YP_TOKEN_KEYWORD_DEF: {
|
10801
11547
|
yp_token_t def_keyword = parser->current;
|
@@ -10954,6 +11700,12 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
10954
11700
|
break;
|
10955
11701
|
}
|
10956
11702
|
case YP_CASE_PARAMETER: {
|
11703
|
+
// If we're about to lex a label, we need to add the label
|
11704
|
+
// state to make sure the next newline is ignored.
|
11705
|
+
if (parser->current.type == YP_TOKEN_LABEL) {
|
11706
|
+
lex_state_set(parser, parser->lex_state | YP_LEX_STATE_LABEL);
|
11707
|
+
}
|
11708
|
+
|
10957
11709
|
lparen = not_provided(parser);
|
10958
11710
|
rparen = not_provided(parser);
|
10959
11711
|
params = parse_parameters(parser, YP_BINDING_POWER_DEFINED, false, false, true);
|
@@ -11008,7 +11760,9 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11008
11760
|
yp_do_loop_stack_push(parser, false);
|
11009
11761
|
|
11010
11762
|
if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE, YP_TOKEN_KEYWORD_END)) {
|
11763
|
+
yp_accepts_block_stack_push(parser, true);
|
11011
11764
|
statements = (yp_node_t *) parse_statements(parser, YP_CONTEXT_DEF);
|
11765
|
+
yp_accepts_block_stack_pop(parser);
|
11012
11766
|
}
|
11013
11767
|
|
11014
11768
|
if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) {
|
@@ -11183,13 +11937,14 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11183
11937
|
parser_lex(parser);
|
11184
11938
|
|
11185
11939
|
yp_token_t module_keyword = parser->previous;
|
11186
|
-
yp_node_t *
|
11940
|
+
yp_node_t *constant_path = parse_expression(parser, YP_BINDING_POWER_INDEX, "Expected to find a module name after `module`.");
|
11941
|
+
yp_token_t name;
|
11187
11942
|
|
11188
|
-
// If we can recover from a syntax error that occurred while parsing
|
11189
|
-
// name of the module, then we'll handle that here.
|
11190
|
-
if (YP_NODE_TYPE_P(
|
11191
|
-
yp_token_t
|
11192
|
-
return (yp_node_t *) yp_module_node_create(parser, NULL, &module_keyword,
|
11943
|
+
// If we can recover from a syntax error that occurred while parsing
|
11944
|
+
// the name of the module, then we'll handle that here.
|
11945
|
+
if (YP_NODE_TYPE_P(constant_path, YP_NODE_MISSING_NODE)) {
|
11946
|
+
yp_token_t missing = (yp_token_t) { .type = YP_TOKEN_MISSING, .start = parser->previous.end, .end = parser->previous.end };
|
11947
|
+
return (yp_node_t *) yp_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
|
11193
11948
|
}
|
11194
11949
|
|
11195
11950
|
while (accept(parser, YP_TOKEN_COLON_COLON)) {
|
@@ -11198,7 +11953,15 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11198
11953
|
expect(parser, YP_TOKEN_CONSTANT, "Expected to find a module name after `::`.");
|
11199
11954
|
yp_node_t *constant = (yp_node_t *) yp_constant_read_node_create(parser, &parser->previous);
|
11200
11955
|
|
11201
|
-
|
11956
|
+
constant_path = (yp_node_t *) yp_constant_path_node_create(parser, constant_path, &double_colon, constant);
|
11957
|
+
}
|
11958
|
+
|
11959
|
+
// Here we retrieve the name of the module. If it wasn't a constant,
|
11960
|
+
// then it's possible that `module foo` was passed, which is a
|
11961
|
+
// syntax error. We handle that here as well.
|
11962
|
+
name = parser->previous;
|
11963
|
+
if (name.type != YP_TOKEN_CONSTANT) {
|
11964
|
+
yp_diagnostic_list_append(&parser->error_list, name.start, name.end, "Expected to find a module name after `module`.");
|
11202
11965
|
}
|
11203
11966
|
|
11204
11967
|
yp_parser_scope_push(parser, true);
|
@@ -11225,7 +11988,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11225
11988
|
yp_diagnostic_list_append(&parser->error_list, module_keyword.start, module_keyword.end, "Module definition in method body");
|
11226
11989
|
}
|
11227
11990
|
|
11228
|
-
return (yp_node_t *) yp_module_node_create(parser, &locals, &module_keyword, name, statements, &parser->previous);
|
11991
|
+
return (yp_node_t *) yp_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous);
|
11229
11992
|
}
|
11230
11993
|
case YP_TOKEN_KEYWORD_NIL:
|
11231
11994
|
parser_lex(parser);
|
@@ -11261,12 +12024,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11261
12024
|
expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `until` statement.");
|
11262
12025
|
}
|
11263
12026
|
|
11264
|
-
|
11265
|
-
if (parser->previous.type == YP_TOKEN_KEYWORD_END) {
|
11266
|
-
until_node->base.location.end = parser->previous.end;
|
11267
|
-
}
|
11268
|
-
|
11269
|
-
return (yp_node_t *) until_node;
|
12027
|
+
return (yp_node_t *) yp_until_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
|
11270
12028
|
}
|
11271
12029
|
case YP_TOKEN_KEYWORD_WHILE: {
|
11272
12030
|
yp_do_loop_stack_push(parser, true);
|
@@ -11287,25 +12045,16 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11287
12045
|
expect(parser, YP_TOKEN_KEYWORD_END, "Expected `end` to close `while` statement.");
|
11288
12046
|
}
|
11289
12047
|
|
11290
|
-
|
11291
|
-
if (parser->previous.type == YP_TOKEN_KEYWORD_END) {
|
11292
|
-
while_node->base.location.end = parser->previous.end;
|
11293
|
-
}
|
11294
|
-
return (yp_node_t *) while_node;
|
12048
|
+
return (yp_node_t *) yp_while_node_create(parser, &keyword, &parser->previous, predicate, statements, 0);
|
11295
12049
|
}
|
11296
12050
|
case YP_TOKEN_PERCENT_LOWER_I: {
|
11297
12051
|
parser_lex(parser);
|
11298
12052
|
yp_array_node_t *array = yp_array_node_create(parser, &parser->previous);
|
11299
12053
|
|
11300
12054
|
while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) {
|
11301
|
-
|
11302
|
-
accept(parser, YP_TOKEN_WORDS_SEP);
|
11303
|
-
} else {
|
11304
|
-
expect(parser, YP_TOKEN_WORDS_SEP, "Expected a separator for the symbols in a `%i` list.");
|
11305
|
-
if (match_type_p(parser, YP_TOKEN_STRING_END)) break;
|
11306
|
-
}
|
11307
|
-
|
12055
|
+
accept(parser, YP_TOKEN_WORDS_SEP);
|
11308
12056
|
if (match_type_p(parser, YP_TOKEN_STRING_END)) break;
|
12057
|
+
|
11309
12058
|
expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a symbol in a `%i` list.");
|
11310
12059
|
|
11311
12060
|
yp_token_t opening = not_provided(parser);
|
@@ -11360,6 +12109,19 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11360
12109
|
// to the list of child nodes.
|
11361
12110
|
yp_node_t *part = parse_string_part(parser);
|
11362
12111
|
yp_interpolated_symbol_node_append((yp_interpolated_symbol_node_t *) current, part);
|
12112
|
+
} else if (YP_NODE_TYPE_P(current, YP_NODE_SYMBOL_NODE)) {
|
12113
|
+
// If we hit string content and the current node is a string node,
|
12114
|
+
// then we need to convert the current node into an interpolated
|
12115
|
+
// string and add the string content to the list of child nodes.
|
12116
|
+
yp_token_t opening = not_provided(parser);
|
12117
|
+
yp_token_t closing = not_provided(parser);
|
12118
|
+
yp_interpolated_symbol_node_t *interpolated =
|
12119
|
+
yp_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
|
12120
|
+
yp_interpolated_symbol_node_append(interpolated, current);
|
12121
|
+
|
12122
|
+
yp_node_t *part = parse_string_part(parser);
|
12123
|
+
yp_interpolated_symbol_node_append(interpolated, part);
|
12124
|
+
current = (yp_node_t *) interpolated;
|
11363
12125
|
} else {
|
11364
12126
|
assert(false && "unreachable");
|
11365
12127
|
}
|
@@ -11462,12 +12224,9 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11462
12224
|
accept(parser, YP_TOKEN_WORDS_SEP);
|
11463
12225
|
|
11464
12226
|
while (!match_any_type_p(parser, 2, YP_TOKEN_STRING_END, YP_TOKEN_EOF)) {
|
11465
|
-
|
11466
|
-
|
11467
|
-
|
11468
|
-
expect(parser, YP_TOKEN_WORDS_SEP, "Expected a separator for the strings in a `%w` list.");
|
11469
|
-
if (match_type_p(parser, YP_TOKEN_STRING_END)) break;
|
11470
|
-
}
|
12227
|
+
accept(parser, YP_TOKEN_WORDS_SEP);
|
12228
|
+
if (match_type_p(parser, YP_TOKEN_STRING_END)) break;
|
12229
|
+
|
11471
12230
|
expect(parser, YP_TOKEN_STRING_CONTENT, "Expected a string in a `%w` list.");
|
11472
12231
|
|
11473
12232
|
yp_token_t opening = not_provided(parser);
|
@@ -11517,6 +12276,19 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11517
12276
|
// to the list of child nodes.
|
11518
12277
|
yp_node_t *part = parse_string_part(parser);
|
11519
12278
|
yp_interpolated_string_node_append((yp_interpolated_string_node_t *) current, part);
|
12279
|
+
} else if (YP_NODE_TYPE_P(current, YP_NODE_STRING_NODE)) {
|
12280
|
+
// If we hit string content and the current node is a string node,
|
12281
|
+
// then we need to convert the current node into an interpolated
|
12282
|
+
// string and add the string content to the list of child nodes.
|
12283
|
+
yp_token_t opening = not_provided(parser);
|
12284
|
+
yp_token_t closing = not_provided(parser);
|
12285
|
+
yp_interpolated_string_node_t *interpolated =
|
12286
|
+
yp_interpolated_string_node_create(parser, &opening, NULL, &closing);
|
12287
|
+
yp_interpolated_string_node_append(interpolated, current);
|
12288
|
+
|
12289
|
+
yp_node_t *part = parse_string_part(parser);
|
12290
|
+
yp_interpolated_string_node_append(interpolated, part);
|
12291
|
+
current = (yp_node_t *) interpolated;
|
11520
12292
|
} else {
|
11521
12293
|
assert(false && "unreachable");
|
11522
12294
|
}
|
@@ -11797,30 +12569,32 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11797
12569
|
yp_accepts_block_stack_push(parser, true);
|
11798
12570
|
parser_lex(parser);
|
11799
12571
|
|
11800
|
-
yp_token_t
|
12572
|
+
yp_token_t operator = parser->previous;
|
11801
12573
|
yp_parser_scope_push(parser, false);
|
11802
12574
|
yp_block_parameters_node_t *params;
|
11803
12575
|
|
11804
12576
|
switch (parser->current.type) {
|
11805
12577
|
case YP_TOKEN_PARENTHESIS_LEFT: {
|
11806
|
-
yp_token_t
|
12578
|
+
yp_token_t opening = parser->current;
|
11807
12579
|
parser_lex(parser);
|
11808
12580
|
|
11809
12581
|
if (match_type_p(parser, YP_TOKEN_PARENTHESIS_RIGHT)) {
|
11810
|
-
params = yp_block_parameters_node_create(parser, NULL, &
|
12582
|
+
params = yp_block_parameters_node_create(parser, NULL, &opening);
|
11811
12583
|
} else {
|
11812
|
-
params = parse_block_parameters(parser, false, &
|
12584
|
+
params = parse_block_parameters(parser, false, &opening, true);
|
11813
12585
|
}
|
11814
12586
|
|
11815
12587
|
accept(parser, YP_TOKEN_NEWLINE);
|
11816
12588
|
expect(parser, YP_TOKEN_PARENTHESIS_RIGHT, "Expected ')' after left parenthesis.");
|
11817
|
-
yp_block_parameters_node_closing_set(params, &parser->previous);
|
11818
12589
|
|
12590
|
+
yp_block_parameters_node_closing_set(params, &parser->previous);
|
11819
12591
|
break;
|
11820
12592
|
}
|
11821
12593
|
case YP_CASE_PARAMETER: {
|
12594
|
+
yp_accepts_block_stack_push(parser, false);
|
11822
12595
|
yp_token_t opening = not_provided(parser);
|
11823
12596
|
params = parse_block_parameters(parser, false, &opening, true);
|
12597
|
+
yp_accepts_block_stack_pop(parser);
|
11824
12598
|
break;
|
11825
12599
|
}
|
11826
12600
|
default: {
|
@@ -11829,19 +12603,25 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11829
12603
|
}
|
11830
12604
|
}
|
11831
12605
|
|
12606
|
+
yp_token_t opening;
|
11832
12607
|
yp_node_t *body = NULL;
|
11833
12608
|
parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
|
11834
12609
|
|
11835
12610
|
if (accept(parser, YP_TOKEN_LAMBDA_BEGIN)) {
|
12611
|
+
opening = parser->previous;
|
12612
|
+
|
11836
12613
|
if (!accept(parser, YP_TOKEN_BRACE_RIGHT)) {
|
11837
12614
|
body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_BRACES);
|
11838
12615
|
expect(parser, YP_TOKEN_BRACE_RIGHT, "Expecting '}' to close lambda block.");
|
11839
12616
|
}
|
11840
12617
|
} else {
|
11841
12618
|
expect(parser, YP_TOKEN_KEYWORD_DO, "Expected a 'do' keyword or a '{' to open lambda block.");
|
12619
|
+
opening = parser->previous;
|
11842
12620
|
|
11843
12621
|
if (!match_any_type_p(parser, 3, YP_TOKEN_KEYWORD_END, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) {
|
12622
|
+
yp_accepts_block_stack_push(parser, true);
|
11844
12623
|
body = (yp_node_t *) parse_statements(parser, YP_CONTEXT_LAMBDA_DO_END);
|
12624
|
+
yp_accepts_block_stack_pop(parser);
|
11845
12625
|
}
|
11846
12626
|
|
11847
12627
|
if (match_any_type_p(parser, 2, YP_TOKEN_KEYWORD_RESCUE, YP_TOKEN_KEYWORD_ENSURE)) {
|
@@ -11855,7 +12635,7 @@ parse_expression_prefix(yp_parser_t *parser, yp_binding_power_t binding_power) {
|
|
11855
12635
|
yp_constant_id_list_t locals = parser->current_scope->locals;
|
11856
12636
|
yp_parser_scope_pop(parser);
|
11857
12637
|
yp_accepts_block_stack_pop(parser);
|
11858
|
-
return (yp_node_t *) yp_lambda_node_create(parser, &locals, &
|
12638
|
+
return (yp_node_t *) yp_lambda_node_create(parser, &locals, &operator, &opening, &parser->previous, params, body);
|
11859
12639
|
}
|
11860
12640
|
case YP_TOKEN_UPLUS: {
|
11861
12641
|
parser_lex(parser);
|
@@ -12074,7 +12854,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12074
12854
|
case YP_CASE_WRITABLE: {
|
12075
12855
|
parser_lex(parser);
|
12076
12856
|
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
12077
|
-
return
|
12857
|
+
return parse_write(parser, node, &token, value);
|
12078
12858
|
}
|
12079
12859
|
case YP_NODE_SPLAT_NODE: {
|
12080
12860
|
yp_splat_node_t *splat_node = (yp_splat_node_t *) node;
|
@@ -12083,7 +12863,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12083
12863
|
case YP_CASE_WRITABLE:
|
12084
12864
|
parser_lex(parser);
|
12085
12865
|
yp_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, "Expected a value after =.");
|
12086
|
-
return
|
12866
|
+
return parse_write(parser, (yp_node_t *) splat_node, &token, value);
|
12087
12867
|
default:
|
12088
12868
|
break;
|
12089
12869
|
}
|
@@ -12105,19 +12885,57 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12105
12885
|
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
12106
12886
|
yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
|
12107
12887
|
/* fallthrough */
|
12108
|
-
case
|
12109
|
-
|
12110
|
-
|
12111
|
-
|
12112
|
-
|
12113
|
-
|
12888
|
+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
|
12889
|
+
parser_lex(parser);
|
12890
|
+
|
12891
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12892
|
+
yp_node_t *result = (yp_node_t *) yp_global_variable_and_write_node_create(parser, node, &token, value);
|
12893
|
+
|
12894
|
+
yp_node_destroy(parser, node);
|
12895
|
+
return result;
|
12896
|
+
}
|
12897
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
12898
|
+
parser_lex(parser);
|
12899
|
+
|
12900
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12901
|
+
yp_node_t *result = (yp_node_t *) yp_class_variable_and_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value);
|
12902
|
+
|
12903
|
+
yp_node_destroy(parser, node);
|
12904
|
+
return result;
|
12905
|
+
}
|
12906
|
+
case YP_NODE_CONSTANT_PATH_NODE: {
|
12907
|
+
parser_lex(parser);
|
12908
|
+
|
12909
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12910
|
+
return (yp_node_t *) yp_constant_path_and_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
|
12911
|
+
}
|
12912
|
+
case YP_NODE_CONSTANT_READ_NODE: {
|
12913
|
+
parser_lex(parser);
|
12914
|
+
|
12915
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12916
|
+
yp_node_t *result = (yp_node_t *) yp_constant_and_write_node_create(parser, node, &token, value);
|
12917
|
+
|
12918
|
+
yp_node_destroy(parser, node);
|
12919
|
+
return result;
|
12920
|
+
}
|
12921
|
+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
|
12114
12922
|
parser_lex(parser);
|
12115
12923
|
|
12116
|
-
|
12117
|
-
|
12924
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12925
|
+
yp_node_t *result = (yp_node_t *) yp_instance_variable_and_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value);
|
12926
|
+
|
12927
|
+
yp_node_destroy(parser, node);
|
12928
|
+
return result;
|
12929
|
+
}
|
12930
|
+
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
12931
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
12932
|
+
parser_lex(parser);
|
12118
12933
|
|
12119
12934
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12120
|
-
|
12935
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, cast->name, cast->depth);
|
12936
|
+
|
12937
|
+
yp_node_destroy(parser, node);
|
12938
|
+
return result;
|
12121
12939
|
}
|
12122
12940
|
case YP_NODE_CALL_NODE: {
|
12123
12941
|
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
@@ -12127,25 +12945,22 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12127
12945
|
// will transform it into a local variable write.
|
12128
12946
|
if (yp_call_node_variable_call_p(call_node)) {
|
12129
12947
|
yp_location_t message_loc = call_node->message_loc;
|
12130
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12948
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12131
12949
|
|
12132
12950
|
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12133
12951
|
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12134
12952
|
}
|
12135
12953
|
|
12136
12954
|
parser_lex(parser);
|
12137
|
-
|
12138
|
-
yp_token_t operator = not_provided(parser);
|
12139
|
-
node = parse_target(parser, node, &operator, NULL);
|
12140
|
-
|
12141
12955
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12142
|
-
|
12956
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_and_write_node_create(parser, node, &token, value, constant_id, 0);
|
12957
|
+
|
12958
|
+
yp_node_destroy(parser, node);
|
12959
|
+
return result;
|
12143
12960
|
}
|
12144
12961
|
|
12145
12962
|
parser_lex(parser);
|
12146
|
-
|
12147
|
-
yp_token_t operator = not_provided(parser);
|
12148
|
-
node = parse_target(parser, node, &operator, NULL);
|
12963
|
+
node = parse_target(parser, node);
|
12149
12964
|
|
12150
12965
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12151
12966
|
return (yp_node_t *) yp_call_operator_and_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
@@ -12171,19 +12986,57 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12171
12986
|
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
12172
12987
|
yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
|
12173
12988
|
/* fallthrough */
|
12174
|
-
case
|
12175
|
-
|
12176
|
-
|
12177
|
-
|
12178
|
-
|
12179
|
-
|
12989
|
+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
|
12990
|
+
parser_lex(parser);
|
12991
|
+
|
12992
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12993
|
+
yp_node_t *result = (yp_node_t *) yp_global_variable_or_write_node_create(parser, node, &token, value);
|
12994
|
+
|
12995
|
+
yp_node_destroy(parser, node);
|
12996
|
+
return result;
|
12997
|
+
}
|
12998
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
12999
|
+
parser_lex(parser);
|
13000
|
+
|
13001
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
13002
|
+
yp_node_t *result = (yp_node_t *) yp_class_variable_or_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value);
|
13003
|
+
|
13004
|
+
yp_node_destroy(parser, node);
|
13005
|
+
return result;
|
13006
|
+
}
|
13007
|
+
case YP_NODE_CONSTANT_PATH_NODE: {
|
13008
|
+
parser_lex(parser);
|
13009
|
+
|
13010
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
13011
|
+
return (yp_node_t *) yp_constant_path_or_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
|
13012
|
+
}
|
13013
|
+
case YP_NODE_CONSTANT_READ_NODE: {
|
13014
|
+
parser_lex(parser);
|
13015
|
+
|
13016
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
13017
|
+
yp_node_t *result = (yp_node_t *) yp_constant_or_write_node_create(parser, node, &token, value);
|
13018
|
+
|
13019
|
+
yp_node_destroy(parser, node);
|
13020
|
+
return result;
|
13021
|
+
}
|
13022
|
+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
|
12180
13023
|
parser_lex(parser);
|
12181
13024
|
|
12182
|
-
|
12183
|
-
|
13025
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
13026
|
+
yp_node_t *result = (yp_node_t *) yp_instance_variable_or_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value);
|
13027
|
+
|
13028
|
+
yp_node_destroy(parser, node);
|
13029
|
+
return result;
|
13030
|
+
}
|
13031
|
+
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
13032
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
13033
|
+
parser_lex(parser);
|
12184
13034
|
|
12185
13035
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12186
|
-
|
13036
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, cast->name, cast->depth);
|
13037
|
+
|
13038
|
+
yp_node_destroy(parser, node);
|
13039
|
+
return result;
|
12187
13040
|
}
|
12188
13041
|
case YP_NODE_CALL_NODE: {
|
12189
13042
|
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
@@ -12193,25 +13046,22 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12193
13046
|
// will transform it into a local variable write.
|
12194
13047
|
if (yp_call_node_variable_call_p(call_node)) {
|
12195
13048
|
yp_location_t message_loc = call_node->message_loc;
|
12196
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
13049
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12197
13050
|
|
12198
13051
|
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12199
13052
|
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12200
13053
|
}
|
12201
13054
|
|
12202
13055
|
parser_lex(parser);
|
12203
|
-
|
12204
|
-
yp_token_t operator = not_provided(parser);
|
12205
|
-
node = parse_target(parser, node, &operator, NULL);
|
12206
|
-
|
12207
13056
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12208
|
-
|
13057
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_or_write_node_create(parser, node, &token, value, constant_id, 0);
|
13058
|
+
|
13059
|
+
yp_node_destroy(parser, node);
|
13060
|
+
return result;
|
12209
13061
|
}
|
12210
13062
|
|
12211
13063
|
parser_lex(parser);
|
12212
|
-
|
12213
|
-
yp_token_t operator = not_provided(parser);
|
12214
|
-
node = parse_target(parser, node, &operator, NULL);
|
13064
|
+
node = parse_target(parser, node);
|
12215
13065
|
|
12216
13066
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after ||=");
|
12217
13067
|
return (yp_node_t *) yp_call_operator_or_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
@@ -12247,19 +13097,57 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12247
13097
|
case YP_NODE_NUMBERED_REFERENCE_READ_NODE:
|
12248
13098
|
yp_diagnostic_list_append(&parser->error_list, node->location.start, node->location.end, "Can't set variable");
|
12249
13099
|
/* fallthrough */
|
12250
|
-
case
|
12251
|
-
|
12252
|
-
|
12253
|
-
|
12254
|
-
|
13100
|
+
case YP_NODE_GLOBAL_VARIABLE_READ_NODE: {
|
13101
|
+
parser_lex(parser);
|
13102
|
+
|
13103
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13104
|
+
yp_node_t *result = (yp_node_t *) yp_global_variable_operator_write_node_create(parser, node, &token, value);
|
13105
|
+
|
13106
|
+
yp_node_destroy(parser, node);
|
13107
|
+
return result;
|
13108
|
+
}
|
13109
|
+
case YP_NODE_CLASS_VARIABLE_READ_NODE: {
|
13110
|
+
parser_lex(parser);
|
13111
|
+
|
13112
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13113
|
+
yp_node_t *result = (yp_node_t *) yp_class_variable_operator_write_node_create(parser, (yp_class_variable_read_node_t *) node, &token, value);
|
13114
|
+
|
13115
|
+
yp_node_destroy(parser, node);
|
13116
|
+
return result;
|
13117
|
+
}
|
13118
|
+
case YP_NODE_CONSTANT_PATH_NODE: {
|
13119
|
+
parser_lex(parser);
|
13120
|
+
|
13121
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13122
|
+
return (yp_node_t *) yp_constant_path_operator_write_node_create(parser, (yp_constant_path_node_t *) node, &token, value);
|
13123
|
+
}
|
13124
|
+
case YP_NODE_CONSTANT_READ_NODE: {
|
13125
|
+
parser_lex(parser);
|
13126
|
+
|
13127
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13128
|
+
yp_node_t *result = (yp_node_t *) yp_constant_operator_write_node_create(parser, node, &token, value);
|
13129
|
+
|
13130
|
+
yp_node_destroy(parser, node);
|
13131
|
+
return result;
|
13132
|
+
}
|
13133
|
+
case YP_NODE_INSTANCE_VARIABLE_READ_NODE: {
|
13134
|
+
parser_lex(parser);
|
13135
|
+
|
13136
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13137
|
+
yp_node_t *result = (yp_node_t *) yp_instance_variable_operator_write_node_create(parser, (yp_instance_variable_read_node_t *) node, &token, value);
|
13138
|
+
|
13139
|
+
yp_node_destroy(parser, node);
|
13140
|
+
return result;
|
13141
|
+
}
|
12255
13142
|
case YP_NODE_LOCAL_VARIABLE_READ_NODE: {
|
13143
|
+
yp_local_variable_read_node_t *cast = (yp_local_variable_read_node_t *) node;
|
12256
13144
|
parser_lex(parser);
|
12257
13145
|
|
12258
|
-
|
12259
|
-
|
13146
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13147
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, cast->name, cast->depth);
|
12260
13148
|
|
12261
|
-
|
12262
|
-
return
|
13149
|
+
yp_node_destroy(parser, node);
|
13150
|
+
return result;
|
12263
13151
|
}
|
12264
13152
|
case YP_NODE_CALL_NODE: {
|
12265
13153
|
yp_call_node_t *call_node = (yp_call_node_t *) node;
|
@@ -12269,25 +13157,23 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12269
13157
|
// will transform it into a local variable write.
|
12270
13158
|
if (yp_call_node_variable_call_p(call_node)) {
|
12271
13159
|
yp_location_t message_loc = call_node->message_loc;
|
12272
|
-
yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
13160
|
+
yp_constant_id_t constant_id = yp_parser_local_add_location(parser, message_loc.start, message_loc.end);
|
12273
13161
|
|
12274
13162
|
if (token_is_numbered_parameter(message_loc.start, message_loc.end)) {
|
12275
13163
|
yp_diagnostic_list_append(&parser->error_list, message_loc.start, message_loc.end, "reserved for numbered parameter");
|
12276
13164
|
}
|
12277
13165
|
|
12278
13166
|
parser_lex(parser);
|
13167
|
+
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
13168
|
+
yp_node_t *result = (yp_node_t *) yp_local_variable_operator_write_node_create(parser, node, &token, value, constant_id, 0);
|
12279
13169
|
|
12280
|
-
|
12281
|
-
|
12282
|
-
|
12283
|
-
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after &&=");
|
12284
|
-
return (yp_node_t *) yp_operator_write_node_create(parser, node, &token, value);
|
13170
|
+
yp_node_destroy(parser, node);
|
13171
|
+
return result;
|
12285
13172
|
}
|
12286
13173
|
|
12287
|
-
|
12288
|
-
node = parse_target(parser, node, &operator, NULL);
|
12289
|
-
|
13174
|
+
node = parse_target(parser, node);
|
12290
13175
|
parser_lex(parser);
|
13176
|
+
|
12291
13177
|
yp_node_t *value = parse_expression(parser, binding_power, "Expected a value after the operator.");
|
12292
13178
|
return (yp_node_t *) yp_call_operator_write_node_create(parser, (yp_call_node_t *) node, &token, value);
|
12293
13179
|
}
|
@@ -12336,7 +13222,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12336
13222
|
yp_string_list_t named_captures;
|
12337
13223
|
yp_string_list_init(&named_captures);
|
12338
13224
|
|
12339
|
-
yp_location_t *content_loc = &((yp_regular_expression_node_t *) node)->content_loc;
|
13225
|
+
const yp_location_t *content_loc = &((yp_regular_expression_node_t *) node)->content_loc;
|
12340
13226
|
|
12341
13227
|
if (yp_regexp_named_capture_group_names(content_loc->start, (size_t) (content_loc->end - content_loc->start), &named_captures, parser->encoding_changed, &parser->encoding)) {
|
12342
13228
|
for (size_t index = 0; index < named_captures.length; index++) {
|
@@ -12456,7 +13342,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12456
13342
|
yp_statements_node_body_append(statements, node);
|
12457
13343
|
|
12458
13344
|
yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'until'");
|
12459
|
-
return (yp_node_t *)
|
13345
|
+
return (yp_node_t *) yp_until_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_NODE_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0);
|
12460
13346
|
}
|
12461
13347
|
case YP_TOKEN_KEYWORD_WHILE_MODIFIER: {
|
12462
13348
|
parser_lex(parser);
|
@@ -12464,7 +13350,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12464
13350
|
yp_statements_node_body_append(statements, node);
|
12465
13351
|
|
12466
13352
|
yp_node_t *predicate = parse_expression(parser, binding_power, "Expected a predicate after 'while'");
|
12467
|
-
return (yp_node_t *)
|
13353
|
+
return (yp_node_t *) yp_while_node_modifier_create(parser, &token, predicate, statements, YP_NODE_TYPE_P(node, YP_NODE_BEGIN_NODE) ? YP_LOOP_FLAGS_BEGIN_MODIFIER : 0);
|
12468
13354
|
}
|
12469
13355
|
case YP_TOKEN_QUESTION_MARK: {
|
12470
13356
|
parser_lex(parser);
|
@@ -12502,7 +13388,7 @@ parse_expression_infix(yp_parser_t *parser, yp_node_t *node, yp_binding_power_t
|
|
12502
13388
|
|
12503
13389
|
if (
|
12504
13390
|
(parser->current.type == YP_TOKEN_PARENTHESIS_LEFT) ||
|
12505
|
-
(token_begins_expression_p(parser->current.type) || match_any_type_p(parser,
|
13391
|
+
(token_begins_expression_p(parser->current.type) || match_any_type_p(parser, 3, YP_TOKEN_UAMPERSAND, YP_TOKEN_USTAR, YP_TOKEN_USTAR_STAR))
|
12506
13392
|
) {
|
12507
13393
|
// If we have a constant immediately following a '::' operator, then
|
12508
13394
|
// this can either be a constant path or a method call, depending on
|
@@ -12734,7 +13620,7 @@ yp_metadata_read_u32(const char *ptr) {
|
|
12734
13620
|
// ]*
|
12735
13621
|
// ]
|
12736
13622
|
// ```
|
12737
|
-
|
13623
|
+
void
|
12738
13624
|
yp_parser_metadata(yp_parser_t *parser, const char *metadata) {
|
12739
13625
|
uint32_t filepath_size = yp_metadata_read_u32(metadata);
|
12740
13626
|
metadata += 4;
|
@@ -12760,7 +13646,7 @@ yp_parser_metadata(yp_parser_t *parser, const char *metadata) {
|
|
12760
13646
|
uint32_t local_size = yp_metadata_read_u32(metadata);
|
12761
13647
|
metadata += 4;
|
12762
13648
|
|
12763
|
-
yp_parser_local_add_location(parser, metadata, metadata + local_size);
|
13649
|
+
yp_parser_local_add_location(parser, (const uint8_t *) metadata, (const uint8_t *) (metadata + local_size));
|
12764
13650
|
metadata += local_size;
|
12765
13651
|
}
|
12766
13652
|
}
|
@@ -12772,7 +13658,9 @@ yp_parser_metadata(yp_parser_t *parser, const char *metadata) {
|
|
12772
13658
|
|
12773
13659
|
// Initialize a parser with the given start and end pointers.
|
12774
13660
|
YP_EXPORTED_FUNCTION void
|
12775
|
-
yp_parser_init(yp_parser_t *parser, const
|
13661
|
+
yp_parser_init(yp_parser_t *parser, const uint8_t *source, size_t size, const char *filepath) {
|
13662
|
+
assert(source != NULL);
|
13663
|
+
|
12776
13664
|
// Set filepath to the file that was passed
|
12777
13665
|
if (!filepath) filepath = "";
|
12778
13666
|
yp_string_t filepath_string;
|
@@ -12841,15 +13729,16 @@ yp_parser_init(yp_parser_t *parser, const char *source, size_t size, const char
|
|
12841
13729
|
size_t newline_size = size / 22;
|
12842
13730
|
yp_newline_list_init(&parser->newline_list, source, newline_size < 4 ? 4 : newline_size);
|
12843
13731
|
|
12844
|
-
|
12845
|
-
if (size >= 3 &&
|
12846
|
-
// If the first three bytes of the source are the UTF-8 BOM, then we'll skip
|
12847
|
-
// over them.
|
13732
|
+
// Skip past the UTF-8 BOM if it exists.
|
13733
|
+
if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
|
12848
13734
|
parser->current.end += 3;
|
12849
|
-
|
12850
|
-
|
12851
|
-
|
12852
|
-
|
13735
|
+
parser->encoding_comment_start += 3;
|
13736
|
+
}
|
13737
|
+
|
13738
|
+
// If the first two bytes of the source are a shebang, then we'll indicate
|
13739
|
+
// that the encoding comment is at the end of the shebang.
|
13740
|
+
if (peek(parser) == '#' && peek_offset(parser, 1) == '!') {
|
13741
|
+
const uint8_t *encoding_comment_start = next_newline(source, (ptrdiff_t) size);
|
12853
13742
|
if (encoding_comment_start) {
|
12854
13743
|
parser->encoding_comment_start = encoding_comment_start + 1;
|
12855
13744
|
}
|
@@ -12921,7 +13810,7 @@ yp_serialize(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
|
|
12921
13810
|
// Parse and serialize the AST represented by the given source to the given
|
12922
13811
|
// buffer.
|
12923
13812
|
YP_EXPORTED_FUNCTION void
|
12924
|
-
yp_parse_serialize(const
|
13813
|
+
yp_parse_serialize(const uint8_t *source, size_t size, yp_buffer_t *buffer, const char *metadata) {
|
12925
13814
|
yp_parser_t parser;
|
12926
13815
|
yp_parser_init(&parser, source, size, NULL);
|
12927
13816
|
if (metadata) yp_parser_metadata(&parser, metadata);
|