2#include "prism/node_new.h"
16#define PM_TAB_WHITESPACE_SIZE 8
19#define MIN(a,b) (((a)<(b))?(a):(b))
20#define MAX(a,b) (((a)>(b))?(a):(b))
26#define U32(value_) ((uint32_t) (value_))
28#define FL PM_NODE_FLAGS
29#define UP PM_NODE_UPCAST
31#define PM_LOCATION_START(location_) ((location_)->start)
32#define PM_LOCATION_END(location_) ((location_)->start + (location_)->length)
34#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
35#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
36#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
37#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
39#define PM_NODE_START(node_) (UP(node_)->location.start)
40#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
41#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
42#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
44#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
45#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
47#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
48#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
49#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
50#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
51#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
53#define PM_LOCATION_INIT(start_, length_) ((pm_location_t) { .start = (start_), .length = (length_) })
54#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
55#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
56#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
58#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
59#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
60#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
61#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
63#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
64#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
65#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
76lex_mode_incrementor(
const uint8_t start) {
93lex_mode_terminator(
const uint8_t start) {
135lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
136 uint8_t incrementor = lex_mode_incrementor(delimiter);
137 uint8_t terminator = lex_mode_terminator(delimiter);
143 .interpolation = interpolation,
144 .incrementor = incrementor,
145 .terminator = terminator
152 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
157 if (terminator !=
'\0') {
158 breakpoints[index++] = terminator;
164 breakpoints[index++] =
'#';
168 if (incrementor !=
'\0') {
169 breakpoints[index++] = incrementor;
173 return lex_mode_push(parser, lex_mode);
183 return lex_mode_push_list(parser,
false,
'\0');
190lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
192 .
mode = PM_LEX_REGEXP,
195 .incrementor = incrementor,
196 .terminator = terminator
204 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
208 if (terminator !=
'\0') {
209 breakpoints[index++] = terminator;
213 if (incrementor !=
'\0') {
214 breakpoints[index++] = incrementor;
218 return lex_mode_push(parser, lex_mode);
225lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
227 .
mode = PM_LEX_STRING,
230 .interpolation = interpolation,
231 .label_allowed = label_allowed,
232 .incrementor = incrementor,
233 .terminator = terminator
240 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
245 if (terminator !=
'\0') {
246 breakpoints[index++] = terminator;
252 breakpoints[index++] =
'#';
257 if (incrementor !=
'\0') {
258 breakpoints[index++] = incrementor;
262 return lex_mode_push(parser, lex_mode);
272 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
304 PM_IGNORED_NEWLINE_NONE = 0,
305 PM_IGNORED_NEWLINE_ALL,
306 PM_IGNORED_NEWLINE_PATTERN
307} pm_ignored_newline_type_t;
309static inline pm_ignored_newline_type_t
311 bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
314 return PM_IGNORED_NEWLINE_ALL;
315 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
316 return PM_IGNORED_NEWLINE_PATTERN;
318 return PM_IGNORED_NEWLINE_NONE;
324 return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->
lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
329 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
333lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
337 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
342 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
350 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
362#ifndef PM_DEBUG_LOGGING
367#define PM_DEBUG_LOGGING 0
373 fprintf(stderr,
"STATE: ");
376 if (parser->
lex_state == PM_LEX_STATE_NONE) {
377 fprintf(stderr,
"NONE\n");
381#define CHECK_STATE(state) \
382 if (parser->lex_state & state) { \
383 if (!first) fprintf(stderr, "|"); \
384 fprintf(stderr, "%s", #state); \
388 CHECK_STATE(PM_LEX_STATE_BEG)
389 CHECK_STATE(PM_LEX_STATE_END)
390 CHECK_STATE(PM_LEX_STATE_ENDARG)
391 CHECK_STATE(PM_LEX_STATE_ENDFN)
392 CHECK_STATE(PM_LEX_STATE_ARG)
393 CHECK_STATE(PM_LEX_STATE_CMDARG)
394 CHECK_STATE(PM_LEX_STATE_MID)
395 CHECK_STATE(PM_LEX_STATE_FNAME)
396 CHECK_STATE(PM_LEX_STATE_DOT)
397 CHECK_STATE(PM_LEX_STATE_CLASS)
398 CHECK_STATE(PM_LEX_STATE_LABEL)
399 CHECK_STATE(PM_LEX_STATE_LABELED)
400 CHECK_STATE(PM_LEX_STATE_FITEM)
404 fprintf(stderr,
"\n");
409 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
411 lex_state_set(parser, state);
412 fprintf(stderr,
"Now: ");
414 fprintf(stderr,
"\n");
417#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
425#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
428#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
431#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
434#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
437#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
440#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
443#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
454 pm_diagnostic_list_append(&parser->
error_list, start, length, diag_id);
463 pm_parser_err(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
472 pm_parser_err_token(parser, &parser->
current, diag_id);
481 pm_parser_err_token(parser, &parser->
previous, diag_id);
490 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
496#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
497 pm_diagnostic_list_append_format(&(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
503#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
504 PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
510#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
511 PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
517#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
518 PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id, __VA_ARGS__)
524#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
525 PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
532 pm_diagnostic_list_append(&parser->
warning_list, start, length, diag_id);
541 pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
550 pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
557#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
558 pm_diagnostic_list_append_format(&(parser_)->warning_list, start_, length_, diag_id_, __VA_ARGS__)
564#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
565 PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id_, __VA_ARGS__)
571#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
572 PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
578#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
579 PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
587pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
588 PM_PARSER_ERR_FORMAT(
590 U32(ident_start - parser->
start),
594 (
const char *) ident_start
606pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
608 if (scope == NULL)
return false;
613 .parameters = PM_SCOPE_PARAMETERS_NONE,
614 .implicit_parameters = { 0 },
632 if (scope->
previous == NULL)
return true;
633 if (scope->
closed)
return false;
634 }
while ((scope = scope->
previous) != NULL);
636 assert(
false &&
"unreachable");
644pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
647 while (depth-- > 0) {
648 assert(scope != NULL);
656 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
657 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
658 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
659} pm_scope_forwarding_param_check_result_t;
661static pm_scope_forwarding_param_check_result_t
662pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
664 bool conflict =
false;
666 while (scope != NULL) {
670 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
672 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
683 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
688 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
689 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
692 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
693 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
695 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
696 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
703 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
704 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
707 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
708 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
710 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
711 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
718 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
719 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
722 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
727 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
728 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
735 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
736 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
739 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
740 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
742 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
743 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
752pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
776#define PM_LOCALS_HASH_THRESHOLD 9
791 name = ((name >> 16) ^ name) * 0x45d9f3b;
792 name = ((name >> 16) ^ name) * 0x45d9f3b;
793 name = (name >> 16) ^ name;
803 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
804 assert(next_capacity > locals->
capacity);
807 if (next_locals == NULL) abort();
809 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
810 if (locals->
size > 0) {
816 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
817 uint32_t mask = next_capacity - 1;
819 for (uint32_t index = 0; index < locals->
capacity; index++) {
823 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
825 uint32_t hash = local->
hash;
827 next_locals[hash & mask] = *local;
832 pm_locals_free(locals);
833 locals->
locals = next_locals;
855 pm_locals_resize(locals);
858 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
859 for (uint32_t index = 0; index < locals->
capacity; index++) {
865 .location = { .start = start, .length = length },
866 .index = locals->
size++,
871 }
else if (local->
name == name) {
876 uint32_t mask = locals->
capacity - 1;
877 uint32_t hash = pm_locals_hash(name);
878 uint32_t initial_hash = hash;
886 .location = { .start = start, .length = length },
887 .index = locals->
size++,
892 }
else if (local->
name == name) {
897 }
while ((hash & mask) != initial_hash);
900 assert(
false &&
"unreachable");
910 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
911 for (uint32_t index = 0; index < locals->
size; index++) {
913 if (local->
name == name)
return index;
916 uint32_t mask = locals->
capacity - 1;
917 uint32_t hash = pm_locals_hash(name);
918 uint32_t initial_hash = hash & mask;
925 }
else if (local->
name == name) {
930 }
while ((hash & mask) != initial_hash);
942 uint32_t index = pm_locals_find(locals, name);
943 assert(index != UINT32_MAX);
946 assert(local->
reads < UINT32_MAX);
957 uint32_t index = pm_locals_find(locals, name);
958 assert(index != UINT32_MAX);
961 assert(local->
reads > 0);
971 uint32_t index = pm_locals_find(locals, name);
972 assert(index != UINT32_MAX);
987 pm_constant_id_list_init_capacity(parser->arena, list, locals->
size);
992 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
996 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
998 for (uint32_t index = 0; index < capacity; index++) {
1002 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
1004 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_line_offset_list_line(&parser->line_offsets, local->
location.
start, parser->start_line) >= 0))) {
1005 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
1007 if (constant->
length >= 1 && *constant->
start !=
'_') {
1008 PM_PARSER_WARN_FORMAT(
1012 PM_WARN_UNUSED_LOCAL_VARIABLE,
1014 (
const char *) constant->
start
1030pm_parser_constant_id_raw(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1031 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
1038pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1039 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1046pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1047 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1055 return pm_parser_constant_id_raw(parser, token->start, token->end);
1062#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1063 case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1074 while (node != NULL) {
1075 switch (PM_NODE_TYPE(node)) {
1076 case PM_CASE_VOID_VALUE:
1077 return void_node != NULL ? void_node : node;
1078 case PM_MATCH_PREDICATE_NODE:
1080 case PM_BEGIN_NODE: {
1086 if (vn != NULL)
return vn;
1091 if (vn != NULL)
return vn;
1101 if (vn == NULL)
return NULL;
1102 if (void_node == NULL) void_node = vn;
1106 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1123 pm_node_t *vn = pm_check_value_expression(parser, node);
1124 if (vn != NULL)
return vn;
1135 case PM_CASE_NODE: {
1146 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1150 if (vn == NULL)
return NULL;
1151 if (void_node == NULL) void_node = vn;
1154 node = UP(cast->else_clause);
1157 case PM_CASE_MATCH_NODE: {
1168 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1172 if (vn == NULL)
return NULL;
1173 if (void_node == NULL) void_node = vn;
1176 node = UP(cast->else_clause);
1179 case PM_ENSURE_NODE: {
1184 case PM_PARENTHESES_NODE: {
1186 node = UP(cast->
body);
1189 case PM_STATEMENTS_NODE: {
1196 switch (PM_NODE_TYPE(body_part)) {
1197 case PM_CASE_VOID_VALUE:
1198 if (void_node == NULL) {
1199 void_node = body_part;
1219 if (void_node == NULL) {
1225 case PM_UNLESS_NODE: {
1234 if (void_node == NULL) {
1240 case PM_ELSE_NODE: {
1255 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1259 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1274 pm_node_t *void_node = pm_check_value_expression(parser, node);
1275 if (void_node != NULL) {
1276 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1285 const char *
type = NULL;
1288 switch (PM_NODE_TYPE(node)) {
1289 case PM_BACK_REFERENCE_READ_NODE:
1290 case PM_CLASS_VARIABLE_READ_NODE:
1291 case PM_GLOBAL_VARIABLE_READ_NODE:
1292 case PM_INSTANCE_VARIABLE_READ_NODE:
1293 case PM_LOCAL_VARIABLE_READ_NODE:
1294 case PM_NUMBERED_REFERENCE_READ_NODE:
1295 type =
"a variable";
1298 case PM_CALL_NODE: {
1303 switch (message->
length) {
1305 switch (message->
start[0]) {
1322 switch (message->
start[1]) {
1324 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1330 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1336 if (message->
start[0] ==
'*') {
1344 if (memcmp(message->
start,
"<=>", 3) == 0) {
1353 case PM_CONSTANT_PATH_NODE:
1357 case PM_CONSTANT_READ_NODE:
1358 type =
"a constant";
1361 case PM_DEFINED_NODE:
1370 case PM_IMAGINARY_NODE:
1371 case PM_INTEGER_NODE:
1372 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1373 case PM_INTERPOLATED_STRING_NODE:
1374 case PM_RATIONAL_NODE:
1375 case PM_REGULAR_EXPRESSION_NODE:
1376 case PM_SOURCE_ENCODING_NODE:
1377 case PM_SOURCE_FILE_NODE:
1378 case PM_SOURCE_LINE_NODE:
1379 case PM_STRING_NODE:
1380 case PM_SYMBOL_NODE:
1388 case PM_RANGE_NODE: {
1391 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1414 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1425 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1426 for (
size_t index = 0; index < size; index++) {
1427 pm_void_statement_check(parser, node->
body.
nodes[index]);
1437 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1438 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1439 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1440} pm_conditional_predicate_type_t;
1448 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1449 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1451 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1452 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1454 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1464pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1465 switch (PM_NODE_TYPE(node)) {
1466 case PM_ARRAY_NODE: {
1467 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1470 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1471 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1476 case PM_HASH_NODE: {
1477 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1480 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1482 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1485 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1492 case PM_IMAGINARY_NODE:
1493 case PM_INTEGER_NODE:
1495 case PM_RATIONAL_NODE:
1496 case PM_REGULAR_EXPRESSION_NODE:
1497 case PM_SOURCE_ENCODING_NODE:
1498 case PM_SOURCE_FILE_NODE:
1499 case PM_SOURCE_LINE_NODE:
1500 case PM_STRING_NODE:
1501 case PM_SYMBOL_NODE:
1515 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1534 switch (PM_NODE_TYPE(node)) {
1537 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1538 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1543 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1544 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1547 case PM_PARENTHESES_NODE: {
1550 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1552 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1557 case PM_BEGIN_NODE: {
1565 case PM_RANGE_NODE: {
1568 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1569 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1577 node->
type = PM_FLIP_FLOP_NODE;
1581 case PM_REGULAR_EXPRESSION_NODE:
1586 node->
type = PM_MATCH_LAST_LINE_NODE;
1588 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1589 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1593 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1598 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1600 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1601 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1605 case PM_INTEGER_NODE:
1606 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1607 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1608 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1611 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1614 case PM_STRING_NODE:
1615 case PM_SOURCE_FILE_NODE:
1616 case PM_INTERPOLATED_STRING_NODE:
1617 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1619 case PM_SYMBOL_NODE:
1620 case PM_INTERPOLATED_SYMBOL_NODE:
1621 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1623 case PM_SOURCE_LINE_NODE:
1624 case PM_SOURCE_ENCODING_NODE:
1626 case PM_RATIONAL_NODE:
1627 case PM_IMAGINARY_NODE:
1628 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1630 case PM_CLASS_VARIABLE_WRITE_NODE:
1633 case PM_CONSTANT_WRITE_NODE:
1636 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1639 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1642 case PM_LOCAL_VARIABLE_WRITE_NODE:
1645 case PM_MULTI_WRITE_NODE:
1681 if (arguments->
block != NULL) {
1682 uint32_t end = PM_NODE_END(arguments->
block);
1685 uint32_t arguments_end = PM_LOCATION_END(&arguments->
closing_loc);
1686 if (arguments_end > end) {
1729 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1743char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1744 if (n <= 0)
return 0;
1751 }
else if (*b ==
'_') {
1753 }
else if (*b >= 0x80) {
1758 }
else if (*b < 0x80) {
1761 return pm_encoding_utf_8_char_width(b, n);
1770char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1773 }
else if (*b < 0x80) {
1776 return pm_encoding_utf_8_char_width(b, n);
1786char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1794 }
else if (*b ==
'_') {
1796 }
else if (*b >= 0x80) {
1802 return char_is_identifier_utf8(b, n);
1809#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1810#define PUNCT(idx) ( \
1811 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1812 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1813 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1814 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1815 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1818const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1824char_is_global_name_punctuation(const uint8_t b) {
1825 const unsigned int i = (const unsigned int) b;
1826 if (i <= 0x20 || 0x7e < i) return false;
1828 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1832token_is_setter_name(pm_token_t *token) {
1834 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1835 ((token->type == PM_TOKEN_IDENTIFIER) &&
1836 (token->end - token->start >= 2) &&
1837 (token->end[-1] == '='))
1845pm_local_is_keyword(const char *source, size_t length) {
1846#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1850 switch (source[0]) {
1851 case 'd': KEYWORD("do"); return false;
1852 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1853 case 'o': KEYWORD("or"); return false;
1854 default: return false;
1857 switch (source[0]) {
1858 case 'a': KEYWORD("and"); return false;
1859 case 'd': KEYWORD("def"); return false;
1860 case 'e': KEYWORD("end"); return false;
1861 case 'f': KEYWORD("for"); return false;
1862 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1863 default: return false;
1866 switch (source[0]) {
1867 case 'c': KEYWORD("case"); return false;
1868 case 'e': KEYWORD("else"); return false;
1869 case 'n': KEYWORD("next"); return false;
1870 case 'r': KEYWORD("redo"); return false;
1871 case 's': KEYWORD("self"); return false;
1872 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1873 case 'w': KEYWORD("when"); return false;
1874 default: return false;
1877 switch (source[0]) {
1878 case 'a': KEYWORD("alias"); return false;
1879 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1880 case 'c': KEYWORD("class"); return false;
1881 case 'e': KEYWORD("elsif"); return false;
1882 case 'f': KEYWORD("false"); return false;
1883 case 'r': KEYWORD("retry"); return false;
1884 case 's': KEYWORD("super"); return false;
1885 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1886 case 'w': KEYWORD("while"); return false;
1887 case 'y': KEYWORD("yield"); return false;
1888 default: return false;
1891 switch (source[0]) {
1892 case 'e': KEYWORD("ensure"); return false;
1893 case 'm': KEYWORD("module"); return false;
1894 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1895 case 'u': KEYWORD("unless"); return false;
1896 default: return false;
1899 KEYWORD("__LINE__");
1900 KEYWORD("__FILE__");
1903 KEYWORD("__ENCODING__");
1912/******************************************************************************/
1913/* Node flag handling functions */
1914/******************************************************************************/
1920pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1921 node->flags |= flag;
1928pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1929 node->flags &= (pm_node_flags_t) ~flag;
1936pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1937 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1938 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1939 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1940 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1941 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1942 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1943 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1944 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1946 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1949/******************************************************************************/
1950/* Node creation functions */
1951/******************************************************************************/
1958#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
1963static inline pm_node_flags_t
1964pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1965 pm_node_flags_t flags = 0;
1967 if (closing->type == PM_TOKEN_REGEXP_END) {
1968 pm_buffer_t unknown_flags = { 0 };
1970 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1972 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1973 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1974 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1975 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1977 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1978 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1979 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1980 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1982 default: pm_buffer_append_byte(&unknown_flags, *flag);
1986 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1987 if (unknown_flags_length != 0) {
1988 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1989 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1991 pm_buffer_free(&unknown_flags);
1997#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1999static pm_statements_node_t *
2000pm_statements_node_create(pm_parser_t *parser);
2003pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
2006pm_statements_node_body_length(pm_statements_node_t *node);
2013pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
2014 if (integer->values != NULL) {
2015 size_t byte_size = integer->length * sizeof(uint32_t);
2016 uint32_t *old_values = integer->values;
2017 integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
2025static pm_missing_node_t *
2026pm_missing_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
2027 return pm_missing_node_new(
2031 ((pm_location_t) { .start = start, .length = length })
2038static pm_alias_global_variable_node_t *
2039pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2040 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2042 return pm_alias_global_variable_node_new(
2046 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2049 TOK2LOC(parser, keyword)
2056static pm_alias_method_node_t *
2057pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2058 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2060 return pm_alias_method_node_new(
2064 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2067 TOK2LOC(parser, keyword)
2074static pm_alternation_pattern_node_t *
2075pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2076 return pm_alternation_pattern_node_new(
2080 PM_LOCATION_INIT_NODES(left, right),
2083 TOK2LOC(parser, operator)
2090static pm_and_node_t *
2091pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2092 pm_assert_value_expression(parser, left);
2094 return pm_and_node_new(
2098 PM_LOCATION_INIT_NODES(left, right),
2101 TOK2LOC(parser, operator)
2108static pm_arguments_node_t *
2109pm_arguments_node_create(pm_parser_t *parser) {
2110 return pm_arguments_node_new(
2114 PM_LOCATION_INIT_UNSET,
2115 ((pm_node_list_t) { 0 })
2123pm_arguments_node_size(pm_arguments_node_t *node) {
2124 return node->arguments.size;
2131pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
2132 if (pm_arguments_node_size(node) == 0) {
2133 PM_NODE_START_SET_NODE(node, argument);
2136 if (PM_NODE_END(node) < PM_NODE_END(argument)) {
2137 PM_NODE_LENGTH_SET_NODE(node, argument);
2140 pm_node_list_append(arena, &node->arguments, argument);
2142 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2143 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2144 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2146 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2154static pm_array_node_t *
2155pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2156 if (opening == NULL) {
2157 return pm_array_node_new(
2160 PM_NODE_FLAG_STATIC_LITERAL,
2161 PM_LOCATION_INIT_UNSET,
2162 ((pm_node_list_t) { 0 }),
2163 ((pm_location_t) { 0 }),
2164 ((pm_location_t) { 0 })
2167 return pm_array_node_new(
2170 PM_NODE_FLAG_STATIC_LITERAL,
2171 PM_LOCATION_INIT_TOKEN(parser, opening),
2172 ((pm_node_list_t) { 0 }),
2173 TOK2LOC(parser, opening),
2174 TOK2LOC(parser, opening)
2183pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
2184 if (!node->elements.size && !node->opening_loc.length) {
2185 PM_NODE_START_SET_NODE(node, element);
2188 pm_node_list_append(arena, &node->elements, element);
2189 PM_NODE_LENGTH_SET_NODE(node, element);
2191 // If the element is not a static literal, then the array is not a static
2192 // literal. Turn that flag off.
2193 if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) {
2194 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2197 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2198 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2206pm_array_node_close_set(const pm_parser_t *parser, pm_array_node_t *node, const pm_token_t *closing) {
2207 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == 0);
2208 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2209 node->closing_loc = TOK2LOC(parser, closing);
2216static pm_array_pattern_node_t *
2217pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2218 pm_array_pattern_node_t *node = pm_array_pattern_node_new(
2222 PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2224 ((pm_node_list_t) { 0 }),
2226 ((pm_node_list_t) { 0 }),
2227 ((pm_location_t) { 0 }),
2228 ((pm_location_t) { 0 })
2231 // For now we're going to just copy over each pointer manually. This could be
2232 // much more efficient, as we could instead resize the node list.
2233 bool found_rest = false;
2236 PM_NODE_LIST_FOREACH(nodes, index, child) {
2237 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2240 } else if (found_rest) {
2241 pm_node_list_append(parser->arena, &node->posts, child);
2243 pm_node_list_append(parser->arena, &node->requireds, child);
2253static pm_array_pattern_node_t *
2254pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2255 return pm_array_pattern_node_new(
2259 PM_LOCATION_INIT_NODE(rest),
2261 ((pm_node_list_t) { 0 }),
2263 ((pm_node_list_t) { 0 }),
2264 ((pm_location_t) { 0 }),
2265 ((pm_location_t) { 0 })
2273static pm_array_pattern_node_t *
2274pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2275 return pm_array_pattern_node_new(
2279 PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
2281 ((pm_node_list_t) { 0 }),
2283 ((pm_node_list_t) { 0 }),
2284 TOK2LOC(parser, opening),
2285 TOK2LOC(parser, closing)
2293static pm_array_pattern_node_t *
2294pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2295 return pm_array_pattern_node_new(
2299 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2301 ((pm_node_list_t) { 0 }),
2303 ((pm_node_list_t) { 0 }),
2304 TOK2LOC(parser, opening),
2305 TOK2LOC(parser, closing)
2310pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
2311 pm_node_list_append(arena, &node->requireds, inner);
2317static pm_assoc_node_t *
2318pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2321 if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
2322 end = PM_NODE_END(value);
2323 } else if (operator != NULL) {
2324 end = PM_TOKEN_END(parser, operator);
2326 end = PM_NODE_END(key);
2329 // Hash string keys will be frozen, so we can mark them as frozen here so
2330 // that the compiler picks them up and also when we check for static literal
2331 // on the keys it gets factored in.
2332 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2333 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2336 // If the key and value of this assoc node are both static literals, then
2337 // we can mark this node as a static literal.
2338 pm_node_flags_t flags = 0;
2340 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2341 value && !PM_NODE_TYPE_P(value, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(value, PM_HASH_NODE) && !PM_NODE_TYPE_P(value, PM_RANGE_NODE)
2343 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2346 return pm_assoc_node_new(
2350 ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
2353 NTOK2LOC(parser, operator)
2360static pm_assoc_splat_node_t *
2361pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2362 assert(operator->type == PM_TOKEN_USTAR_STAR);
2364 return pm_assoc_splat_node_new(
2368 (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
2370 TOK2LOC(parser, operator)
2377static pm_back_reference_read_node_t *
2378pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2379 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2381 return pm_back_reference_read_node_new(
2385 PM_LOCATION_INIT_TOKEN(parser, name),
2386 pm_parser_constant_id_token(parser, name)
2393static pm_begin_node_t *
2394pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2395 uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
2396 uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
2398 return pm_begin_node_new(
2402 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2403 NTOK2LOC(parser, begin_keyword),
2408 ((pm_location_t) { 0 })
2416pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2417 if (node->begin_keyword_loc.length == 0) {
2418 PM_NODE_START_SET_NODE(node, rescue_clause);
2420 PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
2421 node->rescue_clause = rescue_clause;
2428pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2429 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2430 PM_NODE_START_SET_NODE(node, else_clause);
2432 PM_NODE_LENGTH_SET_NODE(node, else_clause);
2433 node->else_clause = else_clause;
2440pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2441 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2442 PM_NODE_START_SET_NODE(node, ensure_clause);
2444 PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
2445 node->ensure_clause = ensure_clause;
2452pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
2453 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
2454 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
2455 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
2461static pm_block_argument_node_t *
2462pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2463 assert(operator->type == PM_TOKEN_UAMPERSAND);
2465 return pm_block_argument_node_new(
2469 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
2471 TOK2LOC(parser, operator)
2478static pm_block_node_t *
2479pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
2480 return pm_block_node_new(
2484 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2488 TOK2LOC(parser, opening),
2489 TOK2LOC(parser, closing)
2496static pm_block_parameter_node_t *
2497pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2498 assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2500 return pm_block_parameter_node_new(
2504 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
2505 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
2506 NTOK2LOC(parser, name),
2507 TOK2LOC(parser, operator)
2514static pm_block_parameters_node_t *
2515pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2517 if (opening != NULL) {
2518 start = PM_TOKEN_START(parser, opening);
2519 } else if (parameters != NULL) {
2520 start = PM_NODE_START(parameters);
2526 if (parameters != NULL) {
2527 end = PM_NODE_END(parameters);
2528 } else if (opening != NULL) {
2529 end = PM_TOKEN_END(parser, opening);
2534 return pm_block_parameters_node_new(
2538 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2540 ((pm_node_list_t) { 0 }),
2541 NTOK2LOC(parser, opening),
2542 ((pm_location_t) { 0 })
2550pm_block_parameters_node_closing_set(const pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_token_t *closing) {
2551 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == 0);
2552 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2553 node->closing_loc = TOK2LOC(parser, closing);
2559static pm_block_local_variable_node_t *
2560pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2561 return pm_block_local_variable_node_new(
2565 PM_LOCATION_INIT_TOKEN(parser, name),
2566 pm_parser_constant_id_token(parser, name)
2574pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2575 pm_node_list_append(arena, &node->locals, UP(local));
2577 if (PM_NODE_LENGTH(node) == 0) {
2578 PM_NODE_START_SET_NODE(node, local);
2581 PM_NODE_LENGTH_SET_NODE(node, local);
2587static pm_break_node_t *
2588pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2589 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2591 return pm_break_node_new(
2595 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
2597 TOK2LOC(parser, keyword)
2601// There are certain flags that we want to use internally but don't want to
2602// expose because they are not relevant beyond parsing. Therefore we'll define
2603// them here and not define them in config.yml/a header file.
2604static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2606static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2607static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2608static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2615static pm_call_node_t *
2616pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2617 return pm_call_node_new(
2621 PM_LOCATION_INIT_UNSET,
2623 ((pm_location_t) { 0 }),
2625 ((pm_location_t) { 0 }),
2626 ((pm_location_t) { 0 }),
2628 ((pm_location_t) { 0 }),
2629 ((pm_location_t) { 0 }),
2638static inline pm_node_flags_t
2639pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2640 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2647static pm_call_node_t *
2648pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2649 pm_assert_value_expression(parser, receiver);
2651 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2652 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2653 flags |= PM_CALL_NODE_FLAGS_INDEX;
2656 pm_call_node_t *node = pm_call_node_create(parser, flags);
2658 PM_NODE_START_SET_NODE(node, receiver);
2660 const pm_location_t *end = pm_arguments_end(arguments);
2661 assert(end != NULL && "unreachable");
2662 PM_NODE_LENGTH_SET_LOCATION(node, end);
2664 node->receiver = receiver;
2665 node->message_loc.start = arguments->opening_loc.start;
2666 node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
2668 node->opening_loc = arguments->opening_loc;
2669 node->arguments = arguments->arguments;
2670 node->closing_loc = arguments->closing_loc;
2671 node->block = arguments->block;
2673 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2680static pm_call_node_t *
2681pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_node_t *argument, pm_node_flags_t flags) {
2682 pm_assert_value_expression(parser, receiver);
2683 pm_assert_value_expression(parser, argument);
2685 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2687 PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
2688 PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
2690 node->receiver = receiver;
2691 node->message_loc = TOK2LOC(parser, operator);
2693 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2694 pm_arguments_node_arguments_append(parser->arena, arguments, argument);
2695 node->arguments = arguments;
2697 node->name = pm_parser_constant_id_token(parser, operator);
2701static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
2706static pm_call_node_t *
2707pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2708 pm_assert_value_expression(parser, receiver);
2710 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2712 PM_NODE_START_SET_NODE(node, receiver);
2713 const pm_location_t *end = pm_arguments_end(arguments);
2715 PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
2717 PM_NODE_LENGTH_SET_LOCATION(node, end);
2720 node->receiver = receiver;
2721 node->call_operator_loc = TOK2LOC(parser, operator);
2722 node->message_loc = TOK2LOC(parser, message);
2723 node->opening_loc = arguments->opening_loc;
2724 node->arguments = arguments->arguments;
2725 node->closing_loc = arguments->closing_loc;
2726 node->block = arguments->block;
2728 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2729 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2736 node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
2743static pm_call_node_t *
2744pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2745 pm_call_node_t *node = pm_call_node_create(parser, 0);
2746 node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
2748 node->receiver = receiver;
2749 node->arguments = arguments;
2751 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2759static pm_call_node_t *
2760pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2761 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2763 PM_NODE_START_SET_TOKEN(parser, node, message);
2764 const pm_location_t *end = pm_arguments_end(arguments);
2765 assert(end != NULL && "unreachable");
2766 PM_NODE_LENGTH_SET_LOCATION(node, end);
2768 node->message_loc = TOK2LOC(parser, message);
2769 node->opening_loc = arguments->opening_loc;
2770 node->arguments = arguments->arguments;
2771 node->closing_loc = arguments->closing_loc;
2772 node->block = arguments->block;
2774 node->name = pm_parser_constant_id_token(parser, message);
2782static pm_call_node_t *
2783pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2784 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2786 node->base.location = (pm_location_t) { 0 };
2787 node->arguments = arguments;
2796static pm_call_node_t *
2797pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2798 pm_assert_value_expression(parser, receiver);
2799 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2801 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2803 PM_NODE_START_SET_TOKEN(parser, node, message);
2804 if (arguments->closing_loc.length > 0) {
2805 PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
2807 assert(receiver != NULL);
2808 PM_NODE_LENGTH_SET_NODE(node, receiver);
2811 node->receiver = receiver;
2812 node->message_loc = TOK2LOC(parser, message);
2813 node->opening_loc = arguments->opening_loc;
2814 node->arguments = arguments->arguments;
2815 node->closing_loc = arguments->closing_loc;
2817 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2824static pm_call_node_t *
2825pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2826 pm_assert_value_expression(parser, receiver);
2828 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2830 PM_NODE_START_SET_NODE(node, receiver);
2831 const pm_location_t *end = pm_arguments_end(arguments);
2832 assert(end != NULL && "unreachable");
2833 PM_NODE_LENGTH_SET_LOCATION(node, end);
2835 node->receiver = receiver;
2836 node->call_operator_loc = TOK2LOC(parser, operator);
2837 node->opening_loc = arguments->opening_loc;
2838 node->arguments = arguments->arguments;
2839 node->closing_loc = arguments->closing_loc;
2840 node->block = arguments->block;
2842 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2843 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2846 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2853static pm_call_node_t *
2854pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2855 pm_assert_value_expression(parser, receiver);
2857 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2859 PM_NODE_START_SET_TOKEN(parser, node, operator);
2860 PM_NODE_LENGTH_SET_NODE(node, receiver);
2862 node->receiver = receiver;
2863 node->message_loc = TOK2LOC(parser, operator);
2865 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2873static pm_call_node_t *
2874pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2875 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2877 node->base.location = TOK2LOC(parser, message);
2878 node->message_loc = TOK2LOC(parser, message);
2880 node->name = pm_parser_constant_id_token(parser, message);
2889pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2891 (node->message_loc.length > 0) &&
2892 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
2893 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
2894 char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
2895 (node->opening_loc.length == 0) &&
2896 (node->arguments == NULL) &&
2897 (node->block == NULL)
2905pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2906 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2908 if (write_constant->length > 0) {
2909 size_t length = write_constant->length - 1;
2911 void *memory = xmalloc(length);
2912 memcpy(memory, write_constant->start, length);
2914 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2916 // We can get here if the message was missing because of a syntax error.
2917 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2924static pm_call_and_write_node_t *
2925pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2926 assert(target->block == NULL);
2927 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2929 pm_call_and_write_node_t *node = pm_call_and_write_node_new(
2933 PM_LOCATION_INIT_NODES(target, value),
2935 target->call_operator_loc,
2936 target->message_loc,
2939 TOK2LOC(parser, operator),
2943 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2945 // The target is no longer necessary because we've reused its children.
2946 // It is arena-allocated so no explicit free is needed.
2956pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2957 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2958 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2960 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2961 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2962 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2968 if (block != NULL) {
2969 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2977static pm_index_and_write_node_t *
2978pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2979 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2981 pm_index_arguments_check(parser, target->arguments, target->block);
2983 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2985 pm_index_and_write_node_t *node = pm_index_and_write_node_new(
2989 PM_LOCATION_INIT_NODES(target, value),
2991 target->call_operator_loc,
2992 target->opening_loc,
2994 target->closing_loc,
2995 (pm_block_argument_node_t *) target->block,
2996 TOK2LOC(parser, operator),
3000 // The target is no longer necessary because we've reused its children.
3001 // It is arena-allocated so no explicit free is needed.
3009static pm_call_operator_write_node_t *
3010pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3011 assert(target->block == NULL);
3013 pm_call_operator_write_node_t *node = pm_call_operator_write_node_new(
3017 PM_LOCATION_INIT_NODES(target, value),
3019 target->call_operator_loc,
3020 target->message_loc,
3023 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3024 TOK2LOC(parser, operator),
3028 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3030 // The target is no longer necessary because we've reused its children.
3031 // It is arena-allocated so no explicit free is needed.
3039static pm_index_operator_write_node_t *
3040pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3041 pm_index_arguments_check(parser, target->arguments, target->block);
3043 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3045 pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
3049 PM_LOCATION_INIT_NODES(target, value),
3051 target->call_operator_loc,
3052 target->opening_loc,
3054 target->closing_loc,
3055 (pm_block_argument_node_t *) target->block,
3056 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3057 TOK2LOC(parser, operator),
3061 // The target is no longer necessary because we've reused its children.
3062 // It is arena-allocated so no explicit free is needed.
3070static pm_call_or_write_node_t *
3071pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3072 assert(target->block == NULL);
3073 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3075 pm_call_or_write_node_t *node = pm_call_or_write_node_new(
3079 PM_LOCATION_INIT_NODES(target, value),
3081 target->call_operator_loc,
3082 target->message_loc,
3085 TOK2LOC(parser, operator),
3089 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3091 // The target is no longer necessary because we've reused its children.
3092 // It is arena-allocated so no explicit free is needed.
3100static pm_index_or_write_node_t *
3101pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3102 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3104 pm_index_arguments_check(parser, target->arguments, target->block);
3106 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3108 pm_index_or_write_node_t *node = pm_index_or_write_node_new(
3112 PM_LOCATION_INIT_NODES(target, value),
3114 target->call_operator_loc,
3115 target->opening_loc,
3117 target->closing_loc,
3118 (pm_block_argument_node_t *) target->block,
3119 TOK2LOC(parser, operator),
3123 // The target is no longer necessary because we've reused its children.
3124 // It is arena-allocated so no explicit free is needed.
3133static pm_call_target_node_t *
3134pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3135 pm_call_target_node_t *node = pm_call_target_node_new(
3139 PM_LOCATION_INIT_NODE(target),
3141 target->call_operator_loc,
3146 /* It is possible to get here where we have parsed an invalid syntax tree
3147 * where the call operator was not present. In that case we will have a
3148 * problem because it is a required location. In this case we need to fill
3149 * it in with a fake location so that the syntax tree remains valid. */
3150 if (node->call_operator_loc.length == 0) {
3151 node->call_operator_loc = target->base.location;
3154 // The target is no longer necessary because we've reused its children.
3155 // It is arena-allocated so no explicit free is needed.
3164static pm_index_target_node_t *
3165pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3166 pm_index_arguments_check(parser, target->arguments, target->block);
3167 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3169 pm_index_target_node_t *node = pm_index_target_node_new(
3172 FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3173 PM_LOCATION_INIT_NODE(target),
3175 target->opening_loc,
3177 target->closing_loc,
3178 (pm_block_argument_node_t *) target->block
3181 // The target is no longer necessary because we've reused its children.
3182 // It is arena-allocated so no explicit free is needed.
3190static pm_capture_pattern_node_t *
3191pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3192 return pm_capture_pattern_node_new(
3196 PM_LOCATION_INIT_NODES(value, target),
3199 TOK2LOC(parser, operator)
3206static pm_case_node_t *
3207pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3208 return pm_case_node_new(
3212 PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
3214 ((pm_node_list_t) { 0 }),
3216 TOK2LOC(parser, case_keyword),
3217 NTOK2LOC(parser, end_keyword)
3225pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
3226 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3228 pm_node_list_append(arena, &node->conditions, condition);
3229 PM_NODE_LENGTH_SET_NODE(node, condition);
3236pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3237 node->else_clause = else_clause;
3238 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3245pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
3246 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3247 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3253static pm_case_match_node_t *
3254pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
3255 return pm_case_match_node_new(
3259 PM_LOCATION_INIT_TOKEN(parser, case_keyword),
3261 ((pm_node_list_t) { 0 }),
3263 TOK2LOC(parser, case_keyword),
3264 ((pm_location_t) { 0 })
3272pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
3273 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3275 pm_node_list_append(arena, &node->conditions, condition);
3276 PM_NODE_LENGTH_SET_NODE(node, condition);
3283pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3284 node->else_clause = else_clause;
3285 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3292pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3293 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3294 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3300static pm_class_node_t *
3301pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, pm_node_t *constant_path, const pm_token_t *name, const pm_token_t *inheritance_operator, pm_node_t *superclass, pm_node_t *body, const pm_token_t *end_keyword) {
3302 return pm_class_node_new(
3306 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
3308 TOK2LOC(parser, class_keyword),
3310 NTOK2LOC(parser, inheritance_operator),
3313 TOK2LOC(parser, end_keyword),
3314 pm_parser_constant_id_token(parser, name)
3321static pm_class_variable_and_write_node_t *
3322pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3323 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3325 return pm_class_variable_and_write_node_new(
3329 PM_LOCATION_INIT_NODES(target, value),
3331 target->base.location,
3332 TOK2LOC(parser, operator),
3340static pm_class_variable_operator_write_node_t *
3341pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3342 return pm_class_variable_operator_write_node_new(
3346 PM_LOCATION_INIT_NODES(target, value),
3348 target->base.location,
3349 TOK2LOC(parser, operator),
3351 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3358static pm_class_variable_or_write_node_t *
3359pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3360 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3362 return pm_class_variable_or_write_node_new(
3366 PM_LOCATION_INIT_NODES(target, value),
3368 target->base.location,
3369 TOK2LOC(parser, operator),
3377static pm_class_variable_read_node_t *
3378pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3379 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3381 return pm_class_variable_read_node_new(
3385 PM_LOCATION_INIT_TOKEN(parser, token),
3386 pm_parser_constant_id_token(parser, token)
3396static inline pm_node_flags_t
3397pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3398 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
3407static pm_class_variable_write_node_t *
3408pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
3409 return pm_class_variable_write_node_new(
3412 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3413 PM_LOCATION_INIT_NODES(read_node, value),
3415 read_node->base.location,
3417 TOK2LOC(parser, operator)
3424static pm_constant_path_and_write_node_t *
3425pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3426 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3428 return pm_constant_path_and_write_node_new(
3432 PM_LOCATION_INIT_NODES(target, value),
3434 TOK2LOC(parser, operator),
3442static pm_constant_path_operator_write_node_t *
3443pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3444 return pm_constant_path_operator_write_node_new(
3448 PM_LOCATION_INIT_NODES(target, value),
3450 TOK2LOC(parser, operator),
3452 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3459static pm_constant_path_or_write_node_t *
3460pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3461 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3463 return pm_constant_path_or_write_node_new(
3467 PM_LOCATION_INIT_NODES(target, value),
3469 TOK2LOC(parser, operator),
3477static pm_constant_path_node_t *
3478pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3479 pm_assert_value_expression(parser, parent);
3481 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3482 if (name_token->type == PM_TOKEN_CONSTANT) {
3483 name = pm_parser_constant_id_token(parser, name_token);
3486 return pm_constant_path_node_new(
3490 (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
3493 TOK2LOC(parser, delimiter),
3494 TOK2LOC(parser, name_token)
3501static pm_constant_path_write_node_t *
3502pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3503 return pm_constant_path_write_node_new(
3506 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3507 PM_LOCATION_INIT_NODES(target, value),
3509 TOK2LOC(parser, operator),
3517static pm_constant_and_write_node_t *
3518pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3519 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3521 return pm_constant_and_write_node_new(
3525 PM_LOCATION_INIT_NODES(target, value),
3527 target->base.location,
3528 TOK2LOC(parser, operator),
3536static pm_constant_operator_write_node_t *
3537pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3538 return pm_constant_operator_write_node_new(
3542 PM_LOCATION_INIT_NODES(target, value),
3544 target->base.location,
3545 TOK2LOC(parser, operator),
3547 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3554static pm_constant_or_write_node_t *
3555pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3556 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3558 return pm_constant_or_write_node_new(
3562 PM_LOCATION_INIT_NODES(target, value),
3564 target->base.location,
3565 TOK2LOC(parser, operator),
3573static pm_constant_read_node_t *
3574pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3575 assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
3577 return pm_constant_read_node_new(
3581 PM_LOCATION_INIT_TOKEN(parser, name),
3582 pm_parser_constant_id_token(parser, name)
3589static pm_constant_write_node_t *
3590pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3591 return pm_constant_write_node_new(
3594 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3595 PM_LOCATION_INIT_NODES(target, value),
3597 target->base.location,
3599 TOK2LOC(parser, operator)
3607pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3608 switch (PM_NODE_TYPE(node)) {
3609 case PM_BEGIN_NODE: {
3610 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3611 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3614 case PM_PARENTHESES_NODE: {
3615 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3616 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3619 case PM_STATEMENTS_NODE: {
3620 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3621 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3626 case PM_IMAGINARY_NODE:
3627 case PM_INTEGER_NODE:
3628 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3629 case PM_INTERPOLATED_STRING_NODE:
3630 case PM_INTERPOLATED_SYMBOL_NODE:
3631 case PM_INTERPOLATED_X_STRING_NODE:
3632 case PM_RATIONAL_NODE:
3633 case PM_REGULAR_EXPRESSION_NODE:
3634 case PM_SOURCE_ENCODING_NODE:
3635 case PM_SOURCE_FILE_NODE:
3636 case PM_SOURCE_LINE_NODE:
3637 case PM_STRING_NODE:
3638 case PM_SYMBOL_NODE:
3639 case PM_X_STRING_NODE:
3640 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3650static pm_def_node_t *
3652 pm_parser_t *parser,
3653 pm_constant_id_t name,
3654 const pm_token_t *name_loc,
3655 pm_node_t *receiver,
3656 pm_parameters_node_t *parameters,
3658 pm_constant_id_list_t *locals,
3659 const pm_token_t *def_keyword,
3660 const pm_token_t *operator,
3661 const pm_token_t *lparen,
3662 const pm_token_t *rparen,
3663 const pm_token_t *equal,
3664 const pm_token_t *end_keyword
3666 if (receiver != NULL) {
3667 pm_def_node_receiver_check(parser, receiver);
3670 return pm_def_node_new(
3674 (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
3676 TOK2LOC(parser, name_loc),
3681 TOK2LOC(parser, def_keyword),
3682 NTOK2LOC(parser, operator),
3683 NTOK2LOC(parser, lparen),
3684 NTOK2LOC(parser, rparen),
3685 NTOK2LOC(parser, equal),
3686 NTOK2LOC(parser, end_keyword)
3693static pm_defined_node_t *
3694pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_token_t *keyword) {
3695 return pm_defined_node_new(
3699 (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
3700 NTOK2LOC(parser, lparen),
3702 NTOK2LOC(parser, rparen),
3703 TOK2LOC(parser, keyword)
3710static pm_else_node_t *
3711pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3712 return pm_else_node_new(
3716 ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
3717 TOK2LOC(parser, else_keyword),
3719 NTOK2LOC(parser, end_keyword)
3726static pm_embedded_statements_node_t *
3727pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3728 return pm_embedded_statements_node_new(
3732 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
3733 TOK2LOC(parser, opening),
3735 TOK2LOC(parser, closing)
3742static pm_embedded_variable_node_t *
3743pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3744 return pm_embedded_variable_node_new(
3748 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
3749 TOK2LOC(parser, operator),
3757static pm_ensure_node_t *
3758pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3759 return pm_ensure_node_new(
3763 PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
3764 TOK2LOC(parser, ensure_keyword),
3766 TOK2LOC(parser, end_keyword)
3773static pm_false_node_t *
3774pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
3775 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
3777 return pm_false_node_new(
3780 PM_NODE_FLAG_STATIC_LITERAL,
3781 PM_LOCATION_INIT_TOKEN(parser, token)
3789static pm_find_pattern_node_t *
3790pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
3791 pm_node_t *left = nodes->nodes[0];
3792 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
3793 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
3797 if (nodes->size == 1) {
3798 right = UP(pm_missing_node_create(parser, PM_NODE_END(left), 0));
3800 right = nodes->nodes[nodes->size - 1];
3801 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
3804#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
3805 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
3806 // The resulting AST will anyway be ignored, but this file still needs to compile.
3807 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
3809 pm_node_t *right_splat_node = right;
3812 pm_find_pattern_node_t *node = pm_find_pattern_node_new(
3816 PM_LOCATION_INIT_NODES(left, right),
3819 ((pm_node_list_t) { 0 }),
3821 ((pm_location_t) { 0 }),
3822 ((pm_location_t) { 0 })
3825 // For now we're going to just copy over each pointer manually. This could be
3826 // much more efficient, as we could instead resize the node list to only point
3828 for (size_t index = 1; index < nodes->size - 1; index++) {
3829 pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
3840pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
3841 ptrdiff_t diff = token->end - token->start;
3842 if (diff <= 0) return 0.0;
3844 // First, get a buffer of the content.
3845 size_t length = (size_t) diff;
3846 const size_t buffer_size = sizeof(char) * (length + 1);
3847 char *buffer = xmalloc(buffer_size);
3848 memcpy((void *) buffer, token->start, length);
3850 // Next, determine if we need to replace the decimal point because of
3851 // locale-specific options, and then normalize them if we have to.
3852 char decimal_point = *localeconv()->decimal_point;
3853 if (decimal_point != '.') {
3854 for (size_t index = 0; index < length; index++) {
3855 if (buffer[index] == '.') buffer[index] = decimal_point;
3859 // Next, handle underscores by removing them from the buffer.
3860 for (size_t index = 0; index < length; index++) {
3861 if (buffer[index] == '_') {
3862 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
3867 // Null-terminate the buffer so that strtod cannot read off the end.
3868 buffer[length] = '\0';
3870 // Now, call strtod to parse the value. Note that CRuby has their own
3871 // version of strtod which avoids locales. We're okay using the locale-aware
3872 // version because we've already validated through the parser that the token
3873 // is in a valid format.
3876 double value = strtod(buffer, &eptr);
3878 // This should never happen, because we've already checked that the token
3879 // is in a valid format. However it's good to be safe.
3880 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
3881 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
3882 xfree_sized(buffer, buffer_size);
3886 // If errno is set, then it should only be ERANGE. At this point we need to
3887 // check if it's infinity (it should be).
3888 if (errno == ERANGE && PRISM_ISINF(value)) {
3890 const char *ellipsis;
3896 warn_width = (int) length;
3900 pm_diagnostic_list_append_format(&parser->warning_list, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
3901 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
3904 // Finally we can free the buffer and return the value.
3905 xfree_sized(buffer, buffer_size);
3912static pm_float_node_t *
3913pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
3914 assert(token->type == PM_TOKEN_FLOAT);
3916 return pm_float_node_new(
3919 PM_NODE_FLAG_STATIC_LITERAL,
3920 PM_LOCATION_INIT_TOKEN(parser, token),
3921 pm_double_parse(parser, token)
3928static pm_imaginary_node_t *
3929pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3930 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
3932 return pm_imaginary_node_new(
3935 PM_NODE_FLAG_STATIC_LITERAL,
3936 PM_LOCATION_INIT_TOKEN(parser, token),
3937 UP(pm_float_node_create(parser, &((pm_token_t) {
3938 .type = PM_TOKEN_FLOAT,
3939 .start = token->start,
3940 .end = token->end - 1
3948static pm_rational_node_t *
3949pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
3950 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
3952 pm_rational_node_t *node = pm_rational_node_new(
3955 PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
3956 PM_LOCATION_INIT_TOKEN(parser, token),
3957 ((pm_integer_t) { 0 }),
3958 ((pm_integer_t) { 0 })
3961 const uint8_t *start = token->start;
3962 const uint8_t *end = token->end - 1; // r
3964 while (start < end && *start == '0') start++; // 0.1 -> .1
3965 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
3967 size_t length = (size_t) (end - start);
3969 node->denominator.value = 1;
3973 const uint8_t *point = memchr(start, '.', length);
3974 assert(point && "should have a decimal point");
3976 uint8_t *digits = xmalloc(length);
3977 if (digits == NULL) {
3978 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
3982 memcpy(digits, start, (unsigned long) (point - start));
3983 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
3984 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
3986 size_t fract_length = 0;
3987 for (const uint8_t *fract = point; fract < end; ++fract) {
3988 if (*fract != '_') ++fract_length;
3991 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
3992 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
3993 xfree_sized(digits, length);
3995 pm_integers_reduce(&node->numerator, &node->denominator);
3996 pm_integer_arena_move(parser->arena, &node->numerator);
3997 pm_integer_arena_move(parser->arena, &node->denominator);
4005static pm_imaginary_node_t *
4006pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4007 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4009 return pm_imaginary_node_new(
4012 PM_NODE_FLAG_STATIC_LITERAL,
4013 PM_LOCATION_INIT_TOKEN(parser, token),
4014 UP(pm_float_node_rational_create(parser, &((pm_token_t) {
4015 .type = PM_TOKEN_FLOAT_RATIONAL,
4016 .start = token->start,
4017 .end = token->end - 1
4025static pm_for_node_t *
4027 pm_parser_t *parser,
4029 pm_node_t *collection,
4030 pm_statements_node_t *statements,
4031 const pm_token_t *for_keyword,
4032 const pm_token_t *in_keyword,
4033 const pm_token_t *do_keyword,
4034 const pm_token_t *end_keyword
4036 return pm_for_node_new(
4040 PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
4044 TOK2LOC(parser, for_keyword),
4045 TOK2LOC(parser, in_keyword),
4046 NTOK2LOC(parser, do_keyword),
4047 TOK2LOC(parser, end_keyword)
4054static pm_forwarding_arguments_node_t *
4055pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4056 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4058 return pm_forwarding_arguments_node_new(
4062 PM_LOCATION_INIT_TOKEN(parser, token)
4069static pm_forwarding_parameter_node_t *
4070pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4071 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4073 return pm_forwarding_parameter_node_new(
4077 PM_LOCATION_INIT_TOKEN(parser, token)
4084static pm_forwarding_super_node_t *
4085pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4086 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4087 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4089 pm_block_node_t *block = NULL;
4090 if (arguments->block != NULL) {
4091 block = (pm_block_node_t *) arguments->block;
4094 return pm_forwarding_super_node_new(
4098 (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
4107static pm_hash_pattern_node_t *
4108pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4109 return pm_hash_pattern_node_new(
4113 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4115 ((pm_node_list_t) { 0 }),
4117 TOK2LOC(parser, opening),
4118 TOK2LOC(parser, closing)
4125static pm_hash_pattern_node_t *
4126pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4130 if (elements->size > 0) {
4132 start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
4133 end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
4135 start = PM_NODE_START(elements->nodes[0]);
4136 end = PM_NODE_END(elements->nodes[elements->size - 1]);
4139 assert(rest != NULL);
4140 start = PM_NODE_START(rest);
4141 end = PM_NODE_END(rest);
4144 pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
4148 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4150 ((pm_node_list_t) { 0 }),
4152 ((pm_location_t) { 0 }),
4153 ((pm_location_t) { 0 })
4156 pm_node_list_concat(parser->arena, &node->elements, elements);
4163static pm_constant_id_t
4164pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4165 switch (PM_NODE_TYPE(target)) {
4166 case PM_GLOBAL_VARIABLE_READ_NODE:
4167 return ((pm_global_variable_read_node_t *) target)->name;
4168 case PM_BACK_REFERENCE_READ_NODE:
4169 return ((pm_back_reference_read_node_t *) target)->name;
4170 case PM_NUMBERED_REFERENCE_READ_NODE:
4171 // This will only ever happen in the event of a syntax error, but we
4172 // still need to provide something for the node.
4173 return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
4175 assert(false && "unreachable");
4176 return (pm_constant_id_t) -1;
4183static pm_global_variable_and_write_node_t *
4184pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4185 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4187 return pm_global_variable_and_write_node_new(
4191 PM_LOCATION_INIT_NODES(target, value),
4192 pm_global_variable_write_name(parser, target),
4194 TOK2LOC(parser, operator),
4202static pm_global_variable_operator_write_node_t *
4203pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4204 return pm_global_variable_operator_write_node_new(
4208 PM_LOCATION_INIT_NODES(target, value),
4209 pm_global_variable_write_name(parser, target),
4211 TOK2LOC(parser, operator),
4213 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4220static pm_global_variable_or_write_node_t *
4221pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4222 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4224 return pm_global_variable_or_write_node_new(
4228 PM_LOCATION_INIT_NODES(target, value),
4229 pm_global_variable_write_name(parser, target),
4231 TOK2LOC(parser, operator),
4239static pm_global_variable_read_node_t *
4240pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4241 return pm_global_variable_read_node_new(
4245 PM_LOCATION_INIT_TOKEN(parser, name),
4246 pm_parser_constant_id_token(parser, name)
4253static pm_global_variable_read_node_t *
4254pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4255 return pm_global_variable_read_node_new(
4259 PM_LOCATION_INIT_UNSET,
4267static pm_global_variable_write_node_t *
4268pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4269 return pm_global_variable_write_node_new(
4272 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4273 PM_LOCATION_INIT_NODES(target, value),
4274 pm_global_variable_write_name(parser, target),
4277 TOK2LOC(parser, operator)
4284static pm_global_variable_write_node_t *
4285pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4286 return pm_global_variable_write_node_new(
4290 PM_LOCATION_INIT_UNSET,
4292 ((pm_location_t) { 0 }),
4294 ((pm_location_t) { 0 })
4301static pm_hash_node_t *
4302pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4303 assert(opening != NULL);
4305 return pm_hash_node_new(
4308 PM_NODE_FLAG_STATIC_LITERAL,
4309 PM_LOCATION_INIT_TOKEN(parser, opening),
4310 TOK2LOC(parser, opening),
4311 ((pm_node_list_t) { 0 }),
4312 ((pm_location_t) { 0 })
4320pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
4321 pm_node_list_append(arena, &hash->elements, element);
4323 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4324 if (static_literal) {
4325 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4326 static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE);
4327 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4328 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4331 if (!static_literal) {
4332 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4337pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
4338 PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
4339 hash->closing_loc = TOK2LOC(parser, token);
4345static pm_if_node_t *
4346pm_if_node_create(pm_parser_t *parser,
4347 const pm_token_t *if_keyword,
4348 pm_node_t *predicate,
4349 const pm_token_t *then_keyword,
4350 pm_statements_node_t *statements,
4351 pm_node_t *subsequent,
4352 const pm_token_t *end_keyword
4354 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4356 uint32_t start = PM_TOKEN_START(parser, if_keyword);
4359 if (end_keyword != NULL) {
4360 end = PM_TOKEN_END(parser, end_keyword);
4361 } else if (subsequent != NULL) {
4362 end = PM_NODE_END(subsequent);
4363 } else if (pm_statements_node_body_length(statements) != 0) {
4364 end = PM_NODE_END(statements);
4366 end = PM_NODE_END(predicate);
4369 return pm_if_node_new(
4372 PM_NODE_FLAG_NEWLINE,
4373 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4374 TOK2LOC(parser, if_keyword),
4376 NTOK2LOC(parser, then_keyword),
4379 NTOK2LOC(parser, end_keyword)
4386static pm_if_node_t *
4387pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4388 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4390 pm_statements_node_t *statements = pm_statements_node_create(parser);
4391 pm_statements_node_body_append(parser, statements, statement, true);
4393 return pm_if_node_new(
4396 PM_NODE_FLAG_NEWLINE,
4397 PM_LOCATION_INIT_NODES(statement, predicate),
4398 TOK2LOC(parser, if_keyword),
4400 ((pm_location_t) { 0 }),
4403 ((pm_location_t) { 0 })
4410static pm_if_node_t *
4411pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_token_t *qmark, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
4412 pm_assert_value_expression(parser, predicate);
4413 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4415 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4416 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4418 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4419 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4421 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
4422 return pm_if_node_new(
4425 PM_NODE_FLAG_NEWLINE,
4426 PM_LOCATION_INIT_NODES(predicate, false_expression),
4427 ((pm_location_t) { 0 }),
4429 TOK2LOC(parser, qmark),
4432 ((pm_location_t) { 0 })
4437pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
4438 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4439 node->end_keyword_loc = TOK2LOC(parser, keyword);
4443pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
4444 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4445 node->end_keyword_loc = TOK2LOC(parser, keyword);
4451static pm_implicit_node_t *
4452pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4453 return pm_implicit_node_new(
4457 PM_LOCATION_INIT_NODE(value),
4465static pm_implicit_rest_node_t *
4466pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4467 assert(token->type == PM_TOKEN_COMMA);
4469 return pm_implicit_rest_node_new(
4473 PM_LOCATION_INIT_TOKEN(parser, token)
4480static pm_integer_node_t *
4481pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4482 assert(token->type == PM_TOKEN_INTEGER);
4484 pm_integer_node_t *node = pm_integer_node_new(
4487 base | PM_NODE_FLAG_STATIC_LITERAL,
4488 PM_LOCATION_INIT_TOKEN(parser, token),
4489 ((pm_integer_t) { 0 })
4492 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4494 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4495 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4496 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4497 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4498 default: assert(false && "unreachable"); break;
4501 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4502 pm_integer_arena_move(parser->arena, &node->value);
4510static pm_imaginary_node_t *
4511pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4512 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4514 return pm_imaginary_node_new(
4517 PM_NODE_FLAG_STATIC_LITERAL,
4518 PM_LOCATION_INIT_TOKEN(parser, token),
4519 UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4520 .type = PM_TOKEN_INTEGER,
4521 .start = token->start,
4522 .end = token->end - 1
4531static pm_rational_node_t *
4532pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4533 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4535 pm_rational_node_t *node = pm_rational_node_new(
4538 base | PM_NODE_FLAG_STATIC_LITERAL,
4539 PM_LOCATION_INIT_TOKEN(parser, token),
4540 ((pm_integer_t) { 0 }),
4541 ((pm_integer_t) { .value = 1 })
4544 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4546 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4547 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4548 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4549 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4550 default: assert(false && "unreachable"); break;
4553 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4554 pm_integer_arena_move(parser->arena, &node->numerator);
4563static pm_imaginary_node_t *
4564pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4565 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4567 return pm_imaginary_node_new(
4570 PM_NODE_FLAG_STATIC_LITERAL,
4571 PM_LOCATION_INIT_TOKEN(parser, token),
4572 UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4573 .type = PM_TOKEN_INTEGER_RATIONAL,
4574 .start = token->start,
4575 .end = token->end - 1
4583static pm_in_node_t *
4584pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t *statements, const pm_token_t *in_keyword, const pm_token_t *then_keyword) {
4585 uint32_t start = PM_TOKEN_START(parser, in_keyword);
4588 if (statements != NULL) {
4589 end = PM_NODE_END(statements);
4590 } else if (then_keyword != NULL) {
4591 end = PM_TOKEN_END(parser, then_keyword);
4593 end = PM_NODE_END(pattern);
4596 return pm_in_node_new(
4600 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4603 TOK2LOC(parser, in_keyword),
4604 NTOK2LOC(parser, then_keyword)
4611static pm_instance_variable_and_write_node_t *
4612pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4613 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4615 return pm_instance_variable_and_write_node_new(
4619 PM_LOCATION_INIT_NODES(target, value),
4621 target->base.location,
4622 TOK2LOC(parser, operator),
4630static pm_instance_variable_operator_write_node_t *
4631pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4632 return pm_instance_variable_operator_write_node_new(
4636 PM_LOCATION_INIT_NODES(target, value),
4638 target->base.location,
4639 TOK2LOC(parser, operator),
4641 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4648static pm_instance_variable_or_write_node_t *
4649pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4650 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4652 return pm_instance_variable_or_write_node_new(
4656 PM_LOCATION_INIT_NODES(target, value),
4658 target->base.location,
4659 TOK2LOC(parser, operator),
4667static pm_instance_variable_read_node_t *
4668pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4669 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4671 return pm_instance_variable_read_node_new(
4675 PM_LOCATION_INIT_TOKEN(parser, token),
4676 pm_parser_constant_id_token(parser, token)
4684static pm_instance_variable_write_node_t *
4685pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
4686 return pm_instance_variable_write_node_new(
4689 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4690 PM_LOCATION_INIT_NODES(read_node, value),
4692 read_node->base.location,
4694 TOK2LOC(parser, operator)
4704pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4705 switch (PM_NODE_TYPE(part)) {
4706 case PM_STRING_NODE:
4707 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4709 case PM_EMBEDDED_STATEMENTS_NODE: {
4710 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4711 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4713 if (embedded == NULL) {
4714 // If there are no statements or more than one statement, then
4715 // we lose the static literal flag.
4716 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4717 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4718 // If the embedded statement is a string, then we can keep the
4719 // static literal flag and mark the string as frozen.
4720 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4721 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4722 // If the embedded statement is an interpolated string and it's
4723 // a static literal, then we can keep the static literal flag.
4725 // Otherwise we lose the static literal flag.
4726 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4731 case PM_EMBEDDED_VARIABLE_NODE:
4732 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4735 assert(false && "unexpected node type");
4739 pm_node_list_append(arena, parts, part);
4745static pm_interpolated_regular_expression_node_t *
4746pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4747 return pm_interpolated_regular_expression_node_new(
4750 PM_NODE_FLAG_STATIC_LITERAL,
4751 PM_LOCATION_INIT_TOKEN(parser, opening),
4752 TOK2LOC(parser, opening),
4753 ((pm_node_list_t) { 0 }),
4754 TOK2LOC(parser, opening)
4759pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
4760 if (PM_NODE_START(node) > PM_NODE_START(part)) {
4761 PM_NODE_START_SET_NODE(node, part);
4763 if (PM_NODE_END(node) < PM_NODE_END(part)) {
4764 PM_NODE_LENGTH_SET_NODE(node, part);
4767 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
4771pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
4772 node->closing_loc = TOK2LOC(parser, closing);
4773 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
4774 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
4801pm_interpolated_string_node_append(pm_arena_t *arena, pm_interpolated_string_node_t *node, pm_node_t *part) {
4802#define CLEAR_FLAGS(node) \
4803 node->base.flags = (pm_node_flags_t) (FL(node) & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
4805#define MUTABLE_FLAGS(node) \
4806 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
4808 if (node->parts.size == 0 && node->opening_loc.length == 0) {
4809 PM_NODE_START_SET_NODE(node, part);
4812 if (PM_NODE_END(part) > PM_NODE_END(node)) {
4813 PM_NODE_LENGTH_SET_NODE(node, part);
4816 switch (PM_NODE_TYPE(part)) {
4817 case PM_STRING_NODE:
4818 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
4819 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
4820 // as long as this interpolation only consists of other string literals.
4821 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
4822 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4824 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4826 case PM_INTERPOLATED_STRING_NODE:
4827 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
4828 // If the string that we're concatenating is a static literal,
4829 // then we can keep the static literal flag for this string.
4831 // Otherwise, we lose the static literal flag here and we should
4832 // also clear the mutability flags.
4836 case PM_EMBEDDED_STATEMENTS_NODE: {
4837 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4838 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4840 if (embedded == NULL) {
4841 // If we're embedding multiple statements or no statements, then
4842 // the string is not longer a static literal.
4844 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4845 // If the embedded statement is a string, then we can make that
4846 // string as frozen and static literal, and not touch the static
4847 // literal status of this string.
4848 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4850 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4851 MUTABLE_FLAGS(node);
4853 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4854 // If the embedded statement is an interpolated string, but that
4855 // string is marked as static literal, then we can keep our
4856 // static literal status for this string.
4857 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4858 MUTABLE_FLAGS(node);
4861 // In all other cases, we lose the static literal flag here and
4868 case PM_EMBEDDED_VARIABLE_NODE:
4869 // Embedded variables clear static literal, which means we also
4870 // should clear the mutability flags.
4873 case PM_X_STRING_NODE:
4874 case PM_INTERPOLATED_X_STRING_NODE:
4875 case PM_SYMBOL_NODE:
4876 case PM_INTERPOLATED_SYMBOL_NODE:
4877 // These will only happen in error cases. But we want to handle it
4878 // here so that we don't fail the assertion.
4882 assert(false && "unexpected node type");
4886 pm_node_list_append(arena, &node->parts, part);
4895static pm_interpolated_string_node_t *
4896pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4897 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
4899 switch (parser->frozen_string_literal) {
4900 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
4901 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
4903 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
4904 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
4908 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
4909 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
4911 pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
4915 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4916 NTOK2LOC(parser, opening),
4917 ((pm_node_list_t) { 0 }),
4918 NTOK2LOC(parser, closing)
4921 if (parts != NULL) {
4923 PM_NODE_LIST_FOREACH(parts, index, part) {
4924 pm_interpolated_string_node_append(parser->arena, node, part);
4935pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
4936 node->closing_loc = TOK2LOC(parser, closing);
4937 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
4941pm_interpolated_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
4942 if (node->parts.size == 0 && node->opening_loc.length == 0) {
4943 PM_NODE_START_SET_NODE(node, part);
4946 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
4948 if (PM_NODE_END(part) > PM_NODE_END(node)) {
4949 PM_NODE_LENGTH_SET_NODE(node, part);
4954pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
4955 node->closing_loc = TOK2LOC(parser, closing);
4956 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
4962static pm_interpolated_symbol_node_t *
4963pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4964 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
4965 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
4967 pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
4970 PM_NODE_FLAG_STATIC_LITERAL,
4971 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4972 NTOK2LOC(parser, opening),
4973 ((pm_node_list_t) { 0 }),
4974 NTOK2LOC(parser, closing)
4977 if (parts != NULL) {
4979 PM_NODE_LIST_FOREACH(parts, index, part) {
4980 pm_interpolated_symbol_node_append(parser->arena, node, part);
4990static pm_interpolated_x_string_node_t *
4991pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4992 return pm_interpolated_x_string_node_new(
4996 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4997 TOK2LOC(parser, opening),
4998 ((pm_node_list_t) { 0 }),
4999 TOK2LOC(parser, closing)
5004pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5005 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5006 PM_NODE_LENGTH_SET_NODE(node, part);
5010pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5011 node->closing_loc = TOK2LOC(parser, closing);
5012 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5018static pm_it_local_variable_read_node_t *
5019pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5020 return pm_it_local_variable_read_node_new(
5024 PM_LOCATION_INIT_TOKEN(parser, name)
5031static pm_it_parameters_node_t *
5032pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5033 return pm_it_parameters_node_new(
5037 PM_LOCATION_INIT_TOKENS(parser, opening, closing)
5044static pm_keyword_hash_node_t *
5045pm_keyword_hash_node_create(pm_parser_t *parser) {
5046 return pm_keyword_hash_node_new(
5049 PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5050 PM_LOCATION_INIT_UNSET,
5051 ((pm_node_list_t) { 0 })
5059pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *hash, pm_node_t *element) {
5060 // If the element being added is not an AssocNode or does not have a symbol
5061 // key, then we want to turn the SYMBOL_KEYS flag off.
5062 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5063 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5066 pm_node_list_append(arena, &hash->elements, element);
5067 if (PM_NODE_LENGTH(hash) == 0) {
5068 PM_NODE_START_SET_NODE(hash, element);
5070 PM_NODE_LENGTH_SET_NODE(hash, element);
5076static pm_required_keyword_parameter_node_t *
5077pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5078 return pm_required_keyword_parameter_node_new(
5082 PM_LOCATION_INIT_TOKEN(parser, name),
5083 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5084 TOK2LOC(parser, name)
5091static pm_optional_keyword_parameter_node_t *
5092pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5093 return pm_optional_keyword_parameter_node_new(
5097 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5098 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5099 TOK2LOC(parser, name),
5107static pm_keyword_rest_parameter_node_t *
5108pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5109 return pm_keyword_rest_parameter_node_new(
5113 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
5114 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
5115 NTOK2LOC(parser, name),
5116 TOK2LOC(parser, operator)
5123static pm_lambda_node_t *
5124pm_lambda_node_create(
5125 pm_parser_t *parser,
5126 pm_constant_id_list_t *locals,
5127 const pm_token_t *operator,
5128 const pm_token_t *opening,
5129 const pm_token_t *closing,
5130 pm_node_t *parameters,
5133 return pm_lambda_node_new(
5137 PM_LOCATION_INIT_TOKENS(parser, operator, closing),
5139 TOK2LOC(parser, operator),
5140 TOK2LOC(parser, opening),
5141 TOK2LOC(parser, closing),
5150static pm_local_variable_and_write_node_t *
5151pm_local_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
5152 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5153 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5155 return pm_local_variable_and_write_node_new(
5159 PM_LOCATION_INIT_NODES(target, value),
5161 TOK2LOC(parser, operator),
5171static pm_local_variable_operator_write_node_t *
5172pm_local_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
5173 return pm_local_variable_operator_write_node_new(
5177 PM_LOCATION_INIT_NODES(target, value),
5179 TOK2LOC(parser, operator),
5182 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
5190static pm_local_variable_or_write_node_t *
5191pm_local_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
5192 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5193 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5195 return pm_local_variable_or_write_node_new(
5199 PM_LOCATION_INIT_NODES(target, value),
5201 TOK2LOC(parser, operator),
5211static pm_local_variable_read_node_t *
5212pm_local_variable_read_node_create_constant_id(pm_parser_t *parser, const pm_token_t *name, pm_constant_id_t name_id, uint32_t depth, bool missing) {
5213 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5215 return pm_local_variable_read_node_new(
5219 PM_LOCATION_INIT_TOKEN(parser, name),
5228static pm_local_variable_read_node_t *
5229pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5230 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5231 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5238static pm_local_variable_read_node_t *
5239pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5240 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5241 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5247static pm_local_variable_write_node_t *
5248pm_local_variable_write_node_create(pm_parser_t *parser, pm_constant_id_t name, uint32_t depth, pm_node_t *value, const pm_location_t *name_loc, const pm_token_t *operator) {
5249 return pm_local_variable_write_node_new(
5252 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5253 ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
5258 TOK2LOC(parser, operator)
5266pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5267 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5275pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
5278 (parser->start[start] == '_') &&
5279 (parser->start[start + 1] != '0') &&
5280 pm_char_is_decimal_digit(parser->start[start + 1])
5289pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
5290 if (pm_token_is_numbered_parameter(parser, start, length)) {
5291 PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
5299static pm_local_variable_target_node_t *
5300pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5301 pm_refute_numbered_parameter(parser, location->start, location->length);
5303 return pm_local_variable_target_node_new(
5307 ((pm_location_t) { .start = location->start, .length = location->length }),
5316static pm_match_predicate_node_t *
5317pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5318 pm_assert_value_expression(parser, value);
5320 return pm_match_predicate_node_new(
5324 PM_LOCATION_INIT_NODES(value, pattern),
5327 TOK2LOC(parser, operator)
5334static pm_match_required_node_t *
5335pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5336 pm_assert_value_expression(parser, value);
5338 return pm_match_required_node_new(
5342 PM_LOCATION_INIT_NODES(value, pattern),
5345 TOK2LOC(parser, operator)
5352static pm_match_write_node_t *
5353pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5354 return pm_match_write_node_new(
5358 PM_LOCATION_INIT_NODE(call),
5360 ((pm_node_list_t) { 0 })
5367static pm_module_node_t *
5368pm_module_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *module_keyword, pm_node_t *constant_path, const pm_token_t *name, pm_node_t *body, const pm_token_t *end_keyword) {
5369 return pm_module_node_new(
5373 PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
5374 (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5375 TOK2LOC(parser, module_keyword),
5378 TOK2LOC(parser, end_keyword),
5379 pm_parser_constant_id_token(parser, name)
5386static pm_multi_target_node_t *
5387pm_multi_target_node_create(pm_parser_t *parser) {
5388 return pm_multi_target_node_new(
5392 PM_LOCATION_INIT_UNSET,
5393 ((pm_node_list_t) { 0 }),
5395 ((pm_node_list_t) { 0 }),
5396 ((pm_location_t) { 0 }),
5397 ((pm_location_t) { 0 })
5405pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5406 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5407 if (node->rest == NULL) {
5408 node->rest = target;
5410 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5411 pm_node_list_append(parser->arena, &node->rights, target);
5413 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5414 if (node->rest == NULL) {
5415 node->rest = target;
5417 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5418 pm_node_list_append(parser->arena, &node->rights, target);
5420 } else if (node->rest == NULL) {
5421 pm_node_list_append(parser->arena, &node->lefts, target);
5423 pm_node_list_append(parser->arena, &node->rights, target);
5426 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
5427 PM_NODE_START_SET_NODE(node, target);
5430 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
5431 PM_NODE_LENGTH_SET_NODE(node, target);
5439pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
5440 PM_NODE_START_SET_TOKEN(parser, node, lparen);
5441 PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
5442 node->lparen_loc = TOK2LOC(parser, lparen);
5449pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
5450 PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
5451 node->rparen_loc = TOK2LOC(parser, rparen);
5457static pm_multi_write_node_t *
5458pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5459 /* The target is no longer necessary because we have reused its children. It
5460 * is arena-allocated so no explicit free is needed. */
5461 return pm_multi_write_node_new(
5464 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5465 PM_LOCATION_INIT_NODES(target, value),
5471 TOK2LOC(parser, operator),
5479static pm_next_node_t *
5480pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5481 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5483 return pm_next_node_new(
5487 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
5489 TOK2LOC(parser, keyword)
5496static pm_nil_node_t *
5497pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5498 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5500 return pm_nil_node_new(
5503 PM_NODE_FLAG_STATIC_LITERAL,
5504 PM_LOCATION_INIT_TOKEN(parser, token)
5511static pm_no_block_parameter_node_t *
5512pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5513 assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5514 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5516 return pm_no_block_parameter_node_new(
5520 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5521 TOK2LOC(parser, operator),
5522 TOK2LOC(parser, keyword)
5529static pm_no_keywords_parameter_node_t *
5530pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5531 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5532 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5534 return pm_no_keywords_parameter_node_new(
5538 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5539 TOK2LOC(parser, operator),
5540 TOK2LOC(parser, keyword)
5547static pm_numbered_parameters_node_t *
5548pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
5549 return pm_numbered_parameters_node_new(
5553 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5562#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5571pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5572 const uint8_t *start = token->start + 1;
5573 const uint8_t *end = token->end;
5575 ptrdiff_t diff = end - start;
5577#if PTRDIFF_MAX > SIZE_MAX
5578 assert(diff < (ptrdiff_t) SIZE_MAX);
5580 size_t length = (size_t) diff;
5582 char *digits = xcalloc(length + 1, sizeof(char));
5583 memcpy(digits, start, length);
5584 digits[length] = '\0';
5588 unsigned long value = strtoul(digits, &endptr, 10);
5590 if ((digits == endptr) || (*endptr != '\0')) {
5591 pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
5595 xfree_sized(digits, sizeof(char) * (length + 1));
5597 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5598 PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5602 return (uint32_t) value;
5610static pm_numbered_reference_read_node_t *
5611pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5612 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5614 return pm_numbered_reference_read_node_new(
5618 PM_LOCATION_INIT_TOKEN(parser, name),
5619 pm_numbered_reference_read_node_number(parser, name)
5626static pm_optional_parameter_node_t *
5627pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5628 return pm_optional_parameter_node_new(
5632 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5633 pm_parser_constant_id_token(parser, name),
5634 TOK2LOC(parser, name),
5635 TOK2LOC(parser, operator),
5643static pm_or_node_t *
5644pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5645 pm_assert_value_expression(parser, left);
5647 return pm_or_node_new(
5651 PM_LOCATION_INIT_NODES(left, right),
5654 TOK2LOC(parser, operator)
5661static pm_parameters_node_t *
5662pm_parameters_node_create(pm_parser_t *parser) {
5663 return pm_parameters_node_new(
5667 PM_LOCATION_INIT_UNSET,
5668 ((pm_node_list_t) { 0 }),
5669 ((pm_node_list_t) { 0 }),
5671 ((pm_node_list_t) { 0 }),
5672 ((pm_node_list_t) { 0 }),
5682pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5683 if ((params->base.location.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
5684 PM_NODE_START_SET_NODE(params, param);
5687 if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
5688 PM_NODE_LENGTH_SET_NODE(params, param);
5696pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
5697 pm_parameters_node_location_set(params, param);
5698 pm_node_list_append(arena, ¶ms->requireds, param);
5705pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
5706 pm_parameters_node_location_set(params, UP(param));
5707 pm_node_list_append(arena, ¶ms->optionals, UP(param));
5714pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
5715 pm_parameters_node_location_set(params, param);
5716 pm_node_list_append(arena, ¶ms->posts, param);
5723pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5724 pm_parameters_node_location_set(params, param);
5725 params->rest = param;
5732pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
5733 pm_parameters_node_location_set(params, param);
5734 pm_node_list_append(arena, ¶ms->keywords, param);
5741pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5742 assert(params->keyword_rest == NULL);
5743 pm_parameters_node_location_set(params, param);
5744 params->keyword_rest = param;
5751pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
5752 assert(params->block == NULL);
5753 pm_parameters_node_location_set(params, param);
5754 params->block = param;
5760static pm_program_node_t *
5761pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
5762 return pm_program_node_new(
5766 PM_LOCATION_INIT_NODE(statements),
5775static pm_parentheses_node_t *
5776pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing, pm_node_flags_t flags) {
5777 return pm_parentheses_node_new(
5781 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5783 TOK2LOC(parser, opening),
5784 TOK2LOC(parser, closing)
5791static pm_pinned_expression_node_t *
5792pm_pinned_expression_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *operator, const pm_token_t *lparen, const pm_token_t *rparen) {
5793 return pm_pinned_expression_node_new(
5797 PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
5799 TOK2LOC(parser, operator),
5800 TOK2LOC(parser, lparen),
5801 TOK2LOC(parser, rparen)
5808static pm_pinned_variable_node_t *
5809pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
5810 return pm_pinned_variable_node_new(
5814 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
5816 TOK2LOC(parser, operator)
5823static pm_post_execution_node_t *
5824pm_post_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
5825 return pm_post_execution_node_new(
5829 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
5831 TOK2LOC(parser, keyword),
5832 TOK2LOC(parser, opening),
5833 TOK2LOC(parser, closing)
5840static pm_pre_execution_node_t *
5841pm_pre_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
5842 return pm_pre_execution_node_new(
5846 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
5848 TOK2LOC(parser, keyword),
5849 TOK2LOC(parser, opening),
5850 TOK2LOC(parser, closing)
5857static pm_range_node_t *
5858pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5859 pm_assert_value_expression(parser, left);
5860 pm_assert_value_expression(parser, right);
5861 pm_node_flags_t flags = 0;
5863 // Indicate that this node is an exclusive range if the operator is `...`.
5864 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
5865 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
5868 // Indicate that this node is a static literal (i.e., can be compiled with
5869 // a putobject in CRuby) if the left and right are implicit nil, explicit
5870 // nil, or integers.
5872 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
5873 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
5875 flags |= PM_NODE_FLAG_STATIC_LITERAL;
5878 uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
5879 uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
5881 return pm_range_node_new(
5885 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5888 TOK2LOC(parser, operator)
5895static pm_redo_node_t *
5896pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
5897 assert(token->type == PM_TOKEN_KEYWORD_REDO);
5899 return pm_redo_node_new(
5903 PM_LOCATION_INIT_TOKEN(parser, token)
5911static pm_regular_expression_node_t *
5912pm_regular_expression_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
5913 return pm_regular_expression_node_new(
5916 pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
5917 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5918 TOK2LOC(parser, opening),
5919 TOK2LOC(parser, content),
5920 TOK2LOC(parser, closing),
5928static inline pm_regular_expression_node_t *
5929pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
5930 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
5936static pm_required_parameter_node_t *
5937pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
5938 return pm_required_parameter_node_new(
5942 PM_LOCATION_INIT_TOKEN(parser, token),
5943 pm_parser_constant_id_token(parser, token)
5950static pm_rescue_modifier_node_t *
5951pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
5952 return pm_rescue_modifier_node_new(
5956 PM_LOCATION_INIT_NODES(expression, rescue_expression),
5958 TOK2LOC(parser, keyword),
5966static pm_rescue_node_t *
5967pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
5968 return pm_rescue_node_new(
5972 PM_LOCATION_INIT_TOKEN(parser, keyword),
5973 TOK2LOC(parser, keyword),
5974 ((pm_node_list_t) { 0 }),
5975 ((pm_location_t) { 0 }),
5977 ((pm_location_t) { 0 }),
5984pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
5985 node->operator_loc = TOK2LOC(parser, operator);
5992pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
5993 node->reference = reference;
5994 PM_NODE_LENGTH_SET_NODE(node, reference);
6001pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6002 node->statements = statements;
6003 if (pm_statements_node_body_length(statements) > 0) {
6004 PM_NODE_LENGTH_SET_NODE(node, statements);
6012pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6013 node->subsequent = subsequent;
6014 PM_NODE_LENGTH_SET_NODE(node, subsequent);
6021pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
6022 pm_node_list_append(arena, &node->exceptions, exception);
6023 PM_NODE_LENGTH_SET_NODE(node, exception);
6029static pm_rest_parameter_node_t *
6030pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6031 return pm_rest_parameter_node_new(
6035 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
6036 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
6037 NTOK2LOC(parser, name),
6038 TOK2LOC(parser, operator)
6045static pm_retry_node_t *
6046pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6047 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6049 return pm_retry_node_new(
6053 PM_LOCATION_INIT_TOKEN(parser, token)
6060static pm_return_node_t *
6061pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6062 return pm_return_node_new(
6066 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
6067 TOK2LOC(parser, keyword),
6075static pm_self_node_t *
6076pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6077 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6079 return pm_self_node_new(
6083 PM_LOCATION_INIT_TOKEN(parser, token)
6090static pm_shareable_constant_node_t *
6091pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6092 return pm_shareable_constant_node_new(
6095 (pm_node_flags_t) value,
6096 PM_LOCATION_INIT_NODE(write),
6104static pm_singleton_class_node_t *
6105pm_singleton_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, const pm_token_t *operator, pm_node_t *expression, pm_node_t *body, const pm_token_t *end_keyword) {
6106 return pm_singleton_class_node_new(
6110 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
6112 TOK2LOC(parser, class_keyword),
6113 TOK2LOC(parser, operator),
6116 TOK2LOC(parser, end_keyword)
6123static pm_source_encoding_node_t *
6124pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6125 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6127 return pm_source_encoding_node_new(
6130 PM_NODE_FLAG_STATIC_LITERAL,
6131 PM_LOCATION_INIT_TOKEN(parser, token)
6138static pm_source_file_node_t*
6139pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6140 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6142 pm_node_flags_t flags = 0;
6144 switch (parser->frozen_string_literal) {
6145 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6146 flags |= PM_STRING_FLAGS_MUTABLE;
6148 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6149 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6153 return pm_source_file_node_new(
6157 PM_LOCATION_INIT_TOKEN(parser, file_keyword),
6165static pm_source_line_node_t *
6166pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6167 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6169 return pm_source_line_node_new(
6172 PM_NODE_FLAG_STATIC_LITERAL,
6173 PM_LOCATION_INIT_TOKEN(parser, token)
6180static pm_splat_node_t *
6181pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6182 return pm_splat_node_new(
6186 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
6187 TOK2LOC(parser, operator),
6195static pm_statements_node_t *
6196pm_statements_node_create(pm_parser_t *parser) {
6197 return pm_statements_node_new(
6201 PM_LOCATION_INIT_UNSET,
6202 ((pm_node_list_t) { 0 })
6210pm_statements_node_body_length(pm_statements_node_t *node) {
6211 return node && node->body.size;
6219pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6220 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6221 PM_NODE_START_SET_NODE(node, statement);
6224 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6225 PM_NODE_LENGTH_SET_NODE(node, statement);
6233pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6234 pm_statements_node_body_update(node, statement);
6236 if (node->body.size > 0) {
6237 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6239 switch (PM_NODE_TYPE(previous)) {
6244 case PM_RETURN_NODE:
6245 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6252 pm_node_list_append(parser->arena, &node->body, statement);
6253 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6260pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
6261 pm_statements_node_body_update(node, statement);
6262 pm_node_list_prepend(arena, &node->body, statement);
6263 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6269static inline pm_string_node_t *
6270pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *string) {
6271 pm_node_flags_t flags = 0;
6273 switch (parser->frozen_string_literal) {
6274 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6275 flags = PM_STRING_FLAGS_MUTABLE;
6277 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6278 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6282 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6283 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6285 return pm_string_node_new(
6289 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6290 NTOK2LOC(parser, opening),
6291 TOK2LOC(parser, content),
6292 NTOK2LOC(parser, closing),
6300static pm_string_node_t *
6301pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6302 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6309static pm_string_node_t *
6310pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6311 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6312 parser->current_string = PM_STRING_EMPTY;
6319static pm_super_node_t *
6320pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6321 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6323 const pm_location_t *end = pm_arguments_end(arguments);
6324 assert(end != NULL && "unreachable");
6326 return pm_super_node_new(
6330 ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
6331 TOK2LOC(parser, keyword),
6332 arguments->opening_loc,
6333 arguments->arguments,
6334 arguments->closing_loc,
6344pm_ascii_only_p(const pm_string_t *contents) {
6345 const size_t length = pm_string_length(contents);
6346 const uint8_t *source = pm_string_source(contents);
6348 for (size_t index = 0; index < length; index++) {
6349 if (source[index] & 0x80) return false;
6359parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6360 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6361 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6364 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6377parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6378 const pm_encoding_t *encoding = parser->encoding;
6380 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6381 size_t width = encoding->char_width(cursor, end - cursor);
6384 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6401static inline pm_node_flags_t
6402parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6403 if (parser->explicit_encoding != NULL) {
6404 // A Symbol may optionally have its encoding explicitly set. This will
6405 // happen if an escape sequence results in a non-ASCII code point.
6406 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6407 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6408 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6409 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6410 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6411 } else if (validate) {
6412 parse_symbol_encoding_validate_other(parser, location, contents);
6414 } else if (pm_ascii_only_p(contents)) {
6415 // Ruby stipulates that all source files must use an ASCII-compatible
6416 // encoding. Thus, all symbols appearing in source are eligible for
6417 // "downgrading" to US-ASCII.
6418 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6419 } else if (validate) {
6420 parse_symbol_encoding_validate_other(parser, location, contents);
6430static pm_symbol_node_t *
6431pm_symbol_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing, const pm_string_t *unescaped, pm_node_flags_t flags) {
6432 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6433 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6435 return pm_symbol_node_new(
6438 PM_NODE_FLAG_STATIC_LITERAL | flags,
6439 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6440 NTOK2LOC(parser, opening),
6441 NTOK2LOC(parser, value),
6442 NTOK2LOC(parser, closing),
6450static inline pm_symbol_node_t *
6451pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6452 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6458static pm_symbol_node_t *
6459pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6460 pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, value, &parser->current_string, false));
6461 parser->current_string = PM_STRING_EMPTY;
6468static pm_symbol_node_t *
6469pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6470 assert(token->type == PM_TOKEN_LABEL);
6472 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6473 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6474 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6476 assert((label.end - label.start) >= 0);
6477 pm_string_shared_init(&node->unescaped, label.start, label.end);
6478 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
6486static pm_symbol_node_t *
6487pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6488 pm_symbol_node_t *node = pm_symbol_node_new(
6491 PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
6492 PM_LOCATION_INIT_UNSET,
6493 ((pm_location_t) { 0 }),
6494 ((pm_location_t) { 0 }),
6495 ((pm_location_t) { 0 }),
6496 ((pm_string_t) { 0 })
6499 pm_string_constant_init(&node->unescaped, content, strlen(content));
6507pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6508 const pm_location_t *location = NULL;
6510 switch (PM_NODE_TYPE(node)) {
6511 case PM_SYMBOL_NODE: {
6512 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6513 if (cast->closing_loc.length > 0) {
6514 location = &cast->closing_loc;
6518 case PM_INTERPOLATED_SYMBOL_NODE: {
6519 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6520 if (cast->closing_loc.length > 0) {
6521 location = &cast->closing_loc;
6529 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6535static pm_symbol_node_t *
6536pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6537 pm_symbol_node_t *new_node = pm_symbol_node_new(
6540 PM_NODE_FLAG_STATIC_LITERAL,
6541 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6542 TOK2LOC(parser, opening),
6544 TOK2LOC(parser, closing),
6548 pm_token_t content = {
6549 .type = PM_TOKEN_IDENTIFIER,
6550 .start = parser->start + node->content_loc.start,
6551 .end = parser->start + node->content_loc.start + node->content_loc.length
6554 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
6556 /* The old node is arena-allocated so no explicit free is needed. */
6563static pm_string_node_t *
6564pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6565 pm_node_flags_t flags = 0;
6567 switch (parser->frozen_string_literal) {
6568 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6569 flags = PM_STRING_FLAGS_MUTABLE;
6571 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6572 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6576 pm_string_node_t *new_node = pm_string_node_new(
6580 PM_LOCATION_INIT_NODE(node),
6587 /* The old node is arena-allocated so no explicit free is needed. */
6594static pm_true_node_t *
6595pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6596 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6598 return pm_true_node_new(
6601 PM_NODE_FLAG_STATIC_LITERAL,
6602 PM_LOCATION_INIT_TOKEN(parser, token)
6609static pm_true_node_t *
6610pm_true_node_synthesized_create(pm_parser_t *parser) {
6611 return pm_true_node_new(
6614 PM_NODE_FLAG_STATIC_LITERAL,
6615 PM_LOCATION_INIT_UNSET
6622static pm_undef_node_t *
6623pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6624 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6626 return pm_undef_node_new(
6630 PM_LOCATION_INIT_TOKEN(parser, token),
6631 ((pm_node_list_t) { 0 }),
6632 TOK2LOC(parser, token)
6640pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6641 PM_NODE_LENGTH_SET_NODE(node, name);
6642 pm_node_list_append(arena, &node->names, name);
6648static pm_unless_node_t *
6649pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, const pm_token_t *then_keyword, pm_statements_node_t *statements) {
6650 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6651 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6653 return pm_unless_node_new(
6656 PM_NODE_FLAG_NEWLINE,
6657 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
6658 TOK2LOC(parser, keyword),
6660 NTOK2LOC(parser, then_keyword),
6663 ((pm_location_t) { 0 })
6670static pm_unless_node_t *
6671pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6672 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6674 pm_statements_node_t *statements = pm_statements_node_create(parser);
6675 pm_statements_node_body_append(parser, statements, statement, true);
6677 return pm_unless_node_new(
6680 PM_NODE_FLAG_NEWLINE,
6681 PM_LOCATION_INIT_NODES(statement, predicate),
6682 TOK2LOC(parser, unless_keyword),
6684 ((pm_location_t) { 0 }),
6687 ((pm_location_t) { 0 })
6692pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
6693 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
6694 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
6703pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
6704 assert(parser->current_block_exits != NULL);
6706 // All of the block exits that we want to remove should be within the
6707 // statements, and since we are modifying the statements, we shouldn't have
6708 // to check the end location.
6709 uint32_t start = statements->base.location.start;
6711 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
6712 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
6713 if (block_exit->location.start < start) break;
6715 // Implicitly remove from the list by lowering the size.
6716 parser->current_block_exits->size--;
6723static pm_until_node_t *
6724pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
6725 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6727 return pm_until_node_new(
6731 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6732 TOK2LOC(parser, keyword),
6733 NTOK2LOC(parser, do_keyword),
6734 TOK2LOC(parser, closing),
6743static pm_until_node_t *
6744pm_until_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
6745 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6746 pm_loop_modifier_block_exits(parser, statements);
6748 return pm_until_node_new(
6752 PM_LOCATION_INIT_NODES(statements, predicate),
6753 TOK2LOC(parser, keyword),
6754 ((pm_location_t) { 0 }),
6755 ((pm_location_t) { 0 }),
6764static pm_when_node_t *
6765pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6766 return pm_when_node_new(
6770 PM_LOCATION_INIT_TOKEN(parser, keyword),
6771 TOK2LOC(parser, keyword),
6772 ((pm_node_list_t) { 0 }),
6773 ((pm_location_t) { 0 }),
6782pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
6783 PM_NODE_LENGTH_SET_NODE(node, condition);
6784 pm_node_list_append(arena, &node->conditions, condition);
6791pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
6792 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
6793 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
6800pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
6801 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
6802 PM_NODE_LENGTH_SET_NODE(node, statements);
6805 node->statements = statements;
6811static pm_while_node_t *
6812pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
6813 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6815 return pm_while_node_new(
6819 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6820 TOK2LOC(parser, keyword),
6821 NTOK2LOC(parser, do_keyword),
6822 TOK2LOC(parser, closing),
6831static pm_while_node_t *
6832pm_while_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
6833 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6834 pm_loop_modifier_block_exits(parser, statements);
6836 return pm_while_node_new(
6840 PM_LOCATION_INIT_NODES(statements, predicate),
6841 TOK2LOC(parser, keyword),
6842 ((pm_location_t) { 0 }),
6843 ((pm_location_t) { 0 }),
6852static pm_while_node_t *
6853pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
6854 return pm_while_node_new(
6858 PM_LOCATION_INIT_UNSET,
6859 ((pm_location_t) { 0 }),
6860 ((pm_location_t) { 0 }),
6861 ((pm_location_t) { 0 }),
6871static pm_x_string_node_t *
6872pm_xstring_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
6873 return pm_x_string_node_new(
6876 PM_STRING_FLAGS_FROZEN,
6877 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6878 TOK2LOC(parser, opening),
6879 TOK2LOC(parser, content),
6880 TOK2LOC(parser, closing),
6888static inline pm_x_string_node_t *
6889pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6890 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6896static pm_yield_node_t *
6897pm_yield_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_location_t *lparen_loc, pm_arguments_node_t *arguments, const pm_location_t *rparen_loc) {
6898 uint32_t start = PM_TOKEN_START(parser, keyword);
6901 if (rparen_loc->length > 0) {
6902 end = PM_LOCATION_END(rparen_loc);
6903 } else if (arguments != NULL) {
6904 end = PM_NODE_END(arguments);
6905 } else if (lparen_loc->length > 0) {
6906 end = PM_LOCATION_END(lparen_loc);
6908 end = PM_TOKEN_END(parser, keyword);
6911 return pm_yield_node_new(
6915 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6916 TOK2LOC(parser, keyword),
6928pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
6929 pm_scope_t *scope = parser->current_scope;
6932 while (scope != NULL) {
6933 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
6934 if (scope->closed) break;
6936 scope = scope->previous;
6949pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
6950 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
6957pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
6958 pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
6964static pm_constant_id_t
6965pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
6966 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
6967 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
6974static inline pm_constant_id_t
6975pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
6976 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
6982static inline pm_constant_id_t
6983pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
6984 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
6990static pm_constant_id_t
6991pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
6992 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
6993 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7000static pm_constant_id_t
7001pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7002 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7003 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7015pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7016 // We want to check whether the parameter name is a numbered parameter or
7018 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7020 // Otherwise we'll fetch the constant id for the parameter name and check
7021 // whether it's already in the current scope.
7022 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7024 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7025 // Add an error if the parameter doesn't start with _ and has been seen before
7026 if ((name->start < name->end) && (*name->start != '_')) {
7027 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7038pm_parser_scope_pop(pm_parser_t *parser) {
7039 pm_scope_t *scope = parser->current_scope;
7040 parser->current_scope = scope->previous;
7041 pm_locals_free(&scope->locals);
7042 xfree_sized(scope, sizeof(pm_scope_t));
7045/******************************************************************************/
7047/******************************************************************************/
7053pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7054 *stack = (*stack << 1) | (value & 1);
7061pm_state_stack_pop(pm_state_stack_t *stack) {
7069pm_state_stack_p(const pm_state_stack_t *stack) {
7074pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7075 // Use the negation of the value to prevent stack overflow.
7076 pm_state_stack_push(&parser->accepts_block_stack, !value);
7080pm_accepts_block_stack_pop(pm_parser_t *parser) {
7081 pm_state_stack_pop(&parser->accepts_block_stack);
7085pm_accepts_block_stack_p(pm_parser_t *parser) {
7086 return !pm_state_stack_p(&parser->accepts_block_stack);
7090pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7091 pm_state_stack_push(&parser->do_loop_stack, value);
7095pm_do_loop_stack_pop(pm_parser_t *parser) {
7096 pm_state_stack_pop(&parser->do_loop_stack);
7100pm_do_loop_stack_p(pm_parser_t *parser) {
7101 return pm_state_stack_p(&parser->do_loop_stack);
7104/******************************************************************************/
7105/* Lexer check helpers */
7106/******************************************************************************/
7112static inline uint8_t
7113peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7114 if (cursor < parser->end) {
7126static inline uint8_t
7127peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7128 return peek_at(parser, parser->current.end + offset);
7135static inline uint8_t
7136peek(const pm_parser_t *parser) {
7137 return peek_at(parser, parser->current.end);
7145match(pm_parser_t *parser, uint8_t value) {
7146 if (peek(parser) == value) {
7147 parser->current.end++;
7158match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7159 if (peek_at(parser, cursor) == '\n') {
7162 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7174match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7175 return match_eol_at(parser, parser->current.end + offset);
7184match_eol(pm_parser_t *parser) {
7185 return match_eol_at(parser, parser->current.end);
7191static inline const uint8_t *
7192next_newline(const uint8_t *cursor, ptrdiff_t length) {
7193 assert(length >= 0);
7195 // Note that it's okay for us to use memchr here to look for \n because none
7196 // of the encodings that we support have \n as a component of a multi-byte
7198 return memchr(cursor, '\n', (size_t) length);
7205ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7206 return !lex_state_p(parser, PM_LEX_STATE_CLASS | PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME | PM_LEX_STATE_ENDFN) && space_seen && !pm_char_is_whitespace(peek(parser));
7214parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7215 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7217 if (encoding != NULL) {
7218 if (parser->encoding != encoding) {
7219 parser->encoding = encoding;
7220 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7223 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7235parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7236 const uint8_t *cursor = parser->current.start + 1;
7237 const uint8_t *end = parser->current.end;
7239 bool separator = false;
7241 if (end - cursor <= 6) return;
7242 switch (cursor[6]) {
7243 case 'C': case 'c': cursor += 6; continue;
7244 case 'O': case 'o': cursor += 5; continue;
7245 case 'D': case 'd': cursor += 4; continue;
7246 case 'I': case 'i': cursor += 3; continue;
7247 case 'N': case 'n': cursor += 2; continue;
7248 case 'G': case 'g': cursor += 1; continue;
7255 if (pm_char_is_whitespace(*cursor)) break;
7258 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7264 if (++cursor >= end) return;
7265 } while (pm_char_is_whitespace(*cursor));
7267 if (separator) break;
7268 if (*cursor != '=' && *cursor != ':') return;
7274 const uint8_t *value_start = cursor;
7275 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7277 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7278 // If we were unable to parse the encoding value, then we've got an
7279 // issue because we didn't understand the encoding that the user was
7280 // trying to use. In this case we'll keep using the default encoding but
7281 // add an error to the parser to indicate an unsuccessful parse.
7282 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7287 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7288 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7289 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7290} pm_magic_comment_boolean_value_t;
7296static pm_magic_comment_boolean_value_t
7297parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7298 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7299 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7300 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7301 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7303 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7308pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7309 return b == '\'' || b == '"' || b == ':' || b == ';';
7317static inline const uint8_t *
7318parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7319 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
7320 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
7339parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7342 const uint8_t *start = parser->
current.start + 1;
7343 const uint8_t *end = parser->
current.end;
7344 if (end - start <= 7)
return false;
7346 const uint8_t *cursor;
7347 bool indicator =
false;
7349 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7352 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7363 while (cursor < end) {
7364 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7366 const uint8_t *key_start = cursor;
7367 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7369 const uint8_t *key_end = cursor;
7370 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7371 if (cursor == end)
break;
7373 if (*cursor ==
':') {
7376 if (!indicator)
return false;
7380 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7381 if (cursor == end)
break;
7383 const uint8_t *value_start;
7384 const uint8_t *value_end;
7386 if (*cursor ==
'"') {
7387 value_start = ++cursor;
7388 for (; cursor < end && *cursor !=
'"'; cursor++) {
7389 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7392 if (cursor < end && *cursor ==
'"') cursor++;
7394 value_start = cursor;
7395 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7400 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7402 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7403 if (cursor != end)
return false;
7409 const size_t key_length = (size_t) (key_end - key_start);
7413 pm_string_shared_init(&key, key_start, key_end);
7415 uint8_t *buffer =
xmalloc(key_length);
7416 if (buffer == NULL)
break;
7418 memcpy(buffer, key_start, key_length);
7419 buffer[dash - key_start] =
'_';
7421 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
7422 buffer[dash - key_start] =
'_';
7425 pm_string_owned_init(&key, buffer, key_length);
7431 uint32_t value_length = (uint32_t) (value_end - value_start);
7437 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7438 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7440 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7444 if (key_length == 11) {
7445 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7446 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7447 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7448 PM_PARSER_WARN_TOKEN_FORMAT(
7451 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7453 (
const char *) key_source,
7455 (
const char *) value_start
7458 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7461 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7466 }
else if (key_length == 21) {
7467 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7470 if (semantic_token_seen) {
7471 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7473 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7474 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7475 PM_PARSER_WARN_TOKEN_FORMAT(
7478 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7480 (
const char *) key_source,
7482 (
const char *) value_start
7485 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7488 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7494 }
else if (key_length == 24) {
7495 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7496 const uint8_t *cursor = parser->
current.start;
7497 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7499 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
7500 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7501 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7502 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7503 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7504 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7505 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7506 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7507 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7508 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7510 PM_PARSER_WARN_TOKEN_FORMAT(
7513 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7515 (
const char *) key_source,
7517 (
const char *) value_start
7543static const uint32_t context_terminators[] = {
7545 [
PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7548 [
PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7550 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7554 [
PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7555 [
PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7556 [
PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7557 [
PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7560 [
PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7561 [
PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7564 [
PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7569 [
PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7573 [
PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7575 [
PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7578 [
PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7581 [
PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7584 [
PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7588 [
PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7591 [
PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7594 [
PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7596 [
PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7603 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7614 while (context_node != NULL) {
7615 if (context_terminator(context_node->
context, token))
return context_node->
context;
7616 context_node = context_node->
prev;
7625 if (context_node == NULL)
return false;
7650 while (context_node != NULL) {
7651 if (context_node->
context == context)
return true;
7652 context_node = context_node->
prev;
7662 while (context_node != NULL) {
7663 switch (context_node->
context) {
7684 context_node = context_node->
prev;
7699 assert(
false &&
"unreachable");
7757 assert(
false &&
"unreachable");
7766pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
7767 if (invalid != NULL) {
7768 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
7769 pm_parser_err(parser, U32(invalid - parser->
start), 1, diag_id);
7774pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7775 const uint8_t *invalid = NULL;
7776 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
7777 pm_strspn_number_validate(parser,
string, length, invalid);
7782pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7783 const uint8_t *invalid = NULL;
7784 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
7785 pm_strspn_number_validate(parser,
string, length, invalid);
7790pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7791 const uint8_t *invalid = NULL;
7792 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
7793 pm_strspn_number_validate(parser,
string, length, invalid);
7798pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7799 const uint8_t *invalid = NULL;
7800 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
7801 pm_strspn_number_validate(parser,
string, length, invalid);
7805static pm_token_type_t
7806lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
7807 pm_token_type_t
type = PM_TOKEN_INTEGER;
7811 if (peek(parser) ==
'.') {
7812 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7814 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7815 type = PM_TOKEN_FLOAT;
7825 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
7826 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
7829 if (pm_char_is_decimal_digit(peek(parser))) {
7831 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7833 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
7835 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7837 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7843 type = PM_TOKEN_FLOAT;
7849static pm_token_type_t
7850lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
7851 pm_token_type_t
type = PM_TOKEN_INTEGER;
7854 if (peek_offset(parser, -1) ==
'0') {
7855 switch (*parser->
current.end) {
7860 if (pm_char_is_decimal_digit(peek(parser))) {
7861 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7864 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
7873 if (pm_char_is_binary_digit(peek(parser))) {
7874 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
7877 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
7887 if (pm_char_is_octal_digit(peek(parser))) {
7888 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
7891 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
7907 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
7915 if (pm_char_is_hexadecimal_digit(peek(parser))) {
7916 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
7919 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
7922 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
7927 type = lex_optional_float_suffix(parser, seen_e);
7934 type = lex_optional_float_suffix(parser, seen_e);
7941 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7944 type = lex_optional_float_suffix(parser, seen_e);
7950 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7951 const uint8_t *fraction_start = parser->
current.end;
7952 const uint8_t *fraction_end = parser->
current.end + 2;
7953 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
7954 pm_parser_err(parser, U32(fraction_start - parser->
start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
7960static pm_token_type_t
7962 pm_token_type_t
type = PM_TOKEN_INTEGER;
7966 bool seen_e =
false;
7967 type = lex_numeric_prefix(parser, &seen_e);
7969 const uint8_t *end = parser->
current.end;
7970 pm_token_type_t suffix_type =
type;
7972 if (
type == PM_TOKEN_INTEGER) {
7973 if (match(parser,
'r')) {
7974 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
7976 if (match(parser,
'i')) {
7977 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
7979 }
else if (match(parser,
'i')) {
7980 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
7983 if (!seen_e && match(parser,
'r')) {
7984 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
7986 if (match(parser,
'i')) {
7987 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
7989 }
else if (match(parser,
'i')) {
7990 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
7994 const uint8_t b = peek(parser);
7995 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8005static pm_token_type_t
8008 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8009 return PM_TOKEN_GLOBAL_VARIABLE;
8014 bool allow_multiple =
true;
8016 switch (*parser->
current.end) {
8034 return PM_TOKEN_GLOBAL_VARIABLE;
8041 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8047 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8050 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8054 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->
current, diag_id);
8057 return PM_TOKEN_GLOBAL_VARIABLE;
8070 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8074 allow_multiple =
false;
8079 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8082 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8083 }
else if (pm_char_is_whitespace(peek(parser))) {
8086 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8092 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), diag_id, (
int) (PM_TOKEN_LENGTH(&parser->
current) + U32(width)), (
const char *) parser->
current.start);
8095 return PM_TOKEN_GLOBAL_VARIABLE;
8112static inline pm_token_type_t
8113lex_keyword(
pm_parser_t *parser,
const uint8_t *current_start,
const char *value,
size_t vlen,
pm_lex_state_t state, pm_token_type_t
type, pm_token_type_t modifier_type) {
8114 if (memcmp(current_start, value, vlen) == 0) {
8117 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
8118 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8120 lex_state_set(parser, state);
8121 if (state == PM_LEX_STATE_BEG) {
8125 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8126 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8127 return modifier_type;
8134 return PM_TOKEN_EOF;
8137static pm_token_type_t
8138lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8141 const uint8_t *end = parser->
end;
8142 const uint8_t *current_start = parser->
current.start;
8143 const uint8_t *current_end = parser->
current.end;
8146 if (encoding_changed) {
8147 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8148 current_end += width;
8151 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8152 current_end += width;
8155 parser->
current.end = current_end;
8159 width = (size_t) (current_end - current_start);
8161 if (current_end < end) {
8162 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8168 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8169 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8173 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8174 (void) match(parser,
':');
8175 return PM_TOKEN_LABEL;
8178 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8179 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8180 return PM_TOKEN_KEYWORD_DEFINED;
8184 return PM_TOKEN_METHOD_NAME;
8187 if (lex_state_p(parser, PM_LEX_STATE_FNAME) && peek_offset(parser, 1) !=
'~' && peek_offset(parser, 1) !=
'>' && (peek_offset(parser, 1) !=
'=' || peek_offset(parser, 2) ==
'>') && match(parser,
'=')) {
8190 return PM_TOKEN_IDENTIFIER;
8194 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8195 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8199 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8200 (void) match(parser,
':');
8201 return PM_TOKEN_LABEL;
8205 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8206 pm_token_type_t
type;
8209 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8211 return PM_TOKEN_KEYWORD_DO;
8213 if (pm_do_loop_stack_p(parser)) {
8214 return PM_TOKEN_KEYWORD_DO_LOOP;
8216 if (!pm_accepts_block_stack_p(parser)) {
8217 return PM_TOKEN_KEYWORD_DO_BLOCK;
8219 return PM_TOKEN_KEYWORD_DO;
8222 if ((
type = lex_keyword(parser, current_start,
"if", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IF, PM_TOKEN_KEYWORD_IF_MODIFIER)) != PM_TOKEN_EOF)
return type;
8223 if ((
type = lex_keyword(parser, current_start,
"in", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8224 if ((
type = lex_keyword(parser, current_start,
"or", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_OR, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8227 if ((
type = lex_keyword(parser, current_start,
"and", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8228 if ((
type = lex_keyword(parser, current_start,
"def", width, PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8229 if ((
type = lex_keyword(parser, current_start,
"end", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8230 if ((
type = lex_keyword(parser, current_start,
"END", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8231 if ((
type = lex_keyword(parser, current_start,
"for", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8232 if ((
type = lex_keyword(parser, current_start,
"nil", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8233 if ((
type = lex_keyword(parser, current_start,
"not", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_NOT, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8236 if ((
type = lex_keyword(parser, current_start,
"case", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8237 if ((
type = lex_keyword(parser, current_start,
"else", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8238 if ((
type = lex_keyword(parser, current_start,
"next", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8239 if ((
type = lex_keyword(parser, current_start,
"redo", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8240 if ((
type = lex_keyword(parser, current_start,
"self", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8241 if ((
type = lex_keyword(parser, current_start,
"then", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8242 if ((
type = lex_keyword(parser, current_start,
"true", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8243 if ((
type = lex_keyword(parser, current_start,
"when", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8246 if ((
type = lex_keyword(parser, current_start,
"alias", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_ALIAS, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8247 if ((
type = lex_keyword(parser, current_start,
"begin", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8248 if ((
type = lex_keyword(parser, current_start,
"BEGIN", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8249 if ((
type = lex_keyword(parser, current_start,
"break", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8250 if ((
type = lex_keyword(parser, current_start,
"class", width, PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8251 if ((
type = lex_keyword(parser, current_start,
"elsif", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8252 if ((
type = lex_keyword(parser, current_start,
"false", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8253 if ((
type = lex_keyword(parser, current_start,
"retry", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8254 if ((
type = lex_keyword(parser, current_start,
"super", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8255 if ((
type = lex_keyword(parser, current_start,
"undef", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_UNDEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8256 if ((
type = lex_keyword(parser, current_start,
"until", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNTIL, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) != PM_TOKEN_EOF)
return type;
8257 if ((
type = lex_keyword(parser, current_start,
"while", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHILE, PM_TOKEN_KEYWORD_WHILE_MODIFIER)) != PM_TOKEN_EOF)
return type;
8258 if ((
type = lex_keyword(parser, current_start,
"yield", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_YIELD, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8261 if ((
type = lex_keyword(parser, current_start,
"ensure", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8262 if ((
type = lex_keyword(parser, current_start,
"module", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8263 if ((
type = lex_keyword(parser, current_start,
"rescue", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) != PM_TOKEN_EOF)
return type;
8264 if ((
type = lex_keyword(parser, current_start,
"return", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8265 if ((
type = lex_keyword(parser, current_start,
"unless", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNLESS, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) != PM_TOKEN_EOF)
return type;
8268 if ((
type = lex_keyword(parser, current_start,
"__LINE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8269 if ((
type = lex_keyword(parser, current_start,
"__FILE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___FILE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8272 if ((
type = lex_keyword(parser, current_start,
"__ENCODING__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8277 if (encoding_changed) {
8278 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8280 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8306static pm_token_type_t
8307lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8310 if (pound + 1 >= parser->
end) {
8311 parser->
current.end = pound + 1;
8312 return PM_TOKEN_STRING_CONTENT;
8321 if (pound + 2 >= parser->
end) {
8322 parser->
current.end = pound + 1;
8323 return PM_TOKEN_STRING_CONTENT;
8328 const uint8_t *variable = pound + 2;
8329 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
8331 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
8335 if (pound > parser->
current.start) {
8337 return PM_TOKEN_STRING_CONTENT;
8342 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8343 parser->
current.end = pound + 1;
8344 return PM_TOKEN_EMBVAR;
8350 parser->
current.end = pound + 1;
8356 if (pound + 2 >= parser->
end) {
8357 parser->
current.end = pound + 1;
8358 return PM_TOKEN_STRING_CONTENT;
8364 const uint8_t *check = pound + 2;
8366 if (pound[2] ==
'-') {
8367 if (pound + 3 >= parser->
end) {
8368 parser->
current.end = pound + 2;
8369 return PM_TOKEN_STRING_CONTENT;
8380 char_is_identifier_start(parser, check, parser->
end - check) ||
8381 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8386 if (pound > parser->
current.start) {
8388 return PM_TOKEN_STRING_CONTENT;
8393 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8394 parser->
current.end = pound + 1;
8395 return PM_TOKEN_EMBVAR;
8400 parser->
current.end = pound + 1;
8406 if (pound > parser->
current.start) {
8408 return PM_TOKEN_STRING_CONTENT;
8415 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8416 parser->
current.end = pound + 2;
8418 pm_do_loop_stack_push(parser,
false);
8419 return PM_TOKEN_EMBEXPR_BEGIN;
8424 parser->
current.end = pound + 1;
8429static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8430static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8431static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8432static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8433static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8438static const bool ascii_printable_chars[] = {
8439 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8441 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8442 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8443 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8444 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8445 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8446 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8450char_is_ascii_printable(
const uint8_t b) {
8451 return (b < 0x80) && ascii_printable_chars[b];
8458static inline uint8_t
8459escape_hexadecimal_digit(
const uint8_t value) {
8460 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8468static inline uint32_t
8469escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const pm_location_t *error_location,
const uint8_t flags) {
8471 for (
size_t index = 0; index < length; index++) {
8472 if (index != 0) value <<= 4;
8473 value |= escape_hexadecimal_digit(
string[index]);
8478 if (value >= 0xD800 && value <= 0xDFFF) {
8479 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8482 }
else if (error_location != NULL) {
8483 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
8485 pm_parser_err(parser, U32(
string - parser->
start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
8496static inline uint8_t
8497escape_byte(uint8_t value,
const uint8_t flags) {
8498 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8499 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8507escape_write_unicode(
pm_parser_t *parser,
pm_buffer_t *buffer,
const uint8_t flags,
const uint8_t *start,
const uint8_t *end, uint32_t value) {
8511 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8513 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8517 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->
start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->
explicit_encoding->
name);
8524 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8525 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8529 pm_parser_err(parser, U32(start - parser->
start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
8532 pm_buffer_append_byte(buffer, 0xEF);
8533 pm_buffer_append_byte(buffer, 0xBF);
8534 pm_buffer_append_byte(buffer, 0xBD);
8546 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8550 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
8557 pm_buffer_append_byte(buffer,
byte);
8577 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8578 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
8581 escape_write_byte_encoded(parser, buffer, flags,
byte);
8593 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
8597 if (*parser->
current.end ==
'\n') pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
8598 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
8599 }
else if (width > 1) {
8601 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
8602 pm_buffer_append_bytes(b, parser->
current.end, width);
8608 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8618escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
8619#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
8621 PM_PARSER_WARN_TOKEN_FORMAT(
8624 PM_WARN_INVALID_CHARACTER,
8638 uint8_t peeked = peek(parser);
8642 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
8647 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
8652 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
8657 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
8662 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
8667 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
8672 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
8677 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
8682 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
8687 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
8692 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
8695 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
8696 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
8699 if (pm_char_is_octal_digit(peek(parser))) {
8700 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8703 if (pm_char_is_octal_digit(peek(parser))) {
8704 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8709 value = escape_byte(value, flags);
8710 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
8714 const uint8_t *start = parser->
current.end - 1;
8717 uint8_t
byte = peek(parser);
8719 if (pm_char_is_hexadecimal_digit(
byte)) {
8720 uint8_t value = escape_hexadecimal_digit(
byte);
8723 byte = peek(parser);
8724 if (pm_char_is_hexadecimal_digit(
byte)) {
8725 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
8729 value = escape_byte(value, flags);
8730 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8731 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
8732 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
8734 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8738 escape_write_byte_encoded(parser, buffer, flags, value);
8740 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
8746 const uint8_t *start = parser->
current.end - 1;
8750 const uint8_t *start = parser->
current.end - 2;
8751 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->
start), U32(parser->
current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8752 }
else if (peek(parser) ==
'{') {
8753 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
8758 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8759 parser->
current.end += whitespace;
8760 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
8771 const uint8_t *extra_codepoints_start = NULL;
8772 int codepoints_count = 0;
8775 const uint8_t *unicode_start = parser->
current.end;
8776 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
8778 if (hexadecimal_length > 6) {
8780 pm_parser_err(parser, U32(unicode_start - parser->
start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
8781 }
else if (hexadecimal_length == 0) {
8784 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8789 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8791 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->
current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
8792 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->
current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8798 parser->
current.end += hexadecimal_length;
8800 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
8801 extra_codepoints_start = unicode_start;
8804 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
8805 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
8812 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
8813 pm_parser_err(parser, U32(extra_codepoints_start - parser->
start), U32(parser->
current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
8817 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->
start), U32(parser->
current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
8818 }
else if (peek(parser) ==
'}') {
8821 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8826 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8828 pm_parser_err(parser, U32(unicode_codepoints_start - parser->
start), U32(parser->
current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8832 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8833 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
8836 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
8839 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8840 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8842 const uint8_t *start = parser->
current.end - 2;
8843 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->
start), U32(parser->
current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8845 }
else if (length == 4) {
8846 uint32_t value = escape_unicode(parser, parser->
current.end, 4, NULL, flags);
8848 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8849 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
8852 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
8855 parser->
current.end += length;
8857 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8861 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8863 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
8872 if (flags & PM_ESCAPE_FLAG_CONTROL) {
8873 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
8877 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8881 uint8_t peeked = peek(parser);
8885 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
8891 if (match(parser,
'u') || match(parser,
'U')) {
8892 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current), PM_ERR_INVALID_ESCAPE_CHARACTER);
8896 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
8900 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
8901 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
8905 escape_read_warn(parser, flags, 0,
"\\t");
8906 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
8909 if (!char_is_ascii_printable(peeked)) {
8910 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8914 if (peeked ==
'\n') pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
8916 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
8923 if (flags & PM_ESCAPE_FLAG_CONTROL) {
8924 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
8927 if (peek(parser) !=
'-') {
8929 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
8935 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8939 uint8_t peeked = peek(parser);
8943 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
8949 if (match(parser,
'u') || match(parser,
'U')) {
8950 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current), PM_ERR_INVALID_ESCAPE_CHARACTER);
8954 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
8958 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
8959 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
8963 escape_read_warn(parser, flags, 0,
"\\t");
8964 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
8967 if (!char_is_ascii_printable(peeked)) {
8969 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
8973 if (peeked ==
'\n') pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
8975 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
8982 if (flags & PM_ESCAPE_FLAG_META) {
8983 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
8986 if (peek(parser) !=
'-') {
8988 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
8994 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
8998 uint8_t peeked = peek(parser);
9003 if (match(parser,
'u') || match(parser,
'U')) {
9004 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9008 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9012 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9013 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9017 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9018 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9021 if (!char_is_ascii_printable(peeked)) {
9023 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9027 if (peeked ==
'\n') pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
9029 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9034 if (peek_offset(parser, 1) ==
'\n') {
9035 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 2);
9037 escape_write_byte_encoded(parser, buffer, flags, escape_byte(
'\n', flags));
9043 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9045 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9049 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9051 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9083static pm_token_type_t
9085 if (lex_state_end_p(parser)) {
9086 lex_state_set(parser, PM_LEX_STATE_BEG);
9087 return PM_TOKEN_QUESTION_MARK;
9091 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9093 return PM_TOKEN_CHARACTER_LITERAL;
9096 if (pm_char_is_whitespace(*parser->
current.end)) {
9097 lex_state_set(parser, PM_LEX_STATE_BEG);
9098 return PM_TOKEN_QUESTION_MARK;
9101 lex_state_set(parser, PM_LEX_STATE_BEG);
9103 if (match(parser,
'\\')) {
9104 lex_state_set(parser, PM_LEX_STATE_END);
9107 pm_buffer_init_capacity(&buffer, 3);
9109 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9116 return PM_TOKEN_CHARACTER_LITERAL;
9125 (parser->
current.end + encoding_width >= parser->
end) ||
9126 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
9129 lex_state_set(parser, PM_LEX_STATE_END);
9130 parser->
current.end += encoding_width;
9132 return PM_TOKEN_CHARACTER_LITERAL;
9136 return PM_TOKEN_QUESTION_MARK;
9143static pm_token_type_t
9145 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9146 const uint8_t *end = parser->
end;
9149 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9152 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9155 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
9156 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9158 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9162 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
9164 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9165 pm_parser_err_token(parser, &parser->
current, diag_id);
9171 lex_mode_pop(parser);
9193 if (comment == NULL)
return NULL;
9197 .location = TOK2LOC(parser, &parser->
current)
9208static pm_token_type_t
9211 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9213 if (newline == NULL) {
9216 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
9217 parser->
current.end = newline + 1;
9220 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
9221 parser_lex_callback(parser);
9224 const uint8_t *comment_start = parser->
current.start;
9225 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9226 if (comment == NULL)
return PM_TOKEN_EOF;
9230 while (parser->
current.end + 4 <= parser->
end) {
9236 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
9239 pm_char_is_whitespace(parser->
current.end[4]) ||
9240 (parser->
current.end[4] ==
'\0') ||
9241 (parser->
current.end[4] ==
'\004') ||
9242 (parser->
current.end[4] ==
'\032')
9245 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9247 if (newline == NULL) {
9250 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
9251 parser->
current.end = newline + 1;
9254 parser->
current.type = PM_TOKEN_EMBDOC_END;
9255 parser_lex_callback(parser);
9260 return PM_TOKEN_EMBDOC_END;
9265 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9267 if (newline == NULL) {
9270 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
9271 parser->
current.end = newline + 1;
9274 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
9275 parser_lex_callback(parser);
9278 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9283 return PM_TOKEN_EOF;
9293 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
9294 parser_lex_callback(parser);
9318 const uint8_t *cursor = parser->
current.end;
9320 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9321 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9384 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9401 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9406 return (width == 0 ? 1 : width);
9414 size_t width = parser_char_width(parser);
9415 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
9421 size_t width = parser_char_width(parser);
9422 const uint8_t *start = parser->
current.end;
9423 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, width);
9424 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, width);
9439 pm_string_constant_init(&parser->
current_string, (
const char *) arena_data,
len);
9445 pm_token_buffer_copy(parser, &token_buffer->
base);
9460 if (token_buffer->
cursor == NULL) {
9463 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
9464 pm_token_buffer_copy(parser, token_buffer);
9473 const uint8_t *cursor = token_buffer->
base.
cursor;
9474 size_t length = (size_t) (parser->
current.end - cursor);
9475 pm_buffer_append_bytes(&token_buffer->
base.
buffer, cursor, length);
9476 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, cursor, length);
9477 pm_regexp_token_buffer_copy(parser, token_buffer);
9481#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9493 const uint8_t *start;
9494 if (token_buffer->
cursor == NULL) {
9495 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9496 start = parser->
current.start;
9498 start = token_buffer->
cursor;
9501 const uint8_t *end = parser->
current.end - 1;
9502 assert(end >= start);
9503 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9505 token_buffer->
cursor = end;
9510 const uint8_t *start;
9512 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9513 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9514 start = parser->
current.start;
9519 const uint8_t *end = parser->
current.end - 1;
9520 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9521 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9526#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9534 size_t whitespace = 0;
9537 case PM_HEREDOC_INDENT_NONE:
9542 case PM_HEREDOC_INDENT_DASH:
9544 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
9546 case PM_HEREDOC_INDENT_TILDE:
9549 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
9550 if (**cursor ==
'\t') {
9551 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
9570 size_t eol_length = match_eol(parser);
9577 parser_flush_heredoc_end(parser);
9580 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + U32(eol_length));
9583 uint8_t delimiter = *parser->
current.end;
9587 if (eol_length == 2) {
9588 delimiter = *(parser->
current.end + 1);
9591 parser->
current.end += eol_length;
9595 return *parser->
current.end++;
9602#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
9621 bool lexed_comment =
false;
9635 case PM_LEX_DEFAULT:
9636 case PM_LEX_EMBEXPR:
9653 bool space_seen =
false;
9657 bool chomping =
true;
9658 while (parser->
current.end < parser->
end && chomping) {
9659 switch (*parser->
current.end) {
9668 if (match_eol_offset(parser, 1)) {
9671 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->
current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
9677 size_t eol_length = match_eol_offset(parser, 1);
9683 parser->
current.end += eol_length + 1;
9684 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current));
9687 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
9711 lex_mode_pop(parser);
9712 goto switch_lex_modes;
9728 switch (*parser->
current.end++) {
9736 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9737 parser->
current.end = ending == NULL ? parser->
end : ending;
9742 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
9745 if (ending) parser->
current.end++;
9746 parser->
current.type = PM_TOKEN_COMMENT;
9747 parser_lex_callback(parser);
9759 parser_lex_magic_comment_encoding(parser);
9763 lexed_comment =
true;
9769 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
9781 if (!lexed_comment) {
9782 parser->
current.end += eol_length - 1;
9786 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current));
9791 parser_flush_heredoc_end(parser);
9796 switch (lex_state_ignored_p(parser)) {
9797 case PM_IGNORED_NEWLINE_NONE:
9799 case PM_IGNORED_NEWLINE_PATTERN:
9801 if (!lexed_comment) parser_lex_ignored_newline(parser);
9802 lex_state_set(parser, PM_LEX_STATE_BEG);
9804 parser->
current.type = PM_TOKEN_NEWLINE;
9808 case PM_IGNORED_NEWLINE_ALL:
9809 if (!lexed_comment) parser_lex_ignored_newline(parser);
9810 lexed_comment =
false;
9811 goto lex_next_token;
9819 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
9821 if (next_content < parser->end) {
9827 if (next_content[0] ==
'#') {
9829 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
9831 while (following && (following + 1 < parser->
end)) {
9833 following += pm_strspn_inline_whitespace(following, parser->
end - following);
9837 if (peek_at(parser, following) !=
'#')
break;
9841 following = next_newline(following, parser->
end - following);
9846 if (lex_state_ignored_p(parser)) {
9847 if (!lexed_comment) parser_lex_ignored_newline(parser);
9848 lexed_comment =
false;
9849 goto lex_next_token;
9855 (peek_at(parser, following) ==
'.') ||
9856 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
9858 if (!lexed_comment) parser_lex_ignored_newline(parser);
9859 lexed_comment =
false;
9860 goto lex_next_token;
9870 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
9871 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
9873 peek_at(parser, following) ==
'a' &&
9874 peek_at(parser, following + 1) ==
'n' &&
9875 peek_at(parser, following + 2) ==
'd' &&
9876 peek_at(parser, next_content + 3) !=
'!' &&
9877 peek_at(parser, next_content + 3) !=
'?' &&
9878 !char_is_identifier(parser, following + 3, parser->
end - (following + 3))
9881 peek_at(parser, following) ==
'o' &&
9882 peek_at(parser, following + 1) ==
'r' &&
9883 peek_at(parser, next_content + 2) !=
'!' &&
9884 peek_at(parser, next_content + 2) !=
'?' &&
9885 !char_is_identifier(parser, following + 2, parser->
end - (following + 2))
9889 if (!lexed_comment) parser_lex_ignored_newline(parser);
9890 lexed_comment =
false;
9891 goto lex_next_token;
9897 if (next_content[0] ==
'.') {
9901 if (peek_at(parser, next_content + 1) ==
'.') {
9902 if (!lexed_comment) parser_lex_ignored_newline(parser);
9903 lex_state_set(parser, PM_LEX_STATE_BEG);
9905 parser->
current.type = PM_TOKEN_NEWLINE;
9909 if (!lexed_comment) parser_lex_ignored_newline(parser);
9910 lex_state_set(parser, PM_LEX_STATE_DOT);
9911 parser->
current.start = next_content;
9912 parser->
current.end = next_content + 1;
9919 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
9920 if (!lexed_comment) parser_lex_ignored_newline(parser);
9921 lex_state_set(parser, PM_LEX_STATE_DOT);
9922 parser->
current.start = next_content;
9923 parser->
current.end = next_content + 2;
9925 LEX(PM_TOKEN_AMPERSAND_DOT);
9931 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
9932 if (!lexed_comment) parser_lex_ignored_newline(parser);
9933 lex_state_set(parser, PM_LEX_STATE_BEG);
9934 parser->
current.start = next_content;
9935 parser->
current.end = next_content + 2;
9937 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
9942 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
9943 if (!lexed_comment) parser_lex_ignored_newline(parser);
9944 lex_state_set(parser, PM_LEX_STATE_BEG);
9945 parser->
current.start = next_content;
9946 parser->
current.end = next_content + 2;
9948 LEX(PM_TOKEN_PIPE_PIPE);
9954 peek_at(parser, next_content) ==
'a' &&
9955 peek_at(parser, next_content + 1) ==
'n' &&
9956 peek_at(parser, next_content + 2) ==
'd' &&
9957 peek_at(parser, next_content + 3) !=
'!' &&
9958 peek_at(parser, next_content + 3) !=
'?' &&
9959 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
9961 if (!lexed_comment) parser_lex_ignored_newline(parser);
9962 lex_state_set(parser, PM_LEX_STATE_BEG);
9963 parser->
current.start = next_content;
9964 parser->
current.end = next_content + 3;
9967 LEX(PM_TOKEN_KEYWORD_AND);
9973 peek_at(parser, next_content) ==
'o' &&
9974 peek_at(parser, next_content + 1) ==
'r' &&
9975 peek_at(parser, next_content + 2) !=
'!' &&
9976 peek_at(parser, next_content + 2) !=
'?' &&
9977 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
9979 if (!lexed_comment) parser_lex_ignored_newline(parser);
9980 lex_state_set(parser, PM_LEX_STATE_BEG);
9981 parser->
current.start = next_content;
9982 parser->
current.end = next_content + 2;
9985 LEX(PM_TOKEN_KEYWORD_OR);
9992 lex_state_set(parser, PM_LEX_STATE_BEG);
9994 parser->
current.type = PM_TOKEN_NEWLINE;
9995 if (!lexed_comment) parser_lex_callback(parser);
10005 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10006 LEX(PM_TOKEN_COMMA);
10010 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10012 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10013 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10017 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10018 pm_do_loop_stack_push(parser,
false);
10025 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10026 pm_do_loop_stack_pop(parser);
10027 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10031 lex_state_set(parser, PM_LEX_STATE_BEG);
10033 LEX(PM_TOKEN_SEMICOLON);
10038 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10040 if (lex_state_operator_p(parser)) {
10041 if (match(parser,
']')) {
10043 lex_state_set(parser, PM_LEX_STATE_ARG);
10044 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10047 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10051 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10052 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10055 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10056 pm_do_loop_stack_push(parser,
false);
10062 lex_state_set(parser, PM_LEX_STATE_END);
10063 pm_do_loop_stack_pop(parser);
10064 LEX(PM_TOKEN_BRACKET_RIGHT);
10068 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10073 lex_state_set(parser, PM_LEX_STATE_BEG);
10074 type = PM_TOKEN_LAMBDA_BEGIN;
10075 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10077 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10078 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10081 lex_state_set(parser, PM_LEX_STATE_BEG);
10082 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10085 lex_state_set(parser, PM_LEX_STATE_BEG);
10088 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10093 pm_do_loop_stack_push(parser,
false);
10101 pm_do_loop_stack_pop(parser);
10104 lex_mode_pop(parser);
10105 LEX(PM_TOKEN_EMBEXPR_END);
10109 lex_state_set(parser, PM_LEX_STATE_END);
10110 LEX(PM_TOKEN_BRACE_RIGHT);
10114 if (match(parser,
'*')) {
10115 if (match(parser,
'=')) {
10116 lex_state_set(parser, PM_LEX_STATE_BEG);
10117 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10120 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10122 if (lex_state_spcarg_p(parser, space_seen)) {
10123 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10124 type = PM_TOKEN_USTAR_STAR;
10125 }
else if (lex_state_beg_p(parser)) {
10126 type = PM_TOKEN_USTAR_STAR;
10127 }
else if (ambiguous_operator_p(parser, space_seen)) {
10128 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10131 if (lex_state_operator_p(parser)) {
10132 lex_state_set(parser, PM_LEX_STATE_ARG);
10134 lex_state_set(parser, PM_LEX_STATE_BEG);
10140 if (match(parser,
'=')) {
10141 lex_state_set(parser, PM_LEX_STATE_BEG);
10142 LEX(PM_TOKEN_STAR_EQUAL);
10145 pm_token_type_t
type = PM_TOKEN_STAR;
10147 if (lex_state_spcarg_p(parser, space_seen)) {
10148 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10149 type = PM_TOKEN_USTAR;
10150 }
else if (lex_state_beg_p(parser)) {
10151 type = PM_TOKEN_USTAR;
10152 }
else if (ambiguous_operator_p(parser, space_seen)) {
10153 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10156 if (lex_state_operator_p(parser)) {
10157 lex_state_set(parser, PM_LEX_STATE_ARG);
10159 lex_state_set(parser, PM_LEX_STATE_BEG);
10167 if (lex_state_operator_p(parser)) {
10168 lex_state_set(parser, PM_LEX_STATE_ARG);
10169 if (match(parser,
'@')) {
10170 LEX(PM_TOKEN_BANG);
10173 lex_state_set(parser, PM_LEX_STATE_BEG);
10176 if (match(parser,
'=')) {
10177 LEX(PM_TOKEN_BANG_EQUAL);
10180 if (match(parser,
'~')) {
10181 LEX(PM_TOKEN_BANG_TILDE);
10184 LEX(PM_TOKEN_BANG);
10189 current_token_starts_line(parser) &&
10191 memcmp(parser->
current.end,
"begin", 5) == 0 &&
10192 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10194 pm_token_type_t
type = lex_embdoc(parser);
10195 if (
type == PM_TOKEN_EOF) {
10199 goto lex_next_token;
10202 if (lex_state_operator_p(parser)) {
10203 lex_state_set(parser, PM_LEX_STATE_ARG);
10205 lex_state_set(parser, PM_LEX_STATE_BEG);
10208 if (match(parser,
'>')) {
10209 LEX(PM_TOKEN_EQUAL_GREATER);
10212 if (match(parser,
'~')) {
10213 LEX(PM_TOKEN_EQUAL_TILDE);
10216 if (match(parser,
'=')) {
10217 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10220 LEX(PM_TOKEN_EQUAL);
10224 if (match(parser,
'<')) {
10226 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10227 !lex_state_end_p(parser) &&
10228 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10230 const uint8_t *end = parser->
current.end;
10235 if (match(parser,
'-')) {
10236 indent = PM_HEREDOC_INDENT_DASH;
10238 else if (match(parser,
'~')) {
10239 indent = PM_HEREDOC_INDENT_TILDE;
10242 if (match(parser,
'`')) {
10243 quote = PM_HEREDOC_QUOTE_BACKTICK;
10245 else if (match(parser,
'"')) {
10246 quote = PM_HEREDOC_QUOTE_DOUBLE;
10248 else if (match(parser,
'\'')) {
10249 quote = PM_HEREDOC_QUOTE_SINGLE;
10252 const uint8_t *ident_start = parser->
current.end;
10257 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
10260 if (quote == PM_HEREDOC_QUOTE_NONE) {
10261 parser->
current.end += width;
10263 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
10264 parser->
current.end += width;
10270 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
10275 size_t ident_length = (size_t) (parser->
current.end - ident_start);
10276 bool ident_error =
false;
10278 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10279 pm_parser_err(parser, U32(ident_start - parser->
start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10280 ident_error =
true;
10285 .mode = PM_LEX_HEREDOC,
10288 .ident_start = ident_start,
10289 .ident_length = ident_length,
10293 .next_start = parser->
current.end,
10295 .line_continuation =
false
10300 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10302 if (body_start == NULL) {
10307 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10308 body_start = parser->
end;
10312 pm_line_offset_list_append(&parser->
line_offsets, U32(body_start - parser->
start + 1));
10321 LEX(PM_TOKEN_HEREDOC_START);
10325 if (match(parser,
'=')) {
10326 lex_state_set(parser, PM_LEX_STATE_BEG);
10327 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10330 if (ambiguous_operator_p(parser, space_seen)) {
10331 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10334 if (lex_state_operator_p(parser)) {
10335 lex_state_set(parser, PM_LEX_STATE_ARG);
10337 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10338 lex_state_set(parser, PM_LEX_STATE_BEG);
10341 LEX(PM_TOKEN_LESS_LESS);
10344 if (lex_state_operator_p(parser)) {
10345 lex_state_set(parser, PM_LEX_STATE_ARG);
10347 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10348 lex_state_set(parser, PM_LEX_STATE_BEG);
10351 if (match(parser,
'=')) {
10352 if (match(parser,
'>')) {
10353 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10356 LEX(PM_TOKEN_LESS_EQUAL);
10359 LEX(PM_TOKEN_LESS);
10363 if (match(parser,
'>')) {
10364 if (lex_state_operator_p(parser)) {
10365 lex_state_set(parser, PM_LEX_STATE_ARG);
10367 lex_state_set(parser, PM_LEX_STATE_BEG);
10369 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10372 if (lex_state_operator_p(parser)) {
10373 lex_state_set(parser, PM_LEX_STATE_ARG);
10375 lex_state_set(parser, PM_LEX_STATE_BEG);
10378 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10382 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10383 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10384 LEX(PM_TOKEN_STRING_BEGIN);
10389 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10390 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10391 LEX(PM_TOKEN_BACKTICK);
10394 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10395 if (previous_command_start) {
10396 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10398 lex_state_set(parser, PM_LEX_STATE_ARG);
10401 LEX(PM_TOKEN_BACKTICK);
10404 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10405 LEX(PM_TOKEN_BACKTICK);
10410 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10411 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10412 LEX(PM_TOKEN_STRING_BEGIN);
10417 LEX(lex_question_mark(parser));
10421 if (match(parser,
'&')) {
10422 lex_state_set(parser, PM_LEX_STATE_BEG);
10424 if (match(parser,
'=')) {
10425 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10428 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10431 if (match(parser,
'=')) {
10432 lex_state_set(parser, PM_LEX_STATE_BEG);
10433 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10436 if (match(parser,
'.')) {
10437 lex_state_set(parser, PM_LEX_STATE_DOT);
10438 LEX(PM_TOKEN_AMPERSAND_DOT);
10441 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10442 if (lex_state_spcarg_p(parser, space_seen)) {
10443 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10444 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10446 const uint8_t delim = peek_offset(parser, 1);
10448 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
10449 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10453 type = PM_TOKEN_UAMPERSAND;
10454 }
else if (lex_state_beg_p(parser)) {
10455 type = PM_TOKEN_UAMPERSAND;
10456 }
else if (ambiguous_operator_p(parser, space_seen)) {
10457 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10460 if (lex_state_operator_p(parser)) {
10461 lex_state_set(parser, PM_LEX_STATE_ARG);
10463 lex_state_set(parser, PM_LEX_STATE_BEG);
10471 if (match(parser,
'|')) {
10472 if (match(parser,
'=')) {
10473 lex_state_set(parser, PM_LEX_STATE_BEG);
10474 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10477 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10479 LEX(PM_TOKEN_PIPE);
10482 lex_state_set(parser, PM_LEX_STATE_BEG);
10483 LEX(PM_TOKEN_PIPE_PIPE);
10486 if (match(parser,
'=')) {
10487 lex_state_set(parser, PM_LEX_STATE_BEG);
10488 LEX(PM_TOKEN_PIPE_EQUAL);
10491 if (lex_state_operator_p(parser)) {
10492 lex_state_set(parser, PM_LEX_STATE_ARG);
10494 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10497 LEX(PM_TOKEN_PIPE);
10501 if (lex_state_operator_p(parser)) {
10502 lex_state_set(parser, PM_LEX_STATE_ARG);
10504 if (match(parser,
'@')) {
10505 LEX(PM_TOKEN_UPLUS);
10508 LEX(PM_TOKEN_PLUS);
10511 if (match(parser,
'=')) {
10512 lex_state_set(parser, PM_LEX_STATE_BEG);
10513 LEX(PM_TOKEN_PLUS_EQUAL);
10517 lex_state_beg_p(parser) ||
10518 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
10520 lex_state_set(parser, PM_LEX_STATE_BEG);
10522 if (pm_char_is_decimal_digit(peek(parser))) {
10524 pm_token_type_t
type = lex_numeric(parser);
10525 lex_state_set(parser, PM_LEX_STATE_END);
10529 LEX(PM_TOKEN_UPLUS);
10532 if (ambiguous_operator_p(parser, space_seen)) {
10533 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
10536 lex_state_set(parser, PM_LEX_STATE_BEG);
10537 LEX(PM_TOKEN_PLUS);
10542 if (lex_state_operator_p(parser)) {
10543 lex_state_set(parser, PM_LEX_STATE_ARG);
10545 if (match(parser,
'@')) {
10546 LEX(PM_TOKEN_UMINUS);
10549 LEX(PM_TOKEN_MINUS);
10552 if (match(parser,
'=')) {
10553 lex_state_set(parser, PM_LEX_STATE_BEG);
10554 LEX(PM_TOKEN_MINUS_EQUAL);
10557 if (match(parser,
'>')) {
10558 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10559 LEX(PM_TOKEN_MINUS_GREATER);
10562 bool spcarg = lex_state_spcarg_p(parser, space_seen);
10563 bool is_beg = lex_state_beg_p(parser);
10564 if (!is_beg && spcarg) {
10565 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
10568 if (is_beg || spcarg) {
10569 lex_state_set(parser, PM_LEX_STATE_BEG);
10570 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
10573 if (ambiguous_operator_p(parser, space_seen)) {
10574 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
10577 lex_state_set(parser, PM_LEX_STATE_BEG);
10578 LEX(PM_TOKEN_MINUS);
10583 bool beg_p = lex_state_beg_p(parser);
10585 if (match(parser,
'.')) {
10586 if (match(parser,
'.')) {
10589 if (lex_state_p(parser, PM_LEX_STATE_END)) {
10590 lex_state_set(parser, PM_LEX_STATE_BEG);
10592 lex_state_set(parser, PM_LEX_STATE_ENDARG);
10594 LEX(PM_TOKEN_UDOT_DOT_DOT);
10598 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
10601 lex_state_set(parser, PM_LEX_STATE_BEG);
10602 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
10605 lex_state_set(parser, PM_LEX_STATE_BEG);
10606 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
10609 lex_state_set(parser, PM_LEX_STATE_DOT);
10624 pm_token_type_t
type = lex_numeric(parser);
10625 lex_state_set(parser, PM_LEX_STATE_END);
10631 if (match(parser,
':')) {
10632 if (lex_state_beg_p(parser) || lex_state_p(parser, PM_LEX_STATE_CLASS) || (lex_state_p(parser, PM_LEX_STATE_ARG_ANY) && space_seen)) {
10633 lex_state_set(parser, PM_LEX_STATE_BEG);
10634 LEX(PM_TOKEN_UCOLON_COLON);
10637 lex_state_set(parser, PM_LEX_STATE_DOT);
10638 LEX(PM_TOKEN_COLON_COLON);
10641 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
10642 lex_state_set(parser, PM_LEX_STATE_BEG);
10643 LEX(PM_TOKEN_COLON);
10646 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
10647 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
10651 lex_state_set(parser, PM_LEX_STATE_FNAME);
10652 LEX(PM_TOKEN_SYMBOL_BEGIN);
10656 if (lex_state_beg_p(parser)) {
10657 lex_mode_push_regexp(parser,
'\0',
'/');
10658 LEX(PM_TOKEN_REGEXP_BEGIN);
10661 if (match(parser,
'=')) {
10662 lex_state_set(parser, PM_LEX_STATE_BEG);
10663 LEX(PM_TOKEN_SLASH_EQUAL);
10666 if (lex_state_spcarg_p(parser, space_seen)) {
10667 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
10668 lex_mode_push_regexp(parser,
'\0',
'/');
10669 LEX(PM_TOKEN_REGEXP_BEGIN);
10672 if (ambiguous_operator_p(parser, space_seen)) {
10673 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
10676 if (lex_state_operator_p(parser)) {
10677 lex_state_set(parser, PM_LEX_STATE_ARG);
10679 lex_state_set(parser, PM_LEX_STATE_BEG);
10682 LEX(PM_TOKEN_SLASH);
10686 if (lex_state_operator_p(parser)) {
10687 lex_state_set(parser, PM_LEX_STATE_ARG);
10689 lex_state_set(parser, PM_LEX_STATE_BEG);
10691 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
10695 if (lex_state_operator_p(parser)) {
10696 (void) match(parser,
'@');
10697 lex_state_set(parser, PM_LEX_STATE_ARG);
10699 lex_state_set(parser, PM_LEX_STATE_BEG);
10702 LEX(PM_TOKEN_TILDE);
10710 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
10711 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
10712 LEX(PM_TOKEN_PERCENT);
10715 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
10716 lex_state_set(parser, PM_LEX_STATE_BEG);
10717 LEX(PM_TOKEN_PERCENT_EQUAL);
10719 lex_state_beg_p(parser) ||
10720 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
10721 lex_state_spcarg_p(parser, space_seen)
10724 if (*parser->
current.end >= 0x80) {
10725 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10728 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10729 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10730 LEX(PM_TOKEN_STRING_BEGIN);
10735 uint8_t delimiter = peek_offset(parser, 1);
10737 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10738 goto lex_next_token;
10741 switch (peek(parser)) {
10746 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10748 lex_mode_push_list_eof(parser);
10751 LEX(PM_TOKEN_PERCENT_LOWER_I);
10757 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10759 lex_mode_push_list_eof(parser);
10762 LEX(PM_TOKEN_PERCENT_UPPER_I);
10768 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10769 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10771 lex_mode_push_regexp(parser,
'\0',
'\0');
10774 LEX(PM_TOKEN_REGEXP_BEGIN);
10780 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10781 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10783 lex_mode_push_string_eof(parser);
10786 LEX(PM_TOKEN_STRING_BEGIN);
10792 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10793 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10795 lex_mode_push_string_eof(parser);
10798 LEX(PM_TOKEN_STRING_BEGIN);
10804 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10805 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10806 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
10808 lex_mode_push_string_eof(parser);
10811 LEX(PM_TOKEN_SYMBOL_BEGIN);
10817 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10819 lex_mode_push_list_eof(parser);
10822 LEX(PM_TOKEN_PERCENT_LOWER_W);
10828 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10830 lex_mode_push_list_eof(parser);
10833 LEX(PM_TOKEN_PERCENT_UPPER_W);
10839 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10840 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10842 lex_mode_push_string_eof(parser);
10845 LEX(PM_TOKEN_PERCENT_LOWER_X);
10852 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10853 goto lex_next_token;
10857 if (ambiguous_operator_p(parser, space_seen)) {
10858 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
10861 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
10862 LEX(PM_TOKEN_PERCENT);
10867 pm_token_type_t
type = lex_global_variable(parser);
10872 lex_mode_pop(parser);
10875 lex_state_set(parser, PM_LEX_STATE_END);
10881 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
10882 LEX(lex_at_variable(parser));
10885 if (*parser->
current.start !=
'_') {
10886 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
10893 if (*parser->
current.start >= 0x80) {
10894 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
10895 }
else if (*parser->
current.start ==
'\\') {
10896 switch (peek_at(parser, parser->
current.start + 1)) {
10899 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
10903 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
10907 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
10911 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
10914 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
10916 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
10921 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
10924 }
else if (char_is_ascii_printable(*parser->
current.start)) {
10925 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
10927 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
10930 goto lex_next_token;
10936 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
10944 current_token_starts_line(parser) &&
10945 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
10946 (parser->
current.end == parser->
end || match_eol(parser))
10951 const uint8_t *cursor = parser->
current.end;
10952 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
10953 pm_line_offset_list_append(&parser->
line_offsets, U32(++cursor - parser->
start));
10957 parser->
current.type = PM_TOKEN___END__;
10958 parser_lex_callback(parser);
10968 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
10969 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
10970 if (previous_command_start) {
10971 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10973 lex_state_set(parser, PM_LEX_STATE_ARG);
10975 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
10976 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10978 lex_state_set(parser, PM_LEX_STATE_END);
10983 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
10984 (
type == PM_TOKEN_IDENTIFIER) &&
10985 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
10986 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)))
10988 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
10995 case PM_LEX_LIST: {
11009 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11010 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11017 if (whitespace > 0) {
11018 parser->
current.end += whitespace;
11019 if (peek_offset(parser, -1) ==
'\n') {
11021 parser_flush_heredoc_end(parser);
11023 LEX(PM_TOKEN_WORDS_SEP);
11035 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11036 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11042 while (breakpoint != NULL) {
11045 if (pm_char_is_whitespace(*breakpoint)) {
11046 parser->
current.end = breakpoint;
11047 pm_token_buffer_flush(parser, &token_buffer);
11048 LEX(PM_TOKEN_STRING_CONTENT);
11057 parser->
current.end = breakpoint + 1;
11058 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11065 if (breakpoint > parser->
current.start) {
11066 parser->
current.end = breakpoint;
11067 pm_token_buffer_flush(parser, &token_buffer);
11068 LEX(PM_TOKEN_STRING_CONTENT);
11073 parser->
current.end = breakpoint + 1;
11074 lex_mode_pop(parser);
11075 lex_state_set(parser, PM_LEX_STATE_END);
11076 LEX(PM_TOKEN_STRING_END);
11080 if (*breakpoint ==
'\0') {
11081 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11088 if (*breakpoint ==
'\\') {
11089 parser->
current.end = breakpoint + 1;
11098 pm_token_buffer_escape(parser, &token_buffer);
11099 uint8_t peeked = peek(parser);
11107 pm_token_buffer_push_byte(&token_buffer, peeked);
11112 if (peek(parser) !=
'\n') {
11113 pm_token_buffer_push_byte(&token_buffer,
'\r');
11118 pm_token_buffer_push_byte(&token_buffer,
'\n');
11124 parser_flush_heredoc_end(parser);
11125 pm_token_buffer_copy(parser, &token_buffer);
11126 LEX(PM_TOKEN_STRING_CONTENT);
11129 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
11136 pm_token_buffer_push_byte(&token_buffer, peeked);
11139 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11141 pm_token_buffer_push_byte(&token_buffer,
'\\');
11142 pm_token_buffer_push_escaped(&token_buffer, parser);
11149 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11154 if (*breakpoint ==
'#') {
11155 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11162 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11166 if (
type == PM_TOKEN_STRING_CONTENT) {
11167 pm_token_buffer_flush(parser, &token_buffer);
11176 parser->
current.end = breakpoint + 1;
11177 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11183 pm_token_buffer_flush(parser, &token_buffer);
11184 LEX(PM_TOKEN_STRING_CONTENT);
11190 pm_token_buffer_flush(parser, &token_buffer);
11191 LEX(PM_TOKEN_STRING_CONTENT);
11193 case PM_LEX_REGEXP: {
11215 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
11216 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11219 while (breakpoint != NULL) {
11221 bool is_terminator = (*breakpoint == term);
11226 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11227 if (term ==
'\n') {
11228 is_terminator =
true;
11234 if (term ==
'\r') {
11235 is_terminator =
false;
11241 if (is_terminator) {
11243 parser->
current.end = breakpoint + 1;
11244 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11252 if (breakpoint > parser->
current.start) {
11253 parser->
current.end = breakpoint;
11254 pm_regexp_token_buffer_flush(parser, &token_buffer);
11255 LEX(PM_TOKEN_STRING_CONTENT);
11259 size_t eol_length = match_eol_at(parser, breakpoint);
11261 parser->
current.end = breakpoint + eol_length;
11267 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current));
11270 parser->
current.end = breakpoint + 1;
11277 lex_mode_pop(parser);
11278 lex_state_set(parser, PM_LEX_STATE_END);
11279 LEX(PM_TOKEN_REGEXP_END);
11284 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
11285 parser->
current.end = breakpoint + 1;
11286 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11291 switch (*breakpoint) {
11294 parser->
current.end = breakpoint + 1;
11295 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11298 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11299 parser->
current.end = breakpoint + 1;
11300 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11305 parser->
current.end = breakpoint;
11306 pm_regexp_token_buffer_escape(parser, &token_buffer);
11314 pm_line_offset_list_append(&parser->
line_offsets, U32(breakpoint - parser->
start + 1));
11315 parser->
current.end = breakpoint + 1;
11316 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11320 parser->
current.end = breakpoint + 1;
11321 parser_flush_heredoc_end(parser);
11322 pm_regexp_token_buffer_flush(parser, &token_buffer);
11323 LEX(PM_TOKEN_STRING_CONTENT);
11328 parser->
current.end = breakpoint + 1;
11337 pm_regexp_token_buffer_escape(parser, &token_buffer);
11338 uint8_t peeked = peek(parser);
11343 if (peek(parser) !=
'\n') {
11345 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11347 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11348 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11357 parser_flush_heredoc_end(parser);
11358 pm_regexp_token_buffer_copy(parser, &token_buffer);
11359 LEX(PM_TOKEN_STRING_CONTENT);
11362 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
11380 case '$':
case ')':
case '*':
case '+':
11381 case '.':
case '>':
case '?':
case ']':
11382 case '^':
case '|':
case '}':
11383 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11389 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11390 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11395 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11396 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11401 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11407 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11414 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11418 if (
type == PM_TOKEN_STRING_CONTENT) {
11419 pm_regexp_token_buffer_flush(parser, &token_buffer);
11425 assert(
false &&
"unreachable");
11431 pm_regexp_token_buffer_flush(parser, &token_buffer);
11432 LEX(PM_TOKEN_STRING_CONTENT);
11438 pm_regexp_token_buffer_flush(parser, &token_buffer);
11439 LEX(PM_TOKEN_STRING_CONTENT);
11441 case PM_LEX_STRING: {
11460 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
11461 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11467 while (breakpoint != NULL) {
11472 parser->
current.end = breakpoint + 1;
11473 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11478 bool is_terminator = (*breakpoint == term);
11483 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11484 if (term ==
'\n') {
11485 is_terminator =
true;
11491 if (term ==
'\r') {
11492 is_terminator =
false;
11499 if (is_terminator) {
11503 parser->
current.end = breakpoint + 1;
11504 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11511 if (breakpoint > parser->
current.start) {
11512 parser->
current.end = breakpoint;
11513 pm_token_buffer_flush(parser, &token_buffer);
11514 LEX(PM_TOKEN_STRING_CONTENT);
11519 size_t eol_length = match_eol_at(parser, breakpoint);
11521 parser->
current.end = breakpoint + eol_length;
11527 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current));
11530 parser->
current.end = breakpoint + 1;
11533 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
11535 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
11536 lex_mode_pop(parser);
11537 LEX(PM_TOKEN_LABEL_END);
11544 parser_flush_heredoc_end(parser);
11547 lex_state_set(parser, PM_LEX_STATE_END);
11548 lex_mode_pop(parser);
11549 LEX(PM_TOKEN_STRING_END);
11552 switch (*breakpoint) {
11555 parser->
current.end = breakpoint + 1;
11556 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11559 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11560 parser->
current.end = breakpoint + 1;
11561 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11568 parser->
current.end = breakpoint;
11569 pm_token_buffer_escape(parser, &token_buffer);
11570 token_buffer.
cursor = breakpoint;
11579 pm_line_offset_list_append(&parser->
line_offsets, U32(breakpoint - parser->
start + 1));
11580 parser->
current.end = breakpoint + 1;
11581 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11585 parser->
current.end = breakpoint + 1;
11586 parser_flush_heredoc_end(parser);
11587 pm_token_buffer_flush(parser, &token_buffer);
11588 LEX(PM_TOKEN_STRING_CONTENT);
11591 parser->
current.end = breakpoint + 1;
11600 pm_token_buffer_escape(parser, &token_buffer);
11601 uint8_t peeked = peek(parser);
11605 pm_token_buffer_push_byte(&token_buffer,
'\\');
11610 if (peek(parser) !=
'\n') {
11612 pm_token_buffer_push_byte(&token_buffer,
'\\');
11614 pm_token_buffer_push_byte(&token_buffer,
'\r');
11620 pm_token_buffer_push_byte(&token_buffer,
'\\');
11621 pm_token_buffer_push_byte(&token_buffer,
'\n');
11628 parser_flush_heredoc_end(parser);
11629 pm_token_buffer_copy(parser, &token_buffer);
11630 LEX(PM_TOKEN_STRING_CONTENT);
11633 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
11640 pm_token_buffer_push_byte(&token_buffer, peeked);
11643 pm_token_buffer_push_byte(&token_buffer, peeked);
11646 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11648 pm_token_buffer_push_byte(&token_buffer,
'\\');
11649 pm_token_buffer_push_escaped(&token_buffer, parser);
11656 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11660 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11667 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11671 if (
type == PM_TOKEN_STRING_CONTENT) {
11672 pm_token_buffer_flush(parser, &token_buffer);
11678 assert(
false &&
"unreachable");
11683 pm_token_buffer_flush(parser, &token_buffer);
11684 LEX(PM_TOKEN_STRING_CONTENT);
11690 pm_token_buffer_flush(parser, &token_buffer);
11691 LEX(PM_TOKEN_STRING_CONTENT);
11693 case PM_LEX_HEREDOC: {
11720 lex_state_set(parser, PM_LEX_STATE_END);
11721 lex_mode_pop(parser);
11722 LEX(PM_TOKEN_HEREDOC_END);
11725 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
11730 if (current_token_starts_line(parser)) {
11731 const uint8_t *start = parser->
current.start;
11733 if (!line_continuation && (start + ident_length <= parser->end)) {
11734 const uint8_t *newline = next_newline(start, parser->
end - start);
11735 const uint8_t *ident_end = newline;
11736 const uint8_t *terminator_end = newline;
11738 if (newline == NULL) {
11739 terminator_end = parser->
end;
11740 ident_end = parser->
end;
11743 if (newline[-1] ==
'\r') {
11748 const uint8_t *terminator_start = ident_end - ident_length;
11749 const uint8_t *cursor = start;
11751 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11752 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11758 (cursor == terminator_start) &&
11759 (memcmp(terminator_start, ident_start, ident_length) == 0)
11761 if (newline != NULL) {
11762 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
11765 parser->
current.end = terminator_end;
11773 lex_state_set(parser, PM_LEX_STATE_END);
11774 lex_mode_pop(parser);
11775 LEX(PM_TOKEN_HEREDOC_END);
11779 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
11781 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
11784 peek_at(parser, start) !=
'\n'
11793 uint8_t breakpoints[] =
"\r\n\\#";
11796 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11797 breakpoints[3] =
'\0';
11800 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11802 bool was_line_continuation =
false;
11804 while (breakpoint != NULL) {
11805 switch (*breakpoint) {
11808 parser->
current.end = breakpoint + 1;
11809 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11812 parser->
current.end = breakpoint + 1;
11814 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11815 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11822 pm_token_buffer_escape(parser, &token_buffer);
11823 token_buffer.
cursor = breakpoint;
11828 parser_flush_heredoc_end(parser);
11829 parser->
current.end = breakpoint + 1;
11830 pm_token_buffer_flush(parser, &token_buffer);
11831 LEX(PM_TOKEN_STRING_CONTENT);
11834 pm_line_offset_list_append(&parser->
line_offsets, U32(breakpoint - parser->
start + 1));
11838 const uint8_t *start = breakpoint + 1;
11840 if (!was_line_continuation && (start + ident_length <= parser->end)) {
11843 const uint8_t *newline = next_newline(start, parser->
end - start);
11845 if (newline == NULL) {
11846 newline = parser->
end;
11847 }
else if (newline[-1] ==
'\r') {
11852 const uint8_t *terminator_start = newline - ident_length;
11856 const uint8_t *cursor = start;
11858 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11859 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11865 cursor == terminator_start &&
11866 (memcmp(terminator_start, ident_start, ident_length) == 0)
11868 parser->
current.end = breakpoint + 1;
11869 pm_token_buffer_flush(parser, &token_buffer);
11870 LEX(PM_TOKEN_STRING_CONTENT);
11874 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
11881 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
11886 parser->
current.end = breakpoint + 1;
11887 pm_token_buffer_flush(parser, &token_buffer);
11888 LEX(PM_TOKEN_STRING_CONTENT);
11893 parser->
current.end = breakpoint + 1;
11894 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11904 parser->
current.end = breakpoint + 1;
11913 pm_token_buffer_escape(parser, &token_buffer);
11914 uint8_t peeked = peek(parser);
11916 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11920 if (peek(parser) !=
'\n') {
11921 pm_token_buffer_push_byte(&token_buffer,
'\\');
11922 pm_token_buffer_push_byte(&token_buffer,
'\r');
11927 pm_token_buffer_push_byte(&token_buffer,
'\\');
11928 pm_token_buffer_push_byte(&token_buffer,
'\n');
11930 breakpoint = parser->
current.end;
11933 pm_token_buffer_push_byte(&token_buffer,
'\\');
11934 pm_token_buffer_push_escaped(&token_buffer, parser);
11941 if (peek(parser) !=
'\n') {
11942 pm_token_buffer_push_byte(&token_buffer,
'\r');
11950 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11951 const uint8_t *end = parser->
current.end;
11954 pm_line_offset_list_append(&parser->
line_offsets, U32(end - parser->
start + 1));
11959 parser->
current.end = breakpoint;
11960 pm_token_buffer_flush(parser, &token_buffer);
11964 parser->
current.end = end + 1;
11966 LEX(PM_TOKEN_STRING_CONTENT);
11969 was_line_continuation =
true;
11971 breakpoint = parser->
current.end;
11974 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11980 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11984 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11992 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11996 if (
type == PM_TOKEN_STRING_CONTENT) {
11997 pm_token_buffer_flush(parser, &token_buffer);
12003 assert(
false &&
"unreachable");
12006 was_line_continuation =
false;
12011 pm_token_buffer_flush(parser, &token_buffer);
12012 LEX(PM_TOKEN_STRING_CONTENT);
12018 pm_token_buffer_flush(parser, &token_buffer);
12019 LEX(PM_TOKEN_STRING_CONTENT);
12023 assert(
false &&
"unreachable");
12041 PM_BINDING_POWER_UNSET = 0,
12042 PM_BINDING_POWER_STATEMENT = 2,
12043 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12044 PM_BINDING_POWER_MODIFIER = 6,
12045 PM_BINDING_POWER_COMPOSITION = 8,
12046 PM_BINDING_POWER_NOT = 10,
12047 PM_BINDING_POWER_MATCH = 12,
12048 PM_BINDING_POWER_DEFINED = 14,
12049 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12050 PM_BINDING_POWER_ASSIGNMENT = 18,
12051 PM_BINDING_POWER_TERNARY = 20,
12052 PM_BINDING_POWER_RANGE = 22,
12053 PM_BINDING_POWER_LOGICAL_OR = 24,
12054 PM_BINDING_POWER_LOGICAL_AND = 26,
12055 PM_BINDING_POWER_EQUALITY = 28,
12056 PM_BINDING_POWER_COMPARISON = 30,
12057 PM_BINDING_POWER_BITWISE_OR = 32,
12058 PM_BINDING_POWER_BITWISE_AND = 34,
12059 PM_BINDING_POWER_SHIFT = 36,
12060 PM_BINDING_POWER_TERM = 38,
12061 PM_BINDING_POWER_FACTOR = 40,
12062 PM_BINDING_POWER_UMINUS = 42,
12063 PM_BINDING_POWER_EXPONENT = 44,
12064 PM_BINDING_POWER_UNARY = 46,
12065 PM_BINDING_POWER_INDEX = 48,
12066 PM_BINDING_POWER_CALL = 50,
12067 PM_BINDING_POWER_MAX = 52
12068} pm_binding_power_t;
12091#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12092#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12093#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12094#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12095#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12099 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12102 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12103 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12104 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12105 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12108 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12109 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12112 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12113 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12116 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12117 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12118 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12119 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12120 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12121 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12122 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12123 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12124 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12125 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12126 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12127 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12128 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12129 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12132 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12135 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12136 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12137 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12138 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12141 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12144 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12147 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12148 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12149 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12150 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12151 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12152 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12155 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12156 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12157 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12158 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12161 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12162 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12165 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12168 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12169 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12172 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12173 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12176 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12177 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12178 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12179 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12182 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12183 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12186 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12187 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12190 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12191 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12192 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12195 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12198 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12199 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12200 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12203#undef BINDING_POWER_ASSIGNMENT
12204#undef LEFT_ASSOCIATIVE
12205#undef RIGHT_ASSOCIATIVE
12206#undef RIGHT_ASSOCIATIVE_UNARY
12220match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12221 return match1(parser, type1) || match1(parser, type2);
12228match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12229 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12236match4(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4) {
12237 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12244match7(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7) {
12245 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
12252match8(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7, pm_token_type_t type8) {
12253 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8);
12264 if (match1(parser,
type)) {
12265 parser_lex(parser);
12276accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12277 if (match2(parser, type1, type2)) {
12278 parser_lex(parser);
12297 if (accept1(parser,
type))
return;
12300 pm_parser_err(parser, U32(location - parser->
start), 0, diag_id);
12312 if (accept2(parser, type1, type2))
return;
12315 pm_parser_err(parser, U32(location - parser->
start), 0, diag_id);
12326expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12327 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12328 parser_lex(parser);
12330 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12344 if (accept1(parser,
type))
return;
12346 const uint8_t *start = opening->
start;
12347 pm_parser_err(parser, U32(start - parser->
start), U32(opening->
end - start), diag_id);
12354#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
12355#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
12356#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
12357#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
12368 pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
12369 pm_assert_value_expression(parser, node);
12392token_begins_expression_p(pm_token_type_t
type) {
12394 case PM_TOKEN_EQUAL_GREATER:
12395 case PM_TOKEN_KEYWORD_IN:
12399 case PM_TOKEN_BRACE_RIGHT:
12400 case PM_TOKEN_BRACKET_RIGHT:
12401 case PM_TOKEN_COLON:
12402 case PM_TOKEN_COMMA:
12403 case PM_TOKEN_EMBEXPR_END:
12405 case PM_TOKEN_LAMBDA_BEGIN:
12406 case PM_TOKEN_KEYWORD_DO:
12407 case PM_TOKEN_KEYWORD_DO_BLOCK:
12408 case PM_TOKEN_KEYWORD_DO_LOOP:
12409 case PM_TOKEN_KEYWORD_END:
12410 case PM_TOKEN_KEYWORD_ELSE:
12411 case PM_TOKEN_KEYWORD_ELSIF:
12412 case PM_TOKEN_KEYWORD_ENSURE:
12413 case PM_TOKEN_KEYWORD_THEN:
12414 case PM_TOKEN_KEYWORD_RESCUE:
12415 case PM_TOKEN_KEYWORD_WHEN:
12416 case PM_TOKEN_NEWLINE:
12417 case PM_TOKEN_PARENTHESIS_RIGHT:
12418 case PM_TOKEN_SEMICOLON:
12424 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12426 case PM_TOKEN_UAMPERSAND:
12430 case PM_TOKEN_UCOLON_COLON:
12431 case PM_TOKEN_UMINUS:
12432 case PM_TOKEN_UMINUS_NUM:
12433 case PM_TOKEN_UPLUS:
12434 case PM_TOKEN_BANG:
12435 case PM_TOKEN_TILDE:
12436 case PM_TOKEN_UDOT_DOT:
12437 case PM_TOKEN_UDOT_DOT_DOT:
12444 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
12453parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags,
pm_diagnostic_id_t diag_id, uint16_t depth) {
12454 if (accept1(parser, PM_TOKEN_USTAR)) {
12456 pm_node_t *expression = parse_value_expression(parser, binding_power, (uint8_t) (flags & PM_PARSE_ACCEPTS_DO_BLOCK), PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
12457 return UP(pm_splat_node_create(parser, &
operator, expression));
12460 return parse_value_expression(parser, binding_power, flags, diag_id, depth);
12464pm_node_unreference_each(
const pm_node_t *node,
void *data) {
12465 switch (PM_NODE_TYPE(node)) {
12470 case PM_BREAK_NODE:
12472 case PM_REDO_NODE: {
12476 while (index < parser->current_block_exits->size) {
12479 if (block_exit == node) {
12502 case PM_LOCAL_VARIABLE_READ_NODE:
12503 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12507 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
12508 if (implicit_parameters->
nodes[index] == node) {
12512 if (index != implicit_parameters->
size - 1) {
12513 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
12516 implicit_parameters->
size--;
12535 pm_visit_node(node, pm_node_unreference_each, parser);
12549 size_t length = constant->
length;
12550 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
12551 if (name == NULL)
return;
12553 memcpy(name, constant->
start, length);
12554 name[length] =
'=';
12559 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
12570 switch (PM_NODE_TYPE(target)) {
12571 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12572 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12573 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12574 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12575 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12576 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12577 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
12581 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->
start + PM_NODE_START(target), parser->
start + PM_NODE_END(target));
12597 switch (PM_NODE_TYPE(target)) {
12598 case PM_MISSING_NODE:
12600 case PM_SOURCE_ENCODING_NODE:
12601 case PM_FALSE_NODE:
12602 case PM_SOURCE_FILE_NODE:
12603 case PM_SOURCE_LINE_NODE:
12606 case PM_TRUE_NODE: {
12609 return parse_unwriteable_target(parser, target);
12611 case PM_CLASS_VARIABLE_READ_NODE:
12613 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
12615 case PM_CONSTANT_PATH_NODE:
12616 if (context_def_p(parser)) {
12617 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12621 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
12624 case PM_CONSTANT_READ_NODE:
12625 if (context_def_p(parser)) {
12626 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12630 target->
type = PM_CONSTANT_TARGET_NODE;
12633 case PM_BACK_REFERENCE_READ_NODE:
12634 case PM_NUMBERED_REFERENCE_READ_NODE:
12635 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12637 case PM_GLOBAL_VARIABLE_READ_NODE:
12639 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
12641 case PM_LOCAL_VARIABLE_READ_NODE: {
12642 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
12643 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->
start + PM_NODE_START(target));
12644 pm_node_unreference(parser, target);
12648 uint32_t name = cast->
name;
12649 uint32_t depth = cast->
depth;
12650 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
12653 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
12657 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12659 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
12661 pm_node_unreference(parser, target);
12665 case PM_INSTANCE_VARIABLE_READ_NODE:
12667 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
12669 case PM_MULTI_TARGET_NODE:
12670 if (splat_parent) {
12673 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12677 case PM_SPLAT_NODE: {
12686 case PM_CALL_NODE: {
12698 (call->
block == NULL)
12711 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
12713 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
12717 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
12718 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
12721 parse_write_name(parser, &call->
name);
12722 return UP(pm_call_target_node_create(parser, call));
12729 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12730 return UP(pm_index_target_node_create(parser, call));
12738 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12749 pm_node_t *result = parse_target(parser, target, multiple,
false);
12754 !match1(parser, PM_TOKEN_EQUAL) &&
12756 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
12758 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
12772 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
12773 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
12784 switch (PM_NODE_TYPE(target)) {
12785 case PM_MISSING_NODE:
12787 case PM_CLASS_VARIABLE_READ_NODE: {
12791 case PM_CONSTANT_PATH_NODE: {
12794 if (context_def_p(parser)) {
12795 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12798 return parse_shareable_constant_write(parser, node);
12800 case PM_CONSTANT_READ_NODE: {
12803 if (context_def_p(parser)) {
12804 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12807 return parse_shareable_constant_write(parser, node);
12809 case PM_BACK_REFERENCE_READ_NODE:
12810 case PM_NUMBERED_REFERENCE_READ_NODE:
12811 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12813 case PM_GLOBAL_VARIABLE_READ_NODE: {
12817 case PM_LOCAL_VARIABLE_READ_NODE: {
12822 uint32_t depth = local_read->
depth;
12823 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
12825 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
12826 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
12827 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->
start + PM_NODE_START(target));
12828 pm_node_unreference(parser, target);
12831 pm_locals_unread(&scope->
locals, name);
12833 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
12835 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12837 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
12839 pm_node_unreference(parser, target);
12843 case PM_INSTANCE_VARIABLE_READ_NODE: {
12847 case PM_MULTI_TARGET_NODE:
12849 case PM_SPLAT_NODE: {
12857 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
12859 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
12861 case PM_CALL_NODE: {
12873 (call->
block == NULL)
12887 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
12888 pm_parser_local_add_location(parser, &message_loc, 0);
12890 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, parser->
start + PM_LOCATION_START(&message_loc), parser->
start + PM_LOCATION_END(&message_loc));
12891 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
12910 pm_arguments_node_arguments_append(parser->
arena, arguments, value);
12911 PM_NODE_LENGTH_SET_NODE(call, arguments);
12912 call->
equal_loc = TOK2LOC(parser,
operator);
12914 parse_write_name(parser, &call->
name);
12915 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
12924 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12926 call->
arguments = pm_arguments_node_create(parser);
12929 pm_arguments_node_arguments_append(parser->
arena, call->
arguments, value);
12930 PM_NODE_LENGTH_SET_NODE(target, value);
12933 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
12934 call->
equal_loc = TOK2LOC(parser,
operator);
12938 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
12953 pm_node_unreference(parser, value);
12960 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
12973 switch (PM_NODE_TYPE(target)) {
12974 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12975 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12976 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12977 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12978 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12979 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12980 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13001parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13002 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13005 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13007 while (accept1(parser, PM_TOKEN_COMMA)) {
13008 if (accept1(parser, PM_TOKEN_USTAR)) {
13013 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13019 if (token_begins_expression_p(parser->
current.type)) {
13020 name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13021 name = parse_target(parser, name,
true,
true);
13024 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13025 pm_multi_target_node_targets_append(parser, result, splat);
13027 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13029 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13030 target = parse_target(parser, target,
true,
false);
13032 pm_multi_target_node_targets_append(parser, result, target);
13033 context_pop(parser);
13034 }
else if (token_begins_expression_p(parser->
current.type)) {
13035 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13036 target = parse_target(parser, target,
true,
false);
13038 pm_multi_target_node_targets_append(parser, result, target);
13039 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13043 pm_multi_target_node_targets_append(parser, result, rest);
13056parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13057 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13058 accept1(parser, PM_TOKEN_NEWLINE);
13061 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13062 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13075 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13078 if (context_terminator(context, &parser->
current))
return NULL;
13084 context_push(parser, context);
13087 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13088 pm_statements_node_body_append(parser, statements, node,
true);
13101 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13104 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13105 if (context_terminator(context, &parser->
current))
break;
13115 if (context_terminator(context, &parser->
current))
break;
13127 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
13128 parser_lex(parser);
13134 if (match1(parser, PM_TOKEN_EOF)) {
13139 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13140 if (context_terminator(context, &parser->
current))
break;
13141 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13151 context_pop(parser);
13153 bool last_value =
true;
13157 last_value =
false;
13162 pm_void_statements_check(parser, statements, last_value);
13175 if (duplicated != NULL) {
13179 pm_diagnostic_list_append_format(
13183 PM_WARN_DUPLICATED_HASH_KEY,
13201 if ((previous = pm_static_literals_add(&parser->
line_offsets, parser->
start, parser->
start_line, literals, node,
false)) != NULL) {
13202 pm_diagnostic_list_append_format(
13204 PM_NODE_START(node),
13205 PM_NODE_LENGTH(node),
13206 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13218 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13219 bool contains_keyword_splat =
false;
13224 switch (parser->
current.type) {
13225 case PM_TOKEN_USTAR_STAR: {
13226 parser_lex(parser);
13230 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
13236 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13237 }
else if (token_begins_expression_p(parser->
current.type)) {
13238 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13240 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13243 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13244 contains_keyword_splat =
true;
13247 case PM_TOKEN_LABEL: {
13249 parser_lex(parser);
13251 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13252 pm_hash_key_static_literals_add(parser, literals, key);
13256 if (token_begins_expression_p(parser->
current.type)) {
13257 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13260 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13261 value = UP(pm_constant_read_node_create(parser, &constant));
13266 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13267 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13269 depth = pm_parser_local_depth(parser, &identifier);
13273 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13275 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13280 value = UP(pm_implicit_node_create(parser, value));
13283 element = UP(pm_assoc_node_create(parser, key, NULL, value));
13287 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
13291 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13292 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13295 pm_hash_key_static_literals_add(parser, literals, key);
13298 if (!pm_symbol_node_label_p(parser, key)) {
13299 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13303 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13304 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
13309 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13316 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13320 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13324 if (token_begins_expression_p(parser->
current.type))
continue;
13330 return contains_keyword_splat;
13335 if (pm_symbol_node_label_p(parser, argument)) {
13339 switch (PM_NODE_TYPE(argument)) {
13340 case PM_CALL_NODE: {
13343 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13346 if (cast->
block != NULL) {
13354 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
13363 arguments->
arguments = pm_arguments_node_create(parser);
13366 pm_arguments_node_arguments_append(parser->
arena, arguments->
arguments, argument);
13373parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
13374 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
13379 match2(parser, terminator, PM_TOKEN_EOF) ||
13380 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
13386 bool parsed_first_argument =
false;
13387 bool parsed_bare_hash =
false;
13388 bool parsed_block_argument =
false;
13389 bool parsed_forwarding_arguments =
false;
13391 while (!match1(parser, PM_TOKEN_EOF)) {
13392 if (parsed_forwarding_arguments) {
13393 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
13398 switch (parser->
current.type) {
13399 case PM_TOKEN_USTAR_STAR:
13400 case PM_TOKEN_LABEL: {
13401 if (parsed_bare_hash) {
13402 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
13406 argument = UP(hash);
13409 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
13411 parse_arguments_append(parser, arguments, argument);
13413 pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13414 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13415 pm_node_flag_set(UP(arguments->
arguments), node_flags);
13417 pm_static_literals_free(&hash_keys);
13418 parsed_bare_hash =
true;
13422 case PM_TOKEN_UAMPERSAND: {
13423 parser_lex(parser);
13427 if (token_begins_expression_p(parser->
current.type)) {
13428 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13430 pm_parser_scope_forwarding_block_check(parser, &
operator);
13433 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
13434 if (parsed_block_argument) {
13435 parse_arguments_append(parser, arguments, argument);
13437 arguments->
block = argument;
13440 if (match1(parser, PM_TOKEN_COMMA)) {
13441 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
13444 parsed_block_argument =
true;
13447 case PM_TOKEN_USTAR: {
13448 parser_lex(parser);
13451 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
13452 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
13453 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
13454 if (parsed_bare_hash) {
13455 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13458 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
13460 if (parsed_bare_hash) {
13461 pm_parser_err(parser, PM_TOKEN_START(parser, &
operator), PM_NODE_END(expression) - PM_TOKEN_START(parser, &
operator), PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13464 argument = UP(pm_splat_node_create(parser, &
operator, expression));
13467 parse_arguments_append(parser, arguments, argument);
13470 case PM_TOKEN_UDOT_DOT_DOT: {
13471 if (accepts_forwarding) {
13472 parser_lex(parser);
13474 if (token_begins_expression_p(parser->
current.type)) {
13479 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
13484 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
13486 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
13489 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
13491 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
13492 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
13493 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
13496 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->
previous));
13497 parse_arguments_append(parser, arguments, argument);
13498 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
13500 parsed_forwarding_arguments =
true;
13507 if (argument == NULL) {
13508 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (!parsed_first_argument ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0u) | PM_PARSE_ACCEPTS_LABEL, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13511 bool contains_keywords =
false;
13512 bool contains_keyword_splat =
false;
13514 if (argument_allowed_for_bare_hash(parser, argument)) {
13515 if (parsed_bare_hash) {
13516 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
13520 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
13525 contains_keywords =
true;
13529 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
13532 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13533 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
13535 pm_keyword_hash_node_elements_append(parser->
arena, bare_hash, argument);
13536 argument = UP(bare_hash);
13539 if (accept1(parser, PM_TOKEN_COMMA) && (
13540 token_begins_expression_p(parser->
current.type) ||
13541 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
13543 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
13546 pm_static_literals_free(&hash_keys);
13547 parsed_bare_hash =
true;
13550 parse_arguments_append(parser, arguments, argument);
13552 pm_node_flags_t node_flags = 0;
13553 if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13554 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13555 pm_node_flag_set(UP(arguments->
arguments), node_flags);
13561 parsed_first_argument =
true;
13564 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
13569 bool accepted_newline =
false;
13570 if (terminator != PM_TOKEN_EOF) {
13571 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
13574 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
13578 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
13581 if (accepted_newline) {
13582 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13588 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
13591 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13603 if (match1(parser, terminator))
break;
13618parse_required_destructured_parameter(
pm_parser_t *parser) {
13619 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
13622 pm_multi_target_node_opening_set(parser, node, &parser->
previous);
13631 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
13632 param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13633 pm_multi_target_node_targets_append(parser, node, param);
13634 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13638 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13639 param = UP(parse_required_destructured_parameter(parser));
13640 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
13644 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13646 value = UP(pm_required_parameter_node_create(parser, &name));
13647 if (pm_parser_parameter_name_check(parser, &name)) {
13648 pm_node_flag_set_repeated_parameter(value);
13650 pm_parser_local_add_token(parser, &name, 1);
13653 param = UP(pm_splat_node_create(parser, &star, value));
13655 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
13658 param = UP(pm_required_parameter_node_create(parser, &name));
13659 if (pm_parser_parameter_name_check(parser, &name)) {
13660 pm_node_flag_set_repeated_parameter(param);
13662 pm_parser_local_add_token(parser, &name, 1);
13665 pm_multi_target_node_targets_append(parser, node, param);
13666 }
while (accept1(parser, PM_TOKEN_COMMA));
13668 accept1(parser, PM_TOKEN_NEWLINE);
13669 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
13670 pm_multi_target_node_closing_set(parser, node, &parser->
previous);
13680 PM_PARAMETERS_NO_CHANGE = 0,
13681 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
13682 PM_PARAMETERS_ORDER_KEYWORDS_REST,
13683 PM_PARAMETERS_ORDER_KEYWORDS,
13684 PM_PARAMETERS_ORDER_REST,
13685 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13686 PM_PARAMETERS_ORDER_OPTIONAL,
13687 PM_PARAMETERS_ORDER_NAMED,
13688 PM_PARAMETERS_ORDER_NONE,
13689} pm_parameters_order_t;
13694static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
13695 [0] = PM_PARAMETERS_NO_CHANGE,
13696 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13697 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13698 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13699 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
13700 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
13701 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
13702 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
13703 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13704 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13705 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
13706 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
13718 pm_parameters_order_t state = parameters_ordering[token->type];
13719 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
13723 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13724 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
13726 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13730 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13731 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
13733 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
13734 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
13736 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
13738 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
13742 if (state < *current) *current = state;
13747parse_parameters_handle_trailing_comma(
13750 pm_parameters_order_t order,
13752 bool allows_trailing_comma
13754 if (!allows_trailing_comma) {
13755 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13760 if (order >= PM_PARAMETERS_ORDER_NAMED) {
13762 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13764 if (params->
rest == NULL) {
13765 pm_parameters_node_rest_set(params, param);
13767 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
13768 pm_parameters_node_posts_append(parser->
arena, params, UP(param));
13772 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13778 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13789 pm_binding_power_t binding_power,
13790 bool uses_parentheses,
13791 bool allows_trailing_comma,
13792 bool allows_forwarding_parameters,
13793 bool accepts_blocks_in_defaults,
13798 pm_do_loop_stack_push(parser,
false);
13801 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
13804 bool parsing =
true;
13806 switch (parser->
current.type) {
13807 case PM_TOKEN_PARENTHESIS_LEFT: {
13808 update_parameter_state(parser, &parser->
current, &order);
13809 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
13811 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13812 pm_parameters_node_requireds_append(parser->
arena, params, param);
13814 pm_parameters_node_posts_append(parser->
arena, params, param);
13818 case PM_TOKEN_UAMPERSAND:
13819 case PM_TOKEN_AMPERSAND: {
13820 update_parameter_state(parser, &parser->
current, &order);
13821 parser_lex(parser);
13827 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->
previous);
13831 bool repeated =
false;
13832 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13834 repeated = pm_parser_parameter_name_check(parser, &name);
13835 pm_parser_local_add_token(parser, &name, 1);
13840 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
13842 pm_node_flag_set_repeated_parameter(param);
13846 if (params->
block == NULL) {
13847 pm_parameters_node_block_set(params, param);
13849 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
13850 pm_parameters_node_posts_append(parser->
arena, params, param);
13855 case PM_TOKEN_UDOT_DOT_DOT: {
13856 if (!allows_forwarding_parameters) {
13857 pm_parser_err_current(parser, diag_id_forwarding);
13860 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
13861 parser_lex(parser);
13870 pm_parameters_node_posts_append(parser->
arena, params, keyword_rest);
13871 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
13875 pm_parameters_node_keyword_rest_set(params, UP(param));
13878 case PM_TOKEN_CLASS_VARIABLE:
13879 case PM_TOKEN_IDENTIFIER:
13880 case PM_TOKEN_CONSTANT:
13881 case PM_TOKEN_INSTANCE_VARIABLE:
13882 case PM_TOKEN_GLOBAL_VARIABLE:
13883 case PM_TOKEN_METHOD_NAME: {
13884 parser_lex(parser);
13886 case PM_TOKEN_CONSTANT:
13887 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
13889 case PM_TOKEN_INSTANCE_VARIABLE:
13890 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
13892 case PM_TOKEN_GLOBAL_VARIABLE:
13893 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
13895 case PM_TOKEN_CLASS_VARIABLE:
13896 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
13898 case PM_TOKEN_METHOD_NAME:
13899 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
13904 if (parser->
current.type == PM_TOKEN_EQUAL) {
13905 update_parameter_state(parser, &parser->
current, &order);
13907 update_parameter_state(parser, &parser->
previous, &order);
13911 bool repeated = pm_parser_parameter_name_check(parser, &name);
13912 pm_parser_local_add_token(parser, &name, 1);
13914 if (match1(parser, PM_TOKEN_EQUAL)) {
13917 parser_lex(parser);
13922 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
13923 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
13924 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
13929 pm_node_flag_set_repeated_parameter(UP(param));
13931 pm_parameters_node_optionals_append(parser->
arena, params, param);
13937 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
13940 context_pop(parser);
13949 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13952 pm_node_flag_set_repeated_parameter(UP(param));
13954 pm_parameters_node_requireds_append(parser->
arena, params, UP(param));
13958 pm_node_flag_set_repeated_parameter(UP(param));
13960 pm_parameters_node_posts_append(parser->
arena, params, UP(param));
13965 case PM_TOKEN_LABEL: {
13966 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
13967 update_parameter_state(parser, &parser->
current, &order);
13970 parser_lex(parser);
13977 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
13978 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
13979 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
13982 bool repeated = pm_parser_parameter_name_check(parser, &local);
13983 pm_parser_local_add_token(parser, &local, 1);
13985 switch (parser->
current.type) {
13986 case PM_TOKEN_COMMA:
13987 case PM_TOKEN_PARENTHESIS_RIGHT:
13988 case PM_TOKEN_PIPE: {
13989 context_pop(parser);
13991 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
13993 pm_node_flag_set_repeated_parameter(param);
13996 pm_parameters_node_keywords_append(parser->
arena, params, param);
13999 case PM_TOKEN_SEMICOLON:
14000 case PM_TOKEN_NEWLINE: {
14001 context_pop(parser);
14003 if (uses_parentheses) {
14008 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14010 pm_node_flag_set_repeated_parameter(param);
14013 pm_parameters_node_keywords_append(parser->
arena, params, param);
14019 if (token_begins_expression_p(parser->
current.type)) {
14023 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14024 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14025 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14028 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
14031 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14034 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14038 pm_node_flag_set_repeated_parameter(param);
14041 context_pop(parser);
14042 pm_parameters_node_keywords_append(parser->
arena, params, param);
14057 case PM_TOKEN_USTAR:
14058 case PM_TOKEN_STAR: {
14059 update_parameter_state(parser, &parser->
current, &order);
14060 parser_lex(parser);
14064 bool repeated =
false;
14066 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14068 repeated = pm_parser_parameter_name_check(parser, &name);
14069 pm_parser_local_add_token(parser, &name, 1);
14074 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14076 pm_node_flag_set_repeated_parameter(param);
14079 if (params->
rest == NULL) {
14080 pm_parameters_node_rest_set(params, param);
14082 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14083 pm_parameters_node_posts_append(parser->
arena, params, param);
14088 case PM_TOKEN_STAR_STAR:
14089 case PM_TOKEN_USTAR_STAR: {
14090 pm_parameters_order_t previous_order = order;
14091 update_parameter_state(parser, &parser->
current, &order);
14092 parser_lex(parser);
14097 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14098 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14099 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14102 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
14106 bool repeated =
false;
14107 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14109 repeated = pm_parser_parameter_name_check(parser, &name);
14110 pm_parser_local_add_token(parser, &name, 1);
14115 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14117 pm_node_flag_set_repeated_parameter(param);
14122 pm_parameters_node_keyword_rest_set(params, param);
14124 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14125 pm_parameters_node_posts_append(parser->
arena, params, param);
14132 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
14142 if (!parsing)
break;
14144 bool accepted_newline =
false;
14145 if (uses_parentheses) {
14146 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14149 if (accept1(parser, PM_TOKEN_COMMA)) {
14152 if (accepted_newline) {
14153 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14161 pm_do_loop_stack_pop(parser);
14164 if (PM_NODE_START(params) == PM_NODE_END(params)) {
14187 return (
size_t) pm_line_offset_list_line(&parser->
line_offsets, PM_TOKEN_START(parser, &parser->
current), 0);
14196token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14198 const uint8_t *end = token->start;
14202 newline_index == 0 &&
14203 parser->
start[0] == 0xef &&
14204 parser->
start[1] == 0xbb &&
14205 parser->
start[2] == 0xbf
14208 int64_t column = 0;
14209 for (; cursor < end; cursor++) {
14212 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14219 if (break_on_non_space)
return -1;
14232parser_warn_indentation_mismatch(
pm_parser_t *parser,
size_t opening_newline_index,
const pm_token_t *opening_token,
bool if_after_else,
bool allow_indent) {
14237 size_t closing_newline_index = token_newline_index(parser);
14238 if (opening_newline_index == closing_newline_index)
return;
14243 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14244 if (!if_after_else && (opening_column == -1))
return;
14251 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14252 if ((closing_column == -1) || (opening_column == closing_column))
return;
14256 if (allow_indent && (closing_column > opening_column))
return;
14259 PM_PARSER_WARN_FORMAT(
14261 PM_TOKEN_START(parser, closing_token),
14262 PM_TOKEN_LENGTH(closing_token),
14263 PM_WARN_INDENTATION_MISMATCH,
14264 (
int) (closing_token->
end - closing_token->
start),
14265 (
const char *) closing_token->
start,
14266 (
int) (opening_token->
end - opening_token->
start),
14267 (
const char *) opening_token->
start,
14268 ((int32_t) opening_newline_index) + parser->
start_line
14273 PM_RESCUES_BEGIN = 1,
14280} pm_rescues_type_t;
14290 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
14291 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14292 parser_lex(parser);
14296 switch (parser->
current.type) {
14297 case PM_TOKEN_EQUAL_GREATER: {
14301 parser_lex(parser);
14302 pm_rescue_node_operator_set(parser, rescue, &parser->
previous);
14304 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14305 reference = parse_target(parser, reference,
false,
false);
14307 pm_rescue_node_reference_set(rescue, reference);
14310 case PM_TOKEN_NEWLINE:
14311 case PM_TOKEN_SEMICOLON:
14312 case PM_TOKEN_KEYWORD_THEN:
14317 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
14322 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
14323 pm_rescue_node_exceptions_append(parser->
arena, rescue, expression);
14327 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
14331 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14332 pm_rescue_node_operator_set(parser, rescue, &parser->
previous);
14334 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14335 reference = parse_target(parser, reference,
false,
false);
14337 pm_rescue_node_reference_set(rescue, reference);
14340 }
while (accept1(parser, PM_TOKEN_COMMA));
14345 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14346 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
14350 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
14354 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
14355 pm_accepts_block_stack_push(parser,
true);
14370 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
14372 pm_accepts_block_stack_pop(parser);
14373 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14376 if (current == NULL) {
14377 pm_begin_node_rescue_clause_set(parent_node, rescue);
14379 pm_rescue_node_subsequent_set(current, rescue);
14388 if (current != NULL) {
14391 while (clause != NULL) {
14392 PM_NODE_LENGTH_SET_NODE(clause, current);
14398 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
14399 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14400 opening_newline_index = token_newline_index(parser);
14402 else_keyword = parser->
current;
14403 opening = &else_keyword;
14405 parser_lex(parser);
14406 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14409 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
14410 pm_accepts_block_stack_push(parser,
true);
14424 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14425 pm_accepts_block_stack_pop(parser);
14427 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14430 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
14431 pm_begin_node_else_clause_set(parent_node, else_clause);
14435 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
14438 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
14439 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14442 parser_lex(parser);
14443 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14446 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14447 pm_accepts_block_stack_push(parser,
true);
14461 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14462 pm_accepts_block_stack_pop(parser);
14464 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14467 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
14468 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
14471 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
14472 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14473 pm_begin_node_end_keyword_set(parser, parent_node, &parser->
current);
14476 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
14486 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
14487 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
14490 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->
current);
14499parse_block_parameters(
14501 bool allows_trailing_comma,
14503 bool is_lambda_literal,
14504 bool accepts_blocks_in_defaults,
14508 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
14509 if (!is_lambda_literal) {
14512 parameters = parse_parameters(
14514 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
14516 allows_trailing_comma,
14518 accepts_blocks_in_defaults,
14520 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
14521 (uint16_t) (depth + 1)
14523 if (!is_lambda_literal) {
14524 context_pop(parser);
14529 if (opening != NULL) {
14530 accept1(parser, PM_TOKEN_NEWLINE);
14532 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
14534 switch (parser->
current.type) {
14535 case PM_TOKEN_CONSTANT:
14536 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14537 parser_lex(parser);
14539 case PM_TOKEN_INSTANCE_VARIABLE:
14540 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14541 parser_lex(parser);
14543 case PM_TOKEN_GLOBAL_VARIABLE:
14544 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14545 parser_lex(parser);
14547 case PM_TOKEN_CLASS_VARIABLE:
14548 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14549 parser_lex(parser);
14552 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
14556 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
14557 pm_parser_local_add_token(parser, &parser->
previous, 1);
14560 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
14562 pm_block_parameters_node_append_local(parser->
arena, block_parameters, local);
14563 }
while (accept1(parser, PM_TOKEN_COMMA));
14567 return block_parameters;
14575outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
14577 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
14588static const char *
const pm_numbered_parameter_names[] = {
14589 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
14603 if (parameters != NULL) {
14605 if (implicit_parameters->
size > 0) {
14608 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14609 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
14610 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14611 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
14613 assert(
false &&
"unreachable");
14622 if (implicit_parameters->
size == 0) {
14629 uint8_t numbered_parameter = 0;
14630 bool it_parameter =
false;
14632 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
14635 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14636 if (it_parameter) {
14637 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
14638 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
14639 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
14641 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
14642 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
14643 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->
start[node->
location.
start + 1] -
'0'));
14645 assert(
false &&
"unreachable");
14647 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14648 if (numbered_parameter > 0) {
14649 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
14651 it_parameter =
true;
14656 if (numbered_parameter > 0) {
14660 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
14662 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
14665 if (it_parameter) {
14666 return UP(pm_it_parameters_node_create(parser, opening, closing));
14676parse_block(
pm_parser_t *parser, uint16_t depth) {
14678 accept1(parser, PM_TOKEN_NEWLINE);
14680 pm_accepts_block_stack_push(parser,
true);
14681 pm_parser_scope_push(parser,
false);
14685 if (accept1(parser, PM_TOKEN_PIPE)) {
14687 if (match1(parser, PM_TOKEN_PIPE)) {
14688 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
14690 parser_lex(parser);
14692 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
14693 accept1(parser, PM_TOKEN_NEWLINE);
14695 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
14698 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->
previous);
14701 accept1(parser, PM_TOKEN_NEWLINE);
14704 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
14705 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
14709 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
14711 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14712 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
14713 pm_accepts_block_stack_push(parser,
true);
14715 pm_accepts_block_stack_pop(parser);
14718 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
14719 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
14720 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
14724 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
14728 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
14729 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->
previous);
14731 pm_parser_scope_pop(parser);
14732 pm_accepts_block_stack_pop(parser);
14734 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
14743parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block, uint8_t flags, uint16_t depth) {
14744 bool found =
false;
14745 bool parsed_command_args =
false;
14747 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14751 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14754 pm_accepts_block_stack_push(parser,
true);
14755 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
14757 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14763 pm_accepts_block_stack_pop(parser);
14766 }
else if ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
14768 parsed_command_args =
true;
14769 pm_accepts_block_stack_push(parser,
false);
14774 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
14779 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
14783 pm_accepts_block_stack_pop(parser);
14789 if (accepts_block) {
14792 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
14794 block = parse_block(parser, (uint16_t) (depth + 1));
14795 pm_arguments_validate_block(parser, arguments, block);
14796 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
14798 block = parse_block(parser, (uint16_t) (depth + 1));
14799 }
else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
14801 block = parse_block(parser, (uint16_t) (depth + 1));
14804 if (block != NULL) {
14806 arguments->
block = UP(block);
14808 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
14810 if (arguments->
block != NULL) {
14812 arguments->
arguments = pm_arguments_node_create(parser);
14814 pm_arguments_node_arguments_append(parser->
arena, arguments->
arguments, arguments->
block);
14816 arguments->
block = UP(block);
14830 bool in_sclass =
false;
14832 switch (context_node->
context) {
14877 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14900 assert(
false &&
"unreachable");
14905 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14916 switch (context_node->
context) {
14991 assert(
false &&
"unreachable");
15005 return previous_block_exits;
15019 switch (PM_NODE_TYPE(block_exit)) {
15020 case PM_BREAK_NODE:
type =
"break";
break;
15021 case PM_NEXT_NODE:
type =
"next";
break;
15022 case PM_REDO_NODE:
type =
"redo";
break;
15023 default: assert(
false &&
"unreachable");
type =
"";
break;
15026 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15038 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15043 }
else if (previous_block_exits != NULL) {
15055 flush_block_exits(parser, previous_block_exits);
15063 pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, error_id, (uint16_t) (depth + 1));
15066 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15068 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15069 predicate_closed =
true;
15073 if (!predicate_closed) {
15074 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15077 context_pop(parser);
15082parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15084 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15089 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15092 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15093 pm_accepts_block_stack_push(parser,
true);
15094 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15095 pm_accepts_block_stack_pop(parser);
15096 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15103 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15106 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
15109 assert(
false &&
"unreachable");
15118 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15119 if (parser_end_of_line_p(parser)) {
15120 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->
current, PM_WARN_KEYWORD_EOL);
15123 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15125 parser_lex(parser);
15127 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15128 pm_accepts_block_stack_push(parser,
true);
15131 pm_accepts_block_stack_pop(parser);
15132 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15134 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15140 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15141 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15142 opening_newline_index = token_newline_index(parser);
15144 parser_lex(parser);
15147 pm_accepts_block_stack_push(parser,
true);
15149 pm_accepts_block_stack_pop(parser);
15151 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15152 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15153 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
15155 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15159 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
15165 assert(
false &&
"unreachable");
15169 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15170 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
15177 bool recursing =
true;
15179 while (recursing) {
15180 switch (PM_NODE_TYPE(current)) {
15184 recursing = current != NULL;
15202 assert(
false &&
"unreachable");
15206 pop_block_exits(parser, previous_block_exits);
15214#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15215 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15216 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15217 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_BLOCK: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15218 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15219 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15220 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15221 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15222 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15223 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15224 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15230#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15231 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15232 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15233 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15234 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15235 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15236 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15237 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15244#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15245 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15246 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15247 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15248 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15249 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15250 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15251 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15252 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15258#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15259 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15260 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15261 case PM_TOKEN_CLASS_VARIABLE
15267#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15268 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15269 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15270 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15274PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15280static inline pm_node_flags_t
15281parse_unescaped_encoding(
const pm_parser_t *parser) {
15286 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15292 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15303parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15304 switch (parser->
current.type) {
15311 case PM_TOKEN_STRING_CONTENT: {
15312 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
15313 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15315 parser_lex(parser);
15324 case PM_TOKEN_EMBEXPR_BEGIN: {
15333 lex_state_set(parser, PM_LEX_STATE_BEG);
15334 parser_lex(parser);
15339 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
15340 pm_accepts_block_stack_push(parser,
true);
15342 pm_accepts_block_stack_pop(parser);
15346 lex_state_set(parser, state);
15347 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15352 if (statements != NULL && statements->
body.
size == 1) {
15353 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15356 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->
previous));
15365 case PM_TOKEN_EMBVAR: {
15370 lex_state_set(parser, PM_LEX_STATE_BEG);
15371 parser_lex(parser);
15376 switch (parser->
current.type) {
15379 case PM_TOKEN_BACK_REFERENCE:
15380 parser_lex(parser);
15381 variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15385 case PM_TOKEN_NUMBERED_REFERENCE:
15386 parser_lex(parser);
15387 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15391 case PM_TOKEN_GLOBAL_VARIABLE:
15392 parser_lex(parser);
15393 variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15397 case PM_TOKEN_INSTANCE_VARIABLE:
15398 parser_lex(parser);
15399 variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
15403 case PM_TOKEN_CLASS_VARIABLE:
15404 parser_lex(parser);
15405 variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
15411 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15412 variable = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
15416 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15419 parser_lex(parser);
15420 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15430static const uint8_t *
15431parse_operator_symbol_name(
const pm_token_t *name) {
15432 switch (name->
type) {
15433 case PM_TOKEN_TILDE:
15434 case PM_TOKEN_BANG:
15435 if (name->
end[-1] ==
'@')
return name->
end - 1;
15445 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
15447 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15448 parser_lex(parser);
15451 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15465 if (lex_mode->
mode != PM_LEX_STRING) {
15466 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15468 switch (parser->
current.type) {
15469 case PM_CASE_OPERATOR:
15470 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15471 case PM_TOKEN_IDENTIFIER:
15472 case PM_TOKEN_CONSTANT:
15473 case PM_TOKEN_INSTANCE_VARIABLE:
15474 case PM_TOKEN_METHOD_NAME:
15475 case PM_TOKEN_CLASS_VARIABLE:
15476 case PM_TOKEN_GLOBAL_VARIABLE:
15477 case PM_TOKEN_NUMBERED_REFERENCE:
15478 case PM_TOKEN_BACK_REFERENCE:
15479 case PM_CASE_KEYWORD:
15480 parser_lex(parser);
15483 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15489 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15496 if (match1(parser, PM_TOKEN_STRING_END)) {
15497 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15498 parser_lex(parser);
15500 .
type = PM_TOKEN_STRING_CONTENT,
15505 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->
previous));
15509 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15513 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15514 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15515 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15521 if (part) pm_interpolated_symbol_node_append(parser->
arena, symbol, part);
15523 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15524 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15525 pm_interpolated_symbol_node_append(parser->
arena, symbol, part);
15529 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15530 if (match1(parser, PM_TOKEN_EOF)) {
15531 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15533 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15536 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->
previous);
15543 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15546 parser_lex(parser);
15557 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15559 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
15560 pm_interpolated_symbol_node_append(parser->
arena, symbol, part);
15562 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->
current, NULL, &parser->
current_string));
15563 pm_interpolated_symbol_node_append(parser->
arena, symbol, part);
15565 if (next_state != PM_LEX_STATE_NONE) {
15566 lex_state_set(parser, next_state);
15569 parser_lex(parser);
15570 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15572 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->
previous);
15577 pm_string_shared_init(&unescaped, content.
start, content.
end);
15580 if (next_state != PM_LEX_STATE_NONE) {
15581 lex_state_set(parser, next_state);
15584 if (match1(parser, PM_TOKEN_EOF)) {
15585 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15587 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15590 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
15598parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
15599 switch (parser->
current.type) {
15600 case PM_CASE_OPERATOR:
15601 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
15602 case PM_CASE_KEYWORD:
15603 case PM_TOKEN_CONSTANT:
15604 case PM_TOKEN_IDENTIFIER:
15605 case PM_TOKEN_METHOD_NAME: {
15606 parser_lex(parser);
15610 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15614 case PM_TOKEN_SYMBOL_BEGIN: {
15616 parser_lex(parser);
15618 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15621 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
15622 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
15633parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
15634 switch (parser->
current.type) {
15635 case PM_CASE_OPERATOR:
15636 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
15637 case PM_CASE_KEYWORD:
15638 case PM_TOKEN_CONSTANT:
15639 case PM_TOKEN_IDENTIFIER:
15640 case PM_TOKEN_METHOD_NAME: {
15641 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
15642 parser_lex(parser);
15646 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15650 case PM_TOKEN_SYMBOL_BEGIN: {
15652 parser_lex(parser);
15654 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15656 case PM_TOKEN_BACK_REFERENCE:
15657 parser_lex(parser);
15658 return UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15659 case PM_TOKEN_NUMBERED_REFERENCE:
15660 parser_lex(parser);
15661 return UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15662 case PM_TOKEN_GLOBAL_VARIABLE:
15663 parser_lex(parser);
15664 return UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15666 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
15667 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
15679 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous));
15681 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
15682 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false));
15686 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
15687 if (is_numbered_param) {
15692 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
15693 for (uint8_t number = 1; number <= maximum; number++) {
15694 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
15697 if (!match1(parser, PM_TOKEN_EQUAL)) {
15701 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false));
15706 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->
previous));
15721 pm_node_flags_t flags = 0;
15723 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
15724 pm_node_t *node = parse_variable(parser);
15725 if (node != NULL)
return node;
15726 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
15730 pm_node_flag_set(UP(node), flags);
15741parse_method_definition_name(
pm_parser_t *parser) {
15742 switch (parser->
current.type) {
15743 case PM_CASE_KEYWORD:
15744 case PM_TOKEN_CONSTANT:
15745 case PM_TOKEN_METHOD_NAME:
15746 parser_lex(parser);
15748 case PM_TOKEN_IDENTIFIER:
15749 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current));
15750 parser_lex(parser);
15752 case PM_CASE_OPERATOR:
15753 lex_state_set(parser, PM_LEX_STATE_ENDFN);
15754 parser_lex(parser);
15769 if (string->
type != PM_STRING_OWNED) {
15772 pm_string_constant_init(
string, (
const char *) writable, length);
15774 writable = (uint8_t *) string->
source;
15781 const uint8_t *source_cursor = writable;
15782 const uint8_t *source_end = source_cursor + dest_length;
15787 size_t trimmed_whitespace = 0;
15793 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
15794 if (*source_cursor ==
'\t') {
15795 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
15796 if (trimmed_whitespace > common_whitespace)
break;
15798 trimmed_whitespace++;
15805 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
15806 string->length = dest_length;
15816 const uint8_t *cursor = parser->
start + PM_LOCATION_START(&string_node->
content_loc);
15829 bool dedent_next =
true;
15833 size_t write_index = 0;
15840 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
15841 nodes->
nodes[write_index++] = node;
15842 dedent_next =
false;
15848 parse_heredoc_dedent_string(parser->
arena, &string_node->
unescaped, common_whitespace);
15851 if (heredoc_dedent_discard_string_node(parser, string_node)) {
15853 nodes->
nodes[write_index++] = node;
15857 dedent_next =
true;
15860 nodes->
size = write_index;
15867parse_strings_empty_content(
const uint8_t *location) {
15868 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
15876 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
15877 bool concating =
false;
15879 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
15885 assert(lex_mode->
mode == PM_LEX_STRING);
15887 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
15890 parser_lex(parser);
15892 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15893 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
15902 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
15910 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
15911 }
else if (!lex_interpolation) {
15917 if (match1(parser, PM_TOKEN_EOF)) {
15922 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
15937 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15939 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
15940 pm_node_list_append(parser->
arena, &parts, part);
15943 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
15944 pm_node_list_append(parser->
arena, &parts, part);
15945 parser_lex(parser);
15946 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
15948 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
15949 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
15950 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
15951 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
15952 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
15953 }
else if (match1(parser, PM_TOKEN_EOF)) {
15954 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
15955 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
15956 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
15957 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
15962 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
15964 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15971 parser_lex(parser);
15973 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15974 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
15975 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15981 if (!accept1(parser, PM_TOKEN_STRING_END)) {
15983 if (location > parser->
start && location[-1] ==
'\n') location--;
15984 pm_parser_err(parser, U32(location - parser->
start), 0, PM_ERR_STRING_LITERAL_EOF);
15989 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
15990 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
15991 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
15996 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->
previous, NULL, &unescaped));
15997 pm_node_flag_set(part, parse_unescaped_encoding(parser));
15998 pm_node_list_append(parser->
arena, &parts, part);
16000 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16001 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16002 pm_node_list_append(parser->
arena, &parts, part);
16006 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16007 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16008 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16009 }
else if (match1(parser, PM_TOKEN_EOF)) {
16010 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16011 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16013 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16014 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16024 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16025 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16026 pm_node_list_append(parser->
arena, &parts, part);
16030 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16031 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16032 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16033 }
else if (match1(parser, PM_TOKEN_EOF)) {
16034 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16035 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16037 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16038 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16042 if (current == NULL) {
16046 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16057 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16058 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16064 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16065 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16070 pm_interpolated_string_node_append(parser->
arena, container, current);
16071 current = UP(container);
16081#define PM_PARSE_PATTERN_SINGLE 0
16082#define PM_PARSE_PATTERN_TOP 1
16083#define PM_PARSE_PATTERN_MULTI 2
16096 if (peek_at(parser, parser->
start + location->
start) ==
'_')
return;
16098 if (pm_constant_id_list_includes(captures, capture)) {
16099 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16101 pm_constant_id_list_append(parser->
arena, captures, capture);
16112 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16114 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16115 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
16121 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16129 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16131 accept1(parser, PM_TOKEN_NEWLINE);
16133 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16134 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16135 accept1(parser, PM_TOKEN_NEWLINE);
16136 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16141 parser_lex(parser);
16143 accept1(parser, PM_TOKEN_NEWLINE);
16145 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16146 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16147 accept1(parser, PM_TOKEN_NEWLINE);
16148 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16157 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16164 switch (PM_NODE_TYPE(inner)) {
16165 case PM_ARRAY_PATTERN_NODE: {
16169 PM_NODE_START_SET_NODE(pattern_node, node);
16170 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16173 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16174 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16176 return UP(pattern_node);
16181 case PM_FIND_PATTERN_NODE: {
16185 PM_NODE_START_SET_NODE(pattern_node, node);
16186 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16189 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16190 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16192 return UP(pattern_node);
16197 case PM_HASH_PATTERN_NODE: {
16201 PM_NODE_START_SET_NODE(pattern_node, node);
16202 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16205 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16206 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16208 return UP(pattern_node);
16220 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16221 pm_array_pattern_node_requireds_append(parser->
arena, pattern_node, inner);
16222 return UP(pattern_node);
16237 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16241 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16245 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->
previous));
16246 name = UP(pm_local_variable_target_node_create(
16248 &TOK2LOC(parser, &parser->
previous),
16250 (uint32_t) (depth == -1 ? 0 : depth)
16255 return pm_splat_node_create(parser, &
operator, name);
16263 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
16264 parser_lex(parser);
16269 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16270 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
16273 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16277 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16281 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->
previous));
16282 value = UP(pm_local_variable_target_node_create(
16284 &TOK2LOC(parser, &parser->
previous),
16286 (uint32_t) (depth == -1 ? 0 : depth)
16290 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16298pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16299 ptrdiff_t length = end - start;
16300 if (length == 0)
return false;
16303 size_t width = char_is_identifier_start(parser, start, end - start);
16304 if (width == 0)
return false;
16310 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16315 const uint8_t *cursor = start + width;
16316 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16317 return cursor == end;
16327 const uint8_t *start = parser->
start + PM_LOCATION_START(value_loc);
16328 const uint8_t *end = parser->
start + PM_LOCATION_END(value_loc);
16330 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
16333 if (pm_slice_is_valid_local(parser, start, end)) {
16334 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16336 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
16338 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
16339 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
16344 pm_parser_local_add(parser, constant_id, start, end, 0);
16347 parse_pattern_capture(parser, captures, constant_id, value_loc);
16352 (uint32_t) (depth == -1 ? 0 : depth)
16355 return UP(pm_implicit_node_create(parser, UP(target)));
16365 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16378 switch (PM_NODE_TYPE(first_node)) {
16379 case PM_ASSOC_SPLAT_NODE:
16380 case PM_NO_KEYWORDS_PARAMETER_NODE:
16383 case PM_SYMBOL_NODE: {
16384 if (pm_symbol_node_label_p(parser, first_node)) {
16385 parse_pattern_hash_key(parser, &keys, first_node);
16388 if (match8(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
16391 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
16395 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16398 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
16399 pm_node_list_append(parser->
arena, &assocs, assoc);
16408 pm_diagnostic_id_t diag_id = PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE) ? PM_ERR_PATTERN_HASH_KEY_INTERPOLATED : PM_ERR_PATTERN_HASH_KEY_LABEL;
16409 pm_parser_err_node(parser, first_node, diag_id);
16411 pm_node_t *value = UP(pm_missing_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
16412 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
16414 pm_node_list_append(parser->
arena, &assocs, assoc);
16420 while (accept1(parser, PM_TOKEN_COMMA)) {
16422 if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
16424 if (rest != NULL) {
16425 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16431 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16432 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16434 if (rest == NULL) {
16437 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16438 pm_node_list_append(parser->
arena, &assocs, assoc);
16443 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16444 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16446 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16447 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16448 }
else if (!pm_symbol_node_label_p(parser, key)) {
16449 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16451 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
16452 key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16454 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16457 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
16460 parse_pattern_hash_key(parser, &keys, key);
16463 if (match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
16464 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16465 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
16467 value = UP(pm_missing_node_create(parser, PM_NODE_END(key), 0));
16470 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16473 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
16475 if (rest != NULL) {
16476 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16479 pm_node_list_append(parser->
arena, &assocs, assoc);
16486 pm_static_literals_free(&keys);
16495 switch (parser->
current.type) {
16496 case PM_TOKEN_IDENTIFIER:
16497 case PM_TOKEN_METHOD_NAME: {
16498 parser_lex(parser);
16502 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16506 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->
previous));
16507 return UP(pm_local_variable_target_node_create(
16509 &TOK2LOC(parser, &parser->
previous),
16511 (uint32_t) (depth == -1 ? 0 : depth)
16514 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16516 parser_lex(parser);
16518 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16521 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous));
16526 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16528 accept1(parser, PM_TOKEN_NEWLINE);
16529 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16532 switch (PM_NODE_TYPE(inner)) {
16533 case PM_ARRAY_PATTERN_NODE: {
16536 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
16537 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16539 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16540 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16542 return UP(pattern_node);
16547 case PM_FIND_PATTERN_NODE: {
16550 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
16551 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16553 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16554 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16556 return UP(pattern_node);
16566 pm_array_pattern_node_requireds_append(parser->
arena, node, inner);
16569 case PM_TOKEN_BRACE_LEFT: {
16575 parser_lex(parser);
16577 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16580 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
16584 switch (parser->
current.type) {
16585 case PM_TOKEN_LABEL:
16586 parser_lex(parser);
16587 first_node = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16589 case PM_TOKEN_USTAR_STAR:
16590 first_node = parse_pattern_keyword_rest(parser, captures);
16592 case PM_TOKEN_STRING_BEGIN:
16593 first_node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
16597 parser_lex(parser);
16599 first_node = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
16604 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
16606 accept1(parser, PM_TOKEN_NEWLINE);
16607 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
16610 PM_NODE_START_SET_TOKEN(parser, node, &opening);
16611 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
16620 case PM_TOKEN_UDOT_DOT:
16621 case PM_TOKEN_UDOT_DOT_DOT: {
16623 parser_lex(parser);
16627 switch (parser->
current.type) {
16628 case PM_CASE_PRIMITIVE: {
16629 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16630 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16633 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
16634 pm_node_t *right = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
16635 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16639 case PM_CASE_PRIMITIVE: {
16640 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_LABEL | PM_PARSE_ACCEPTS_DO_BLOCK, diag_id, (uint16_t) (depth + 1));
16643 if (pm_symbol_node_label_p(parser, node))
return node;
16646 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
16647 pm_parser_err_node(parser, node, diag_id);
16648 pm_missing_node_t *missing_node = pm_missing_node_create(parser, PM_NODE_START(node), PM_NODE_LENGTH(node));
16650 pm_node_unreference(parser, node);
16651 return UP(missing_node);
16655 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
16661 switch (parser->
current.type) {
16662 case PM_CASE_PRIMITIVE: {
16663 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16664 return UP(pm_range_node_create(parser, node, &
operator, right));
16667 return UP(pm_range_node_create(parser, node, &
operator, NULL));
16673 case PM_TOKEN_CARET: {
16674 parser_lex(parser);
16679 switch (parser->
current.type) {
16680 case PM_TOKEN_IDENTIFIER: {
16681 parser_lex(parser);
16682 pm_node_t *variable = UP(parse_variable(parser));
16684 if (variable == NULL) {
16685 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
16686 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0));
16689 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16691 case PM_TOKEN_INSTANCE_VARIABLE: {
16692 parser_lex(parser);
16693 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
16695 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16697 case PM_TOKEN_CLASS_VARIABLE: {
16698 parser_lex(parser);
16699 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
16701 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16703 case PM_TOKEN_GLOBAL_VARIABLE: {
16704 parser_lex(parser);
16705 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
16707 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16709 case PM_TOKEN_NUMBERED_REFERENCE: {
16710 parser_lex(parser);
16711 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
16713 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16715 case PM_TOKEN_BACK_REFERENCE: {
16716 parser_lex(parser);
16717 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
16719 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16721 case PM_TOKEN_PARENTHESIS_LEFT: {
16726 parser_lex(parser);
16728 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
16731 accept1(parser, PM_TOKEN_NEWLINE);
16732 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
16733 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous));
16738 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
16739 pm_node_t *variable = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
16740 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16744 case PM_TOKEN_UCOLON_COLON: {
16746 parser_lex(parser);
16748 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16751 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
16753 case PM_TOKEN_CONSTANT: {
16755 parser_lex(parser);
16757 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
16758 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
16761 pm_parser_err_current(parser, diag_id);
16762 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
16767parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
16768 switch (PM_NODE_TYPE(node)) {
16769 case PM_LOCAL_VARIABLE_TARGET_NODE: {
16771 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
16785 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
16795 bool alternation =
false;
16797 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
16798 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
16799 parse_pattern_alternation_error(parser, node);
16802 switch (parser->
current.type) {
16803 case PM_TOKEN_IDENTIFIER:
16804 case PM_TOKEN_BRACKET_LEFT_ARRAY:
16805 case PM_TOKEN_BRACE_LEFT:
16806 case PM_TOKEN_CARET:
16807 case PM_TOKEN_CONSTANT:
16808 case PM_TOKEN_UCOLON_COLON:
16809 case PM_TOKEN_UDOT_DOT:
16810 case PM_TOKEN_UDOT_DOT_DOT:
16811 case PM_CASE_PRIMITIVE: {
16812 if (!alternation) {
16813 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16816 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
16818 if (captures->
size) parse_pattern_alternation_error(parser, right);
16819 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16824 case PM_TOKEN_PARENTHESIS_LEFT:
16825 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
16828 parser_lex(parser);
16830 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16831 accept1(parser, PM_TOKEN_NEWLINE);
16832 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16833 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->
previous, 0));
16835 if (!alternation) {
16838 if (captures->
size) parse_pattern_alternation_error(parser, right);
16839 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16845 pm_parser_err_current(parser, diag_id);
16846 pm_node_t *right = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
16848 if (!alternation) {
16851 if (captures->
size) parse_pattern_alternation_error(parser, right);
16852 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->
previous));
16862 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
16864 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
16869 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16873 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->
previous));
16876 &TOK2LOC(parser, &parser->
previous),
16878 (uint32_t) (depth == -1 ? 0 : depth)
16881 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
16894 bool leading_rest =
false;
16895 bool trailing_rest =
false;
16897 switch (parser->
current.type) {
16898 case PM_TOKEN_LABEL: {
16899 parser_lex(parser);
16901 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
16903 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16904 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16909 case PM_TOKEN_USTAR_STAR: {
16910 node = parse_pattern_keyword_rest(parser, captures);
16911 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16913 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16914 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16919 case PM_TOKEN_STRING_BEGIN: {
16922 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16924 if (pm_symbol_node_label_p(parser, node)) {
16925 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16927 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16928 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16934 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
16937 case PM_TOKEN_USTAR: {
16938 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
16939 parser_lex(parser);
16940 node = UP(parse_pattern_rest(parser, captures));
16941 leading_rest =
true;
16947 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
16953 if (pm_symbol_node_label_p(parser, node)) {
16954 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16957 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
16962 pm_node_list_append(parser->
arena, &nodes, node);
16965 while (accept1(parser, PM_TOKEN_COMMA)) {
16967 if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_AND, PM_TOKEN_KEYWORD_OR)) {
16968 node = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
16969 pm_node_list_append(parser->
arena, &nodes, node);
16970 trailing_rest =
true;
16974 if (accept1(parser, PM_TOKEN_USTAR)) {
16975 node = UP(parse_pattern_rest(parser, captures));
16980 if (trailing_rest) {
16981 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
16984 trailing_rest =
true;
16986 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
16989 pm_node_list_append(parser->
arena, &nodes, node);
16996 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
16997 node = UP(pm_find_pattern_node_create(parser, &nodes));
16999 if (nodes.
size == 2) {
17000 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17003 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17005 if (leading_rest && trailing_rest) {
17006 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17011 }
else if (leading_rest) {
17014 node = UP(pm_array_pattern_node_rest_create(parser, node));
17026parse_negative_numeric(
pm_node_t *node) {
17027 switch (PM_NODE_TYPE(node)) {
17028 case PM_INTEGER_NODE: {
17035 case PM_FLOAT_NODE: {
17042 case PM_RATIONAL_NODE: {
17049 case PM_IMAGINARY_NODE:
17055 assert(
false &&
"unreachable");
17068 case PM_ERR_HASH_KEY: {
17072 case PM_ERR_HASH_VALUE:
17073 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17077 case PM_ERR_UNARY_RECEIVER: {
17082 case PM_ERR_UNARY_DISALLOWED:
17083 case PM_ERR_EXPECT_ARGUMENT: {
17088 pm_parser_err_previous(parser, diag_id);
17098#define CONTEXT_NONE 0
17099#define CONTEXT_THROUGH_ENSURE 1
17100#define CONTEXT_THROUGH_ELSE 2
17103 int context = CONTEXT_NONE;
17105 while (context_node != NULL) {
17106 switch (context_node->
context) {
17127 if (context == CONTEXT_NONE) {
17128 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17129 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17130 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17131 }
else if (context == CONTEXT_THROUGH_ELSE) {
17132 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17144 context = CONTEXT_THROUGH_ELSE;
17155 context = CONTEXT_THROUGH_ENSURE;
17159 assert(
false &&
"unreachable");
17190 context_node = context_node->
prev;
17194#undef CONTEXT_ENSURE
17205 while (context_node != NULL) {
17206 switch (context_node->
context) {
17231 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17235 assert(
false &&
"unreachable");
17277 context_node = context_node->
prev;
17289 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
17300pm_command_call_value_p(
const pm_node_t *node) {
17301 switch (PM_NODE_TYPE(node)) {
17302 case PM_CALL_NODE: {
17307 if (pm_call_node_command_p(call) && !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) && (call->
receiver == NULL || call->
call_operator_loc.
length > 0)) {
17314 return pm_command_call_value_p(call->
receiver);
17319 case PM_SUPER_NODE: {
17323 case PM_YIELD_NODE: {
17327 case PM_RESCUE_MODIFIER_NODE:
17329 case PM_DEF_NODE: {
17333 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
17336 return pm_command_call_value_p(body);
17352pm_block_call_p(
const pm_node_t *node) {
17353 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17358 if (call->
arguments != NULL && call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE)) {
17379 switch (parser->
current.type) {
17380 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17381 parser_lex(parser);
17384 pm_accepts_block_stack_push(parser,
true);
17385 bool parsed_bare_hash =
false;
17387 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
17388 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
17392 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17398 if (accept1(parser, PM_TOKEN_COMMA)) {
17401 if (accepted_newline) {
17402 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
17416 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
17420 if (accept1(parser, PM_TOKEN_USTAR)) {
17424 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
17425 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
17427 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
17430 element = UP(pm_splat_node_create(parser, &
operator, expression));
17431 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
17432 if (parsed_bare_hash) {
17433 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
17436 element = UP(pm_keyword_hash_node_create(parser));
17439 if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_DO_BLOCK, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) {
17440 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17443 pm_static_literals_free(&hash_keys);
17444 parsed_bare_hash =
true;
17446 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_LABEL, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
17448 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17449 if (parsed_bare_hash) {
17450 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
17455 pm_hash_key_static_literals_add(parser, &hash_keys, element);
17458 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
17462 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
17463 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(
operator), value));
17464 pm_keyword_hash_node_elements_append(parser->
arena, hash, assoc);
17466 element = UP(hash);
17467 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17468 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17471 pm_static_literals_free(&hash_keys);
17472 parsed_bare_hash =
true;
17476 pm_array_node_elements_append(parser->
arena, array, element);
17477 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
17480 accept1(parser, PM_TOKEN_NEWLINE);
17482 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17488 pm_array_node_close_set(parser, array, &parser->
previous);
17489 pm_accepts_block_stack_pop(parser);
17493 case PM_TOKEN_PARENTHESIS_LEFT:
17494 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17496 pm_node_flags_t paren_flags = 0;
17499 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17501 parser_lex(parser);
17503 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17504 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17505 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17512 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
17513 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17514 pop_block_exits(parser, previous_block_exits);
17515 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, paren_flags));
17520 pm_accepts_block_stack_push(parser,
true);
17522 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17523 context_pop(parser);
17528 bool terminator_found =
false;
17530 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17531 terminator_found =
true;
17532 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17533 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
17534 terminator_found =
true;
17537 if (terminator_found) {
17539 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17540 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17541 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17550 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17551 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
17552 lex_state_set(parser, PM_LEX_STATE_ENDARG);
17555 parser_lex(parser);
17556 pm_accepts_block_stack_pop(parser);
17557 pop_block_exits(parser, previous_block_exits);
17559 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17565 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
17568 multi_target = pm_multi_target_node_create(parser);
17569 pm_multi_target_node_targets_append(parser, multi_target, statement);
17572 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
17574 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
17575 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->
previous);
17578 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
17579 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17580 accept1(parser, PM_TOKEN_NEWLINE);
17582 result = UP(multi_target);
17591 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
17594 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17595 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
17599 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17609 pm_statements_node_body_append(parser, statements, statement,
true);
17611 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, paren_flags));
17618 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17621 pm_statements_node_body_append(parser, statements, statement,
true);
17625 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
17631 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17632 pm_statements_node_body_append(parser, statements, node,
true);
17639 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
17645 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
17649 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17650 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17651 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
17652 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17654 }
else if (!match1(parser, PM_TOKEN_EOF)) {
17661 context_pop(parser);
17662 pm_accepts_block_stack_pop(parser);
17663 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17672 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17674 pm_multi_target_node_targets_append(parser, multi_target, statement);
17676 statement = UP(multi_target);
17680 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
17681 const uint8_t *offset = parser->
start + PM_NODE_END(statement);
17682 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
17683 pm_node_t *value = UP(pm_missing_node_create(parser, PM_NODE_END(statement), 0));
17685 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
17688 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
17692 pop_block_exits(parser, previous_block_exits);
17693 pm_void_statements_check(parser, statements,
true);
17694 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, paren_flags));
17696 case PM_TOKEN_BRACE_LEFT: {
17707 pm_accepts_block_stack_push(parser,
true);
17708 parser_lex(parser);
17713 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
17714 if (current_hash_keys != NULL) {
17715 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
17718 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
17719 pm_static_literals_free(&hash_keys);
17722 accept1(parser, PM_TOKEN_NEWLINE);
17725 pm_accepts_block_stack_pop(parser);
17726 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
17727 pm_hash_node_closing_loc_set(parser, node, &parser->
previous);
17731 case PM_TOKEN_CHARACTER_LITERAL: {
17732 pm_node_t *node = UP(pm_string_node_create_current_string(
17735 .type = PM_TOKEN_STRING_BEGIN,
17736 .start = parser->
current.start,
17737 .end = parser->
current.start + 1
17740 .type = PM_TOKEN_STRING_CONTENT,
17741 .start = parser->
current.start + 1,
17747 pm_node_flag_set(node, parse_unescaped_encoding(parser));
17751 parser_lex(parser);
17755 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17756 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
17761 case PM_TOKEN_CLASS_VARIABLE: {
17762 parser_lex(parser);
17763 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
17765 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17766 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17771 case PM_TOKEN_CONSTANT: {
17772 parser_lex(parser);
17778 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
17779 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17780 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17781 match1(parser, PM_TOKEN_BRACE_LEFT)
17784 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
17785 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
17790 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17793 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17798 case PM_TOKEN_UCOLON_COLON: {
17799 parser_lex(parser);
17802 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17803 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous));
17805 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17806 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17811 case PM_TOKEN_UDOT_DOT:
17812 case PM_TOKEN_UDOT_DOT_DOT: {
17814 parser_lex(parser);
17816 pm_node_t *right = parse_expression(parser, pm_binding_powers[
operator.
type].left, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
17822 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17823 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
17826 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17828 case PM_TOKEN_FLOAT:
17829 parser_lex(parser);
17830 return UP(pm_float_node_create(parser, &parser->
previous));
17831 case PM_TOKEN_FLOAT_IMAGINARY:
17832 parser_lex(parser);
17833 return UP(pm_float_node_imaginary_create(parser, &parser->
previous));
17834 case PM_TOKEN_FLOAT_RATIONAL:
17835 parser_lex(parser);
17836 return UP(pm_float_node_rational_create(parser, &parser->
previous));
17837 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
17838 parser_lex(parser);
17839 return UP(pm_float_node_rational_imaginary_create(parser, &parser->
previous));
17840 case PM_TOKEN_NUMBERED_REFERENCE: {
17841 parser_lex(parser);
17842 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
17844 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17845 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17850 case PM_TOKEN_GLOBAL_VARIABLE: {
17851 parser_lex(parser);
17852 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
17854 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17855 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17860 case PM_TOKEN_BACK_REFERENCE: {
17861 parser_lex(parser);
17862 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
17864 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17865 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17870 case PM_TOKEN_IDENTIFIER:
17871 case PM_TOKEN_METHOD_NAME: {
17872 parser_lex(parser);
17874 pm_node_t *node = parse_variable_call(parser);
17876 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17884 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
17887 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
17896 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
17898 PM_NODE_LENGTH_SET_LOCATION(call, end);
17906 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17907 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17908 match1(parser, PM_TOKEN_BRACE_LEFT)
17911 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
17912 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
17914 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
17918 pm_node_unreference(parser, node);
17924 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
17926 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
17927 pm_node_unreference(parser, node);
17930 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
17938 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17939 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17944 case PM_TOKEN_HEREDOC_START: {
17950 size_t common_whitespace = (size_t) -1;
17953 parser_lex(parser);
17959 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
17965 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
17966 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY));
17971 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
17972 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
17979 node = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
17980 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
17985 pm_node_flag_set(part, parse_unescaped_encoding(parser));
17992 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
17994 cast->
base.
type = PM_X_STRING_NODE;
17997 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
17998 parse_heredoc_dedent_string(parser->
arena, &cast->
unescaped, common_whitespace);
18008 pm_node_list_append(parser->
arena, &parts, part);
18010 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18011 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18012 pm_node_list_append(parser->
arena, &parts, part);
18018 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18020 cast->
parts = parts;
18023 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->
previous);
18031 pm_interpolated_string_node_closing_set(parser, cast, &parser->
previous);
18039 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18041 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18047 parse_heredoc_dedent(parser, nodes, common_whitespace);
18051 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18052 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18057 case PM_TOKEN_INSTANCE_VARIABLE: {
18058 parser_lex(parser);
18059 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
18061 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18062 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18067 case PM_TOKEN_INTEGER: {
18069 parser_lex(parser);
18070 return UP(pm_integer_node_create(parser, base, &parser->
previous));
18072 case PM_TOKEN_INTEGER_IMAGINARY: {
18074 parser_lex(parser);
18075 return UP(pm_integer_node_imaginary_create(parser, base, &parser->
previous));
18077 case PM_TOKEN_INTEGER_RATIONAL: {
18079 parser_lex(parser);
18080 return UP(pm_integer_node_rational_create(parser, base, &parser->
previous));
18082 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18084 parser_lex(parser);
18085 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous));
18087 case PM_TOKEN_KEYWORD___ENCODING__:
18088 parser_lex(parser);
18089 return UP(pm_source_encoding_node_create(parser, &parser->
previous));
18090 case PM_TOKEN_KEYWORD___FILE__:
18091 parser_lex(parser);
18092 return UP(pm_source_file_node_create(parser, &parser->
previous));
18093 case PM_TOKEN_KEYWORD___LINE__:
18094 parser_lex(parser);
18095 return UP(pm_source_line_node_create(parser, &parser->
previous));
18096 case PM_TOKEN_KEYWORD_ALIAS: {
18097 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18098 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18101 parser_lex(parser);
18104 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18105 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18107 switch (PM_NODE_TYPE(new_name)) {
18108 case PM_BACK_REFERENCE_READ_NODE:
18109 case PM_NUMBERED_REFERENCE_READ_NODE:
18110 case PM_GLOBAL_VARIABLE_READ_NODE: {
18111 if (PM_NODE_TYPE_P(old_name, PM_BACK_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(old_name, PM_GLOBAL_VARIABLE_READ_NODE)) {
18112 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18113 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18116 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18119 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
18121 case PM_SYMBOL_NODE:
18122 case PM_INTERPOLATED_SYMBOL_NODE: {
18123 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18124 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18129 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
18132 case PM_TOKEN_KEYWORD_CASE: {
18133 size_t opening_newline_index = token_newline_index(parser);
18134 parser_lex(parser);
18140 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18142 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18143 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18145 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18147 }
else if (!token_begins_expression_p(parser->
current.type)) {
18150 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18151 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18154 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18155 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18156 parser_lex(parser);
18157 pop_block_exits(parser, previous_block_exits);
18158 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18159 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous));
18166 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18167 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
18173 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18174 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18175 parser_lex(parser);
18178 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18181 if (accept1(parser, PM_TOKEN_USTAR)) {
18183 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18185 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18186 pm_when_node_conditions_append(parser->
arena, when_node, UP(splat_node));
18188 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18190 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18191 pm_when_node_conditions_append(parser->
arena, when_node, condition);
18195 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18199 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18200 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18201 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18202 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18205 pm_when_clause_static_literals_add(parser, &literals, condition);
18207 }
while (accept1(parser, PM_TOKEN_COMMA));
18209 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18210 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18211 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->
previous);
18214 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18215 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->
previous);
18218 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18220 if (statements != NULL) {
18221 pm_when_node_statements_set(when_node, statements);
18225 pm_case_node_condition_append(parser->
arena, case_node, UP(when_node));
18231 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18234 pm_static_literals_free(&literals);
18235 node = UP(case_node);
18237 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
18241 if (predicate == NULL) {
18242 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18248 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18249 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18254 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18256 parser_lex(parser);
18261 pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1));
18268 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18270 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18271 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18272 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18274 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18275 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18282 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18283 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18287 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18294 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18302 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
18303 pm_case_match_node_condition_append(parser->
arena, case_node, condition);
18309 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18312 node = UP(case_node);
18315 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18316 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18320 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18321 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18323 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18326 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18327 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18333 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18334 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18336 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18342 pop_block_exits(parser, previous_block_exits);
18345 case PM_TOKEN_KEYWORD_BEGIN: {
18346 size_t opening_newline_index = token_newline_index(parser);
18347 parser_lex(parser);
18350 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18353 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18356 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18357 pm_accepts_block_stack_push(parser,
true);
18358 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18359 pm_accepts_block_stack_pop(parser);
18360 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18363 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18364 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18365 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
18367 PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->
previous);
18368 pm_begin_node_end_keyword_set(parser, begin_node, &parser->
previous);
18369 pop_block_exits(parser, previous_block_exits);
18370 return UP(begin_node);
18372 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
18374 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18376 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18377 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18380 parser_lex(parser);
18383 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
18387 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
18390 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
18393 flush_block_exits(parser, previous_block_exits);
18394 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
18396 case PM_TOKEN_KEYWORD_BREAK:
18397 case PM_TOKEN_KEYWORD_NEXT:
18398 case PM_TOKEN_KEYWORD_RETURN: {
18399 parser_lex(parser);
18405 token_begins_expression_p(parser->
current.type) ||
18406 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
18408 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
18410 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
18412 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
18415 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
18416 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(next.
type));
18421 switch (keyword.
type) {
18422 case PM_TOKEN_KEYWORD_BREAK: {
18427 case PM_TOKEN_KEYWORD_NEXT: {
18432 case PM_TOKEN_KEYWORD_RETURN: {
18434 parse_return(parser, node);
18438 assert(
false &&
"unreachable");
18439 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
18442 case PM_TOKEN_KEYWORD_SUPER: {
18443 parser_lex(parser);
18447 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
18452 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
18454 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
18457 return UP(pm_super_node_create(parser, &keyword, &arguments));
18459 case PM_TOKEN_KEYWORD_YIELD: {
18460 parser_lex(parser);
18464 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
18470 if (arguments.
block != NULL) {
18471 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
18472 pm_node_unreference(parser, arguments.
block);
18473 arguments.
block = NULL;
18481 case PM_TOKEN_KEYWORD_CLASS: {
18482 size_t opening_newline_index = token_newline_index(parser);
18483 parser_lex(parser);
18486 pm_do_loop_stack_push(parser,
false);
18489 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18491 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18493 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, (uint16_t) (depth + 1));
18495 pm_parser_scope_push(parser,
true);
18496 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18501 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18502 pm_accepts_block_stack_push(parser,
true);
18503 statements = UP(parse_statements(parser,
PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18504 pm_accepts_block_stack_pop(parser);
18507 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18508 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18509 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_SCLASS, (uint16_t) (depth + 1)));
18511 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18514 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18519 pm_parser_scope_pop(parser);
18520 pm_do_loop_stack_pop(parser);
18522 flush_block_exits(parser, previous_block_exits);
18523 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous));
18526 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
18528 if (name.
type != PM_TOKEN_CONSTANT) {
18529 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18535 if (match1(parser, PM_TOKEN_LESS)) {
18536 inheritance_operator = parser->
current;
18537 lex_state_set(parser, PM_LEX_STATE_BEG);
18540 parser_lex(parser);
18542 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
18547 pm_parser_scope_push(parser,
true);
18549 if (inheritance_operator.
start != NULL) {
18550 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18552 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18556 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18557 pm_accepts_block_stack_push(parser,
true);
18558 statements = UP(parse_statements(parser,
PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18559 pm_accepts_block_stack_pop(parser);
18562 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18563 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18564 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1)));
18566 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18569 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18571 if (context_def_p(parser)) {
18572 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18578 pm_parser_scope_pop(parser);
18579 pm_do_loop_stack_pop(parser);
18581 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18582 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18585 pop_block_exits(parser, previous_block_exits);
18586 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->
previous));
18588 case PM_TOKEN_KEYWORD_DEF: {
18590 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18593 size_t opening_newline_index = token_newline_index(parser);
18603 parser_lex(parser);
18607 bool valid_name =
true;
18609 switch (parser->
current.type) {
18610 case PM_CASE_OPERATOR:
18611 pm_parser_scope_push(parser,
true);
18612 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18613 parser_lex(parser);
18617 case PM_TOKEN_IDENTIFIER: {
18618 parser_lex(parser);
18620 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18621 receiver = parse_variable_call(parser);
18623 pm_parser_scope_push(parser,
true);
18624 lex_state_set(parser, PM_LEX_STATE_FNAME);
18625 parser_lex(parser);
18628 name = parse_method_definition_name(parser);
18630 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous));
18631 pm_parser_scope_push(parser,
true);
18638 case PM_TOKEN_INSTANCE_VARIABLE:
18639 case PM_TOKEN_CLASS_VARIABLE:
18640 case PM_TOKEN_GLOBAL_VARIABLE:
18641 valid_name =
false;
18643 case PM_TOKEN_CONSTANT:
18644 case PM_TOKEN_KEYWORD_NIL:
18645 case PM_TOKEN_KEYWORD_SELF:
18646 case PM_TOKEN_KEYWORD_TRUE:
18647 case PM_TOKEN_KEYWORD_FALSE:
18648 case PM_TOKEN_KEYWORD___FILE__:
18649 case PM_TOKEN_KEYWORD___LINE__:
18650 case PM_TOKEN_KEYWORD___ENCODING__: {
18651 pm_parser_scope_push(parser,
true);
18652 parser_lex(parser);
18656 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18657 lex_state_set(parser, PM_LEX_STATE_FNAME);
18658 parser_lex(parser);
18661 switch (identifier.
type) {
18662 case PM_TOKEN_CONSTANT:
18663 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18665 case PM_TOKEN_INSTANCE_VARIABLE:
18666 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18668 case PM_TOKEN_CLASS_VARIABLE:
18669 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18671 case PM_TOKEN_GLOBAL_VARIABLE:
18672 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18674 case PM_TOKEN_KEYWORD_NIL:
18675 receiver = UP(pm_nil_node_create(parser, &identifier));
18677 case PM_TOKEN_KEYWORD_SELF:
18678 receiver = UP(pm_self_node_create(parser, &identifier));
18680 case PM_TOKEN_KEYWORD_TRUE:
18681 receiver = UP(pm_true_node_create(parser, &identifier));
18683 case PM_TOKEN_KEYWORD_FALSE:
18684 receiver = UP(pm_false_node_create(parser, &identifier));
18686 case PM_TOKEN_KEYWORD___FILE__:
18687 receiver = UP(pm_source_file_node_create(parser, &identifier));
18689 case PM_TOKEN_KEYWORD___LINE__:
18690 receiver = UP(pm_source_line_node_create(parser, &identifier));
18692 case PM_TOKEN_KEYWORD___ENCODING__:
18693 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18699 name = parse_method_definition_name(parser);
18709 case PM_TOKEN_PARENTHESIS_LEFT: {
18714 context_pop(parser);
18715 parser_lex(parser);
18718 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
18720 accept1(parser, PM_TOKEN_NEWLINE);
18721 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18724 lex_state_set(parser, PM_LEX_STATE_FNAME);
18725 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18728 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18732 pm_parser_scope_push(parser,
true);
18734 name = parse_method_definition_name(parser);
18738 pm_parser_scope_push(parser,
true);
18739 name = parse_method_definition_name(parser);
18747 bool accept_endless_def =
true;
18748 switch (parser->
current.type) {
18749 case PM_TOKEN_PARENTHESIS_LEFT: {
18750 parser_lex(parser);
18753 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18758 params = parse_parameters(
18760 PM_BINDING_POWER_DEFINED,
18762 allow_trailing_comma,
18766 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18767 (uint16_t) (depth + 1)
18771 lex_state_set(parser, PM_LEX_STATE_BEG);
18774 context_pop(parser);
18775 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18784 case PM_CASE_PARAMETER: {
18787 if (parser->
current.type == PM_TOKEN_LABEL) {
18788 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
18791 params = parse_parameters(
18793 PM_BINDING_POWER_DEFINED,
18799 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18800 (uint16_t) (depth + 1)
18805 accept_endless_def =
false;
18807 context_pop(parser);
18812 context_pop(parser);
18821 if (accept1(parser, PM_TOKEN_EQUAL)) {
18822 if (token_is_setter_name(&name)) {
18823 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18825 if (!accept_endless_def) {
18826 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18832 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_START(parser, &def_keyword), PM_TOKENS_LENGTH(&def_keyword, &parser->
previous), PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE,
"endless method definition");
18837 pm_do_loop_stack_push(parser,
false);
18838 statements = UP(pm_statements_node_create(parser));
18840 uint8_t allow_flags;
18842 allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
18845 allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18856 pm_accepts_block_stack_push(parser,
true);
18857 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_flags | PM_PARSE_IN_ENDLESS_DEF, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
18858 pm_accepts_block_stack_pop(parser);
18866 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18867 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18868 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18871 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18878 pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_MATCH + 1, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
18879 context_pop(parser);
18881 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18887 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(statement)) {
18891 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18892 pm_do_loop_stack_pop(parser);
18893 context_pop(parser);
18895 if (lparen.
start == NULL) {
18896 lex_state_set(parser, PM_LEX_STATE_BEG);
18898 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18900 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18903 pm_accepts_block_stack_push(parser,
true);
18904 pm_do_loop_stack_push(parser,
false);
18906 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18907 pm_accepts_block_stack_push(parser,
true);
18908 statements = UP(parse_statements(parser,
PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18909 pm_accepts_block_stack_pop(parser);
18912 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18913 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18914 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &def_keyword, def_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_DEF, (uint16_t) (depth + 1)));
18916 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18919 pm_accepts_block_stack_pop(parser);
18920 pm_do_loop_stack_pop(parser);
18922 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18928 pm_parser_scope_pop(parser);
18935 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
18937 flush_block_exits(parser, previous_block_exits);
18939 return UP(pm_def_node_create(
18948 NTOK2PTR(
operator),
18952 NTOK2PTR(end_keyword)
18955 case PM_TOKEN_KEYWORD_DEFINED: {
18956 parser_lex(parser);
18964 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
18966 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
18969 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18970 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
18973 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
18976 accept1(parser, PM_TOKEN_NEWLINE);
18977 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18982 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
18985 context_pop(parser);
18986 return UP(pm_defined_node_create(
18994 case PM_TOKEN_KEYWORD_END_UPCASE: {
18995 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18996 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
18999 parser_lex(parser);
19002 if (context_def_p(parser)) {
19003 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19006 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19010 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
19011 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
19013 case PM_TOKEN_KEYWORD_FALSE:
19014 parser_lex(parser);
19015 return UP(pm_false_node_create(parser, &parser->
previous));
19016 case PM_TOKEN_KEYWORD_FOR: {
19017 size_t opening_newline_index = token_newline_index(parser);
19018 parser_lex(parser);
19026 if (accept1(parser, PM_TOKEN_USTAR)) {
19030 if (token_begins_expression_p(parser->
current.type)) {
19031 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19034 index = UP(pm_splat_node_create(parser, &star_operator, name));
19035 }
else if (token_begins_expression_p(parser->
current.type)) {
19036 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19038 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19039 index = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
19043 if (match1(parser, PM_TOKEN_COMMA)) {
19044 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19046 index = parse_target(parser, index,
false,
false);
19049 context_pop(parser);
19050 pm_do_loop_stack_push(parser,
true);
19052 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19055 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19056 pm_do_loop_stack_pop(parser);
19059 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19062 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19068 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19069 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19072 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19073 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19075 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->
previous));
19077 case PM_TOKEN_KEYWORD_IF:
19078 if (parser_end_of_line_p(parser)) {
19079 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->
current, PM_WARN_KEYWORD_EOL);
19082 size_t opening_newline_index = token_newline_index(parser);
19083 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19084 parser_lex(parser);
19086 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19087 case PM_TOKEN_KEYWORD_UNDEF: {
19088 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19089 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19092 parser_lex(parser);
19094 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19096 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19098 pm_undef_node_append(parser->
arena, undef, name);
19100 while (match1(parser, PM_TOKEN_COMMA)) {
19101 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19102 parser_lex(parser);
19103 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19105 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19109 pm_undef_node_append(parser->
arena, undef, name);
19115 case PM_TOKEN_KEYWORD_NOT: {
19116 parser_lex(parser);
19129 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19130 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19131 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->
previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19133 accept1(parser, PM_TOKEN_NEWLINE);
19134 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19137 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
19140 accept1(parser, PM_TOKEN_NEWLINE);
19142 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19145 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19146 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19148 arguments.
opening_loc = TOK2LOC(parser, &lparen);
19149 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19152 accept1(parser, PM_TOKEN_NEWLINE);
19153 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19158 receiver = parse_expression(parser, PM_BINDING_POWER_NOT, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19161 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19163 case PM_TOKEN_KEYWORD_UNLESS: {
19164 size_t opening_newline_index = token_newline_index(parser);
19165 parser_lex(parser);
19167 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19169 case PM_TOKEN_KEYWORD_MODULE: {
19171 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19173 size_t opening_newline_index = token_newline_index(parser);
19174 parser_lex(parser);
19177 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19182 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19183 pop_block_exits(parser, previous_block_exits);
19186 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19189 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19192 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19193 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous));
19200 if (name.
type != PM_TOKEN_CONSTANT) {
19201 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19204 pm_parser_scope_push(parser,
true);
19205 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19208 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19209 pm_accepts_block_stack_push(parser,
true);
19210 statements = UP(parse_statements(parser,
PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19211 pm_accepts_block_stack_pop(parser);
19214 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19215 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19216 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &module_keyword, module_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_MODULE, (uint16_t) (depth + 1)));
19218 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19224 pm_parser_scope_pop(parser);
19225 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
19227 if (context_def_p(parser)) {
19228 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19231 pop_block_exits(parser, previous_block_exits);
19233 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous));
19235 case PM_TOKEN_KEYWORD_NIL:
19236 parser_lex(parser);
19237 return UP(pm_nil_node_create(parser, &parser->
previous));
19238 case PM_TOKEN_KEYWORD_REDO: {
19239 parser_lex(parser);
19246 case PM_TOKEN_KEYWORD_RETRY: {
19247 parser_lex(parser);
19250 parse_retry(parser, node);
19254 case PM_TOKEN_KEYWORD_SELF:
19255 parser_lex(parser);
19256 return UP(pm_self_node_create(parser, &parser->
previous));
19257 case PM_TOKEN_KEYWORD_TRUE:
19258 parser_lex(parser);
19259 return UP(pm_true_node_create(parser, &parser->
previous));
19260 case PM_TOKEN_KEYWORD_UNTIL: {
19261 size_t opening_newline_index = token_newline_index(parser);
19264 pm_do_loop_stack_push(parser,
true);
19266 parser_lex(parser);
19268 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19270 pm_do_loop_stack_pop(parser);
19271 context_pop(parser);
19274 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19277 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19281 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19282 pm_accepts_block_stack_push(parser,
true);
19283 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19284 pm_accepts_block_stack_pop(parser);
19285 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19288 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19289 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
19291 return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->
previous, predicate, statements, 0));
19293 case PM_TOKEN_KEYWORD_WHILE: {
19294 size_t opening_newline_index = token_newline_index(parser);
19297 pm_do_loop_stack_push(parser,
true);
19299 parser_lex(parser);
19301 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19303 pm_do_loop_stack_pop(parser);
19304 context_pop(parser);
19307 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19310 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19314 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19315 pm_accepts_block_stack_push(parser,
true);
19316 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19317 pm_accepts_block_stack_pop(parser);
19318 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19321 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19322 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
19324 return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->
previous, predicate, statements, 0));
19326 case PM_TOKEN_PERCENT_LOWER_I: {
19327 parser_lex(parser);
19332 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19333 accept1(parser, PM_TOKEN_WORDS_SEP);
19334 if (match1(parser, PM_TOKEN_STRING_END))
break;
19338 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19340 if (current == NULL) {
19341 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->
current, NULL));
19342 parser_lex(parser);
19343 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19344 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
19345 parser_lex(parser);
19347 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19350 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
19351 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
previous, NULL));
19352 parser_lex(parser);
19355 pm_interpolated_symbol_node_append(parser->
arena, interpolated, first_string);
19356 pm_interpolated_symbol_node_append(parser->
arena, interpolated, second_string);
19359 current = UP(interpolated);
19361 assert(
false &&
"unreachable");
19366 pm_array_node_elements_append(parser->
arena, array, current);
19369 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
19374 if (match1(parser, PM_TOKEN_EOF)) {
19375 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19378 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
19380 pm_array_node_close_set(parser, array, &closing);
19384 case PM_TOKEN_PERCENT_UPPER_I: {
19385 parser_lex(parser);
19393 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19394 switch (parser->
current.type) {
19395 case PM_TOKEN_WORDS_SEP: {
19396 if (current == NULL) {
19402 pm_array_node_elements_append(parser->
arena, array, current);
19406 parser_lex(parser);
19409 case PM_TOKEN_STRING_CONTENT: {
19410 if (current == NULL) {
19414 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->
current, NULL));
19415 parser_lex(parser);
19416 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19420 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
19421 parser_lex(parser);
19424 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19430 .
type = PM_TOKEN_STRING_CONTENT,
19435 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
19436 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
previous, NULL));
19437 parser_lex(parser);
19440 pm_interpolated_symbol_node_append(parser->
arena, interpolated, first_string);
19441 pm_interpolated_symbol_node_append(parser->
arena, interpolated, second_string);
19444 current = UP(interpolated);
19446 assert(
false &&
"unreachable");
19451 case PM_TOKEN_EMBVAR: {
19452 bool start_location_set =
false;
19453 if (current == NULL) {
19457 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19458 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19464 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19465 pm_interpolated_symbol_node_append(parser->
arena, interpolated, current);
19466 PM_NODE_START_SET_NODE(interpolated, current);
19467 start_location_set =
true;
19468 current = UP(interpolated);
19474 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19476 if (!start_location_set) {
19477 PM_NODE_START_SET_NODE(current, part);
19481 case PM_TOKEN_EMBEXPR_BEGIN: {
19482 bool start_location_set =
false;
19483 if (current == NULL) {
19487 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19488 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19495 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19496 pm_interpolated_symbol_node_append(parser->
arena, interpolated, current);
19497 PM_NODE_START_SET_NODE(interpolated, current);
19498 start_location_set =
true;
19499 current = UP(interpolated);
19500 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19504 assert(
false &&
"unreachable");
19507 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19509 if (!start_location_set) {
19510 PM_NODE_START_SET_NODE(current, part);
19515 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19516 parser_lex(parser);
19523 pm_array_node_elements_append(parser->
arena, array, current);
19527 if (match1(parser, PM_TOKEN_EOF)) {
19528 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19531 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19533 pm_array_node_close_set(parser, array, &closing);
19537 case PM_TOKEN_PERCENT_LOWER_W: {
19538 parser_lex(parser);
19543 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19544 accept1(parser, PM_TOKEN_WORDS_SEP);
19545 if (match1(parser, PM_TOKEN_STRING_END))
break;
19549 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19550 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
19553 if (current == NULL) {
19555 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19557 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19559 pm_interpolated_string_node_append(parser->
arena, interpolated, current);
19560 pm_interpolated_string_node_append(parser->
arena, interpolated,
string);
19561 current = UP(interpolated);
19563 assert(
false &&
"unreachable");
19565 parser_lex(parser);
19569 pm_array_node_elements_append(parser->
arena, array, current);
19572 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
19577 if (match1(parser, PM_TOKEN_EOF)) {
19578 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
19581 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
19584 pm_array_node_close_set(parser, array, &closing);
19587 case PM_TOKEN_PERCENT_UPPER_W: {
19588 parser_lex(parser);
19596 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19597 switch (parser->
current.type) {
19598 case PM_TOKEN_WORDS_SEP: {
19603 if (current == NULL) {
19610 pm_array_node_elements_append(parser->
arena, array, current);
19614 parser_lex(parser);
19617 case PM_TOKEN_STRING_CONTENT: {
19618 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
19619 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
19620 parser_lex(parser);
19622 if (current == NULL) {
19628 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19633 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19639 pm_interpolated_string_node_append(parser->
arena, interpolated, current);
19640 pm_interpolated_string_node_append(parser->
arena, interpolated,
string);
19641 current = UP(interpolated);
19643 assert(
false &&
"unreachable");
19648 case PM_TOKEN_EMBVAR: {
19649 if (current == NULL) {
19654 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19655 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19661 pm_interpolated_string_node_append(parser->
arena, interpolated, current);
19662 current = UP(interpolated);
19669 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19673 case PM_TOKEN_EMBEXPR_BEGIN: {
19674 if (current == NULL) {
19679 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19680 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19686 pm_interpolated_string_node_append(parser->
arena, interpolated, current);
19687 current = UP(interpolated);
19688 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19693 assert(
false &&
"unreachable");
19696 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19701 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19702 parser_lex(parser);
19709 pm_array_node_elements_append(parser->
arena, array, current);
19713 if (match1(parser, PM_TOKEN_EOF)) {
19714 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19717 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19720 pm_array_node_close_set(parser, array, &closing);
19723 case PM_TOKEN_REGEXP_BEGIN: {
19725 parser_lex(parser);
19727 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19732 .
type = PM_TOKEN_STRING_CONTENT,
19737 parser_lex(parser);
19740 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
19746 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19753 parser_lex(parser);
19758 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19765 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19766 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
19774 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19776 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->
previous, NULL, &unescaped));
19781 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19784 pm_interpolated_regular_expression_node_append(parser->
arena, interpolated, part);
19789 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19795 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19796 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19797 pm_interpolated_regular_expression_node_append(parser->
arena, interpolated, part);
19802 if (match1(parser, PM_TOKEN_EOF)) {
19803 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19806 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19809 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19810 return UP(interpolated);
19812 case PM_TOKEN_BACKTICK:
19813 case PM_TOKEN_PERCENT_LOWER_X: {
19814 parser_lex(parser);
19821 if (match1(parser, PM_TOKEN_STRING_END)) {
19826 .
type = PM_TOKEN_STRING_CONTENT,
19831 parser_lex(parser);
19832 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->
previous));
19837 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19844 parser_lex(parser);
19846 if (match1(parser, PM_TOKEN_STRING_END)) {
19847 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
19848 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19849 parser_lex(parser);
19855 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19857 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->
previous, NULL, &unescaped));
19858 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19860 pm_interpolated_xstring_node_append(parser->
arena, node, part);
19865 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19869 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19870 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19871 pm_interpolated_xstring_node_append(parser->
arena, node, part);
19876 if (match1(parser, PM_TOKEN_EOF)) {
19877 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
19880 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
19882 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
19886 case PM_TOKEN_USTAR: {
19887 parser_lex(parser);
19892 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19893 pm_parser_err_prefix(parser, diag_id);
19894 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
19900 if (token_begins_expression_p(parser->
current.type)) {
19901 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19904 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
19906 if (match1(parser, PM_TOKEN_COMMA)) {
19907 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19909 return parse_target_validate(parser, splat,
true);
19912 case PM_TOKEN_BANG: {
19913 if (binding_power > PM_BINDING_POWER_UNARY) {
19914 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19917 parser_lex(parser);
19920 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0), PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
19921 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
19923 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
19926 case PM_TOKEN_TILDE: {
19927 if (binding_power > PM_BINDING_POWER_UNARY) {
19928 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19930 parser_lex(parser);
19933 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
19934 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
19938 case PM_TOKEN_UMINUS: {
19939 if (binding_power > PM_BINDING_POWER_UNARY) {
19940 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19942 parser_lex(parser);
19945 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
19946 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
19950 case PM_TOKEN_UMINUS_NUM: {
19951 parser_lex(parser);
19954 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
19956 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
19958 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
19959 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
19960 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
19962 switch (PM_NODE_TYPE(node)) {
19963 case PM_INTEGER_NODE:
19964 case PM_FLOAT_NODE:
19965 case PM_RATIONAL_NODE:
19966 case PM_IMAGINARY_NODE:
19967 parse_negative_numeric(node);
19970 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
19977 case PM_TOKEN_MINUS_GREATER: {
19981 size_t opening_newline_index = token_newline_index(parser);
19982 pm_accepts_block_stack_push(parser,
true);
19983 parser_lex(parser);
19986 pm_parser_scope_push(parser,
false);
19990 switch (parser->
current.type) {
19991 case PM_TOKEN_PARENTHESIS_LEFT: {
19993 parser_lex(parser);
19995 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19996 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
19998 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20001 accept1(parser, PM_TOKEN_NEWLINE);
20002 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20004 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->
previous);
20007 case PM_CASE_PARAMETER: {
20008 pm_accepts_block_stack_push(parser,
false);
20009 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
20010 pm_accepts_block_stack_pop(parser);
20014 block_parameters = NULL;
20023 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20026 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20030 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20031 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20033 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20036 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20040 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20041 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20042 body = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &
operator, opening.
start, (
pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1)));
20044 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20047 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20051 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20052 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->
previous);
20054 pm_parser_scope_pop(parser);
20055 pm_accepts_block_stack_pop(parser);
20057 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body));
20059 case PM_TOKEN_UPLUS: {
20060 if (binding_power > PM_BINDING_POWER_UNARY) {
20061 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20063 parser_lex(parser);
20066 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20067 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20071 case PM_TOKEN_STRING_BEGIN:
20072 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
20073 case PM_TOKEN_SYMBOL_BEGIN: {
20075 parser_lex(parser);
20077 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20088 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20089 pm_parser_err_prefix(parser, diag_id);
20095 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20096 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20102 pm_parser_err_prefix(parser, diag_id);
20105 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
20120parse_assignment_value(
pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags,
pm_diagnostic_id_t diag_id, uint16_t depth) {
20121 pm_node_t *value = parse_value_expression(parser, binding_power, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), diag_id, (uint16_t) (depth + 1));
20127 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
20129 parser_lex(parser);
20130 parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20135 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20139 parser_lex(parser);
20141 pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20142 context_pop(parser);
20144 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20156 switch (PM_NODE_TYPE(node)) {
20157 case PM_BEGIN_NODE: {
20162 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20164 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20167 case PM_PARENTHESES_NODE: {
20169 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20172 case PM_STATEMENTS_NODE: {
20177 parse_assignment_value_local(parser, statement);
20199parse_assignment_values(
pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags,
pm_diagnostic_id_t diag_id, uint16_t depth) {
20200 bool permitted =
true;
20201 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20203 pm_node_t *value = parse_starred_expression(parser, binding_power, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MODIFIER ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), diag_id, (uint16_t) (depth + 1));
20204 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20206 parse_assignment_value_local(parser, value);
20207 bool single_value =
true;
20212 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20213 single_value =
false;
20216 pm_array_node_elements_append(parser->
arena, array, value);
20219 while (accept1(parser, PM_TOKEN_COMMA)) {
20220 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20222 pm_array_node_elements_append(parser->
arena, array, element);
20223 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20225 parse_assignment_value_local(parser, element);
20233 if (single_value && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
20235 parser_lex(parser);
20236 parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20241 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20245 parser_lex(parser);
20247 bool accepts_command_call_inner =
false;
20251 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20254 accepts_command_call_inner =
true;
20258 pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (accepts_command_call_inner ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0), PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20259 context_pop(parser);
20261 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20277 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20278 pm_node_unreference(parser, UP(call_node->
arguments));
20282 if (call_node->
block != NULL) {
20283 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20284 pm_node_unreference(parser, UP(call_node->
block));
20285 call_node->
block = NULL;
20289static inline const uint8_t *
20290pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20293 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20294 uint8_t value = escape_hexadecimal_digit(*cursor);
20297 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20298 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20302 pm_buffer_append_byte(unescaped, value);
20304 pm_buffer_append_string(unescaped,
"\\x", 2);
20310static inline const uint8_t *
20311pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20312 uint8_t value = (uint8_t) (*cursor -
'0');
20315 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20316 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20319 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20320 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20325 pm_buffer_append_byte(unescaped, value);
20329static inline const uint8_t *
20331 const uint8_t *start = cursor - 1;
20334 if (cursor >= end) {
20335 pm_buffer_append_string(unescaped,
"\\u", 2);
20339 if (*cursor !=
'{') {
20340 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20341 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
20343 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20344 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20347 return cursor + length;
20352 while (cursor < end && *cursor ==
' ') cursor++;
20354 if (cursor >= end)
break;
20355 if (*cursor ==
'}') {
20360 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20364 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
20366 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20374pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor,
const pm_location_t *error_location) {
20375 const uint8_t *end = source + length;
20376 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20379 if (++cursor >= end) {
20380 pm_buffer_append_byte(unescaped,
'\\');
20386 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20388 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20389 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20392 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
20395 pm_buffer_append_byte(unescaped,
'\\');
20399 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
20400 if (next_cursor == NULL)
break;
20402 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20403 cursor = next_cursor;
20406 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20432 pm_named_capture_escape(parser, &unescaped, source, length, cursor, shared ? NULL : &call->receiver->location);
20437 const uint8_t *start;
20438 const uint8_t *end;
20443 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20452 end = source + length;
20453 name = pm_parser_constant_id_raw(parser, start, end);
20460 void *memory =
xmalloc(length);
20461 if (memory == NULL) abort();
20463 memcpy(memory, source, length);
20464 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20469 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20470 pm_constant_id_list_append(parser->
arena, names, name);
20473 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20476 if (pm_local_is_keyword((
const char *) source, length)) {
20483 pm_parser_local_add(parser, name, start, end, 0);
20488 if (callback_data->
match == NULL) {
20489 callback_data->
match = pm_match_write_node_create(parser, call);
20494 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &TOK2LOC(parser, &((
pm_token_t) { .type = 0, .start = start, .end = end })), name, depth == -1 ? 0 : (uint32_t) depth));
20514 pm_regexp_parse_named_captures(parser,
pm_string_source(content),
pm_string_length(content),
false, extended_mode, parse_regular_expression_named_capture, &callback_data);
20516 if (callback_data.
match != NULL) {
20517 return UP(callback_data.
match);
20524parse_expression_infix(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20527 switch (token.type) {
20528 case PM_TOKEN_EQUAL: {
20529 switch (PM_NODE_TYPE(node)) {
20530 case PM_CALL_NODE: {
20536 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20537 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
20541 case PM_CASE_WRITABLE: {
20545 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20546 pm_parser_local_add_location(parser, &node->
location, 0);
20549 parser_lex(parser);
20550 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20552 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
20553 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20556 return parse_write(parser, node, &token, value);
20558 case PM_SPLAT_NODE: {
20560 pm_multi_target_node_targets_append(parser, multi_target, node);
20562 parser_lex(parser);
20563 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20564 return parse_write(parser, UP(multi_target), &token, value);
20566 case PM_SOURCE_ENCODING_NODE:
20567 case PM_FALSE_NODE:
20568 case PM_SOURCE_FILE_NODE:
20569 case PM_SOURCE_LINE_NODE:
20572 case PM_TRUE_NODE: {
20575 parser_lex(parser);
20576 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20577 return parse_unwriteable_write(parser, node, &token, value);
20583 parser_lex(parser);
20584 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20588 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
20589 switch (PM_NODE_TYPE(node)) {
20590 case PM_BACK_REFERENCE_READ_NODE:
20591 case PM_NUMBERED_REFERENCE_READ_NODE:
20592 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20594 case PM_GLOBAL_VARIABLE_READ_NODE: {
20595 parser_lex(parser);
20597 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20598 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
20602 case PM_CLASS_VARIABLE_READ_NODE: {
20603 parser_lex(parser);
20605 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20610 case PM_CONSTANT_PATH_NODE: {
20611 parser_lex(parser);
20613 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20616 return parse_shareable_constant_write(parser, write);
20618 case PM_CONSTANT_READ_NODE: {
20619 parser_lex(parser);
20621 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20624 return parse_shareable_constant_write(parser, write);
20626 case PM_INSTANCE_VARIABLE_READ_NODE: {
20627 parser_lex(parser);
20629 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20634 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20636 parser_lex(parser);
20638 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20639 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
20641 pm_node_unreference(parser, node);
20644 case PM_LOCAL_VARIABLE_READ_NODE: {
20645 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
20647 pm_node_unreference(parser, node);
20651 parser_lex(parser);
20653 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20654 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20658 case PM_CALL_NODE: {
20664 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20667 parser_lex(parser);
20669 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20670 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20677 parser_lex(parser);
20682 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20683 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20684 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
20688 if (pm_call_node_writable_p(parser, cast)) {
20689 parse_write_name(parser, &cast->
name);
20691 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20694 parse_call_operator_write(parser, cast, &token);
20695 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20696 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
20698 case PM_MULTI_WRITE_NODE: {
20699 parser_lex(parser);
20700 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
20704 parser_lex(parser);
20709 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
20713 case PM_TOKEN_PIPE_PIPE_EQUAL: {
20714 switch (PM_NODE_TYPE(node)) {
20715 case PM_BACK_REFERENCE_READ_NODE:
20716 case PM_NUMBERED_REFERENCE_READ_NODE:
20717 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20719 case PM_GLOBAL_VARIABLE_READ_NODE: {
20720 parser_lex(parser);
20722 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20723 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
20727 case PM_CLASS_VARIABLE_READ_NODE: {
20728 parser_lex(parser);
20730 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20735 case PM_CONSTANT_PATH_NODE: {
20736 parser_lex(parser);
20738 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20741 return parse_shareable_constant_write(parser, write);
20743 case PM_CONSTANT_READ_NODE: {
20744 parser_lex(parser);
20746 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20749 return parse_shareable_constant_write(parser, write);
20751 case PM_INSTANCE_VARIABLE_READ_NODE: {
20752 parser_lex(parser);
20754 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20759 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20761 parser_lex(parser);
20763 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20764 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
20766 pm_node_unreference(parser, node);
20769 case PM_LOCAL_VARIABLE_READ_NODE: {
20770 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
20771 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->
start + PM_NODE_START(node));
20772 pm_node_unreference(parser, node);
20776 parser_lex(parser);
20778 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20779 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20783 case PM_CALL_NODE: {
20789 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20792 parser_lex(parser);
20794 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20795 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20802 parser_lex(parser);
20807 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20808 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20809 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
20813 if (pm_call_node_writable_p(parser, cast)) {
20814 parse_write_name(parser, &cast->
name);
20816 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20819 parse_call_operator_write(parser, cast, &token);
20820 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20821 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
20823 case PM_MULTI_WRITE_NODE: {
20824 parser_lex(parser);
20825 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
20829 parser_lex(parser);
20834 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
20838 case PM_TOKEN_AMPERSAND_EQUAL:
20839 case PM_TOKEN_CARET_EQUAL:
20840 case PM_TOKEN_GREATER_GREATER_EQUAL:
20841 case PM_TOKEN_LESS_LESS_EQUAL:
20842 case PM_TOKEN_MINUS_EQUAL:
20843 case PM_TOKEN_PERCENT_EQUAL:
20844 case PM_TOKEN_PIPE_EQUAL:
20845 case PM_TOKEN_PLUS_EQUAL:
20846 case PM_TOKEN_SLASH_EQUAL:
20847 case PM_TOKEN_STAR_EQUAL:
20848 case PM_TOKEN_STAR_STAR_EQUAL: {
20849 switch (PM_NODE_TYPE(node)) {
20850 case PM_BACK_REFERENCE_READ_NODE:
20851 case PM_NUMBERED_REFERENCE_READ_NODE:
20852 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20854 case PM_GLOBAL_VARIABLE_READ_NODE: {
20855 parser_lex(parser);
20857 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20858 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
20862 case PM_CLASS_VARIABLE_READ_NODE: {
20863 parser_lex(parser);
20865 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20870 case PM_CONSTANT_PATH_NODE: {
20871 parser_lex(parser);
20873 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20876 return parse_shareable_constant_write(parser, write);
20878 case PM_CONSTANT_READ_NODE: {
20879 parser_lex(parser);
20881 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20884 return parse_shareable_constant_write(parser, write);
20886 case PM_INSTANCE_VARIABLE_READ_NODE: {
20887 parser_lex(parser);
20889 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20894 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20896 parser_lex(parser);
20898 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20899 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
20901 pm_node_unreference(parser, node);
20904 case PM_LOCAL_VARIABLE_READ_NODE: {
20905 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
20906 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->
start + PM_NODE_START(node));
20907 pm_node_unreference(parser, node);
20911 parser_lex(parser);
20913 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20914 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20918 case PM_CALL_NODE: {
20919 parser_lex(parser);
20925 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20928 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20929 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20937 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20938 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20939 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
20943 if (pm_call_node_writable_p(parser, cast)) {
20944 parse_write_name(parser, &cast->
name);
20946 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20949 parse_call_operator_write(parser, cast, &token);
20950 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20951 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
20953 case PM_MULTI_WRITE_NODE: {
20954 parser_lex(parser);
20955 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
20959 parser_lex(parser);
20968 case PM_TOKEN_AMPERSAND_AMPERSAND:
20969 case PM_TOKEN_KEYWORD_AND: {
20970 parser_lex(parser);
20972 pm_node_t *right = parse_expression(parser, binding_power, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (parser->
previous.
type == PM_TOKEN_KEYWORD_AND ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0), PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20973 return UP(pm_and_node_create(parser, node, &token, right));
20975 case PM_TOKEN_KEYWORD_OR:
20976 case PM_TOKEN_PIPE_PIPE: {
20977 parser_lex(parser);
20979 pm_node_t *right = parse_expression(parser, binding_power, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (parser->
previous.
type == PM_TOKEN_KEYWORD_OR ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0), PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20980 return UP(pm_or_node_create(parser, node, &token, right));
20982 case PM_TOKEN_EQUAL_TILDE: {
20990 parser_lex(parser);
20991 pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20994 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21000 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21007 bool interpolated =
false;
21008 size_t total_length = 0;
21012 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21015 interpolated =
true;
21020 if (!interpolated && total_length > 0) {
21021 void *memory =
xmalloc(total_length);
21022 if (!memory) abort();
21024 uint8_t *cursor = memory;
21034 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21036 result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21039 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21050 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
21052 if (name_data.
match != NULL) {
21053 result = UP(name_data.
match);
21059 case PM_TOKEN_UAMPERSAND:
21060 case PM_TOKEN_USTAR:
21061 case PM_TOKEN_USTAR_STAR:
21064 case PM_TOKEN_BANG_EQUAL:
21065 case PM_TOKEN_BANG_TILDE:
21066 case PM_TOKEN_EQUAL_EQUAL:
21067 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21068 case PM_TOKEN_LESS_EQUAL_GREATER:
21069 case PM_TOKEN_CARET:
21070 case PM_TOKEN_PIPE:
21071 case PM_TOKEN_AMPERSAND:
21072 case PM_TOKEN_GREATER_GREATER:
21073 case PM_TOKEN_LESS_LESS:
21074 case PM_TOKEN_MINUS:
21075 case PM_TOKEN_PLUS:
21076 case PM_TOKEN_PERCENT:
21077 case PM_TOKEN_SLASH:
21078 case PM_TOKEN_STAR:
21079 case PM_TOKEN_STAR_STAR: {
21080 parser_lex(parser);
21082 switch (PM_NODE_TYPE(node)) {
21083 case PM_RESCUE_MODIFIER_NODE: {
21086 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21090 case PM_AND_NODE: {
21092 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21093 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21099 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21100 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21108 pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21109 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21111 case PM_TOKEN_GREATER:
21112 case PM_TOKEN_GREATER_EQUAL:
21113 case PM_TOKEN_LESS:
21114 case PM_TOKEN_LESS_EQUAL: {
21115 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21116 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21119 parser_lex(parser);
21120 pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21121 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21123 case PM_TOKEN_AMPERSAND_DOT:
21124 case PM_TOKEN_DOT: {
21125 parser_lex(parser);
21130 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21131 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21132 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21135 switch (PM_NODE_TYPE(node)) {
21136 case PM_RESCUE_MODIFIER_NODE: {
21139 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21143 case PM_AND_NODE: {
21145 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21146 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21152 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21153 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21163 switch (parser->
current.type) {
21164 case PM_CASE_OPERATOR:
21165 case PM_CASE_KEYWORD:
21166 case PM_TOKEN_CONSTANT:
21167 case PM_TOKEN_IDENTIFIER:
21168 case PM_TOKEN_METHOD_NAME: {
21169 parser_lex(parser);
21179 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21180 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21183 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21186 match1(parser, PM_TOKEN_COMMA)
21188 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21193 case PM_TOKEN_DOT_DOT:
21194 case PM_TOKEN_DOT_DOT_DOT: {
21195 parser_lex(parser);
21198 if (token_begins_expression_p(parser->
current.type)) {
21199 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21202 return UP(pm_range_node_create(parser, node, &token, right));
21204 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21206 parser_lex(parser);
21208 pm_node_t *predicate = parse_value_expression(parser, binding_power, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21209 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21211 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21213 parser_lex(parser);
21215 pm_node_t *predicate = parse_value_expression(parser, binding_power, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21216 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21218 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21219 parser_lex(parser);
21221 pm_statements_node_body_append(parser, statements, node,
true);
21223 pm_node_t *predicate = parse_value_expression(parser, binding_power, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21224 return UP(pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0));
21226 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21227 parser_lex(parser);
21229 pm_statements_node_body_append(parser, statements, node,
true);
21231 pm_node_t *predicate = parse_value_expression(parser, binding_power, (flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21232 return UP(pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0));
21234 case PM_TOKEN_QUESTION_MARK: {
21237 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21240 parser_lex(parser);
21242 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21252 pm_node_t *false_expression = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
21254 context_pop(parser);
21255 pop_block_exits(parser, previous_block_exits);
21256 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21259 accept1(parser, PM_TOKEN_NEWLINE);
21260 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21263 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21265 context_pop(parser);
21266 pop_block_exits(parser, previous_block_exits);
21267 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21269 case PM_TOKEN_COLON_COLON: {
21270 parser_lex(parser);
21273 switch (parser->
current.type) {
21274 case PM_TOKEN_CONSTANT: {
21275 parser_lex(parser);
21279 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21280 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21291 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21292 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21295 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21299 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21300 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21305 case PM_CASE_OPERATOR:
21306 case PM_CASE_KEYWORD:
21307 case PM_TOKEN_IDENTIFIER:
21308 case PM_TOKEN_METHOD_NAME: {
21309 parser_lex(parser);
21315 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21316 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21319 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21320 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21325 case PM_TOKEN_PARENTHESIS_LEFT: {
21329 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21331 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21334 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21335 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21339 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21341 parser_lex(parser);
21342 accept1(parser, PM_TOKEN_NEWLINE);
21344 pm_node_t *value = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21345 context_pop(parser);
21347 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21349 case PM_TOKEN_BRACKET_LEFT: {
21350 parser_lex(parser);
21355 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21356 pm_accepts_block_stack_push(parser,
true);
21357 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
21358 pm_accepts_block_stack_pop(parser);
21359 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21366 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21367 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21368 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21375 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21376 block = parse_block(parser, (uint16_t) (depth + 1));
21377 pm_arguments_validate_block(parser, &arguments, block);
21378 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21379 block = parse_block(parser, (uint16_t) (depth + 1));
21382 if (block != NULL) {
21383 if (arguments.
block != NULL) {
21384 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21386 arguments.
arguments = pm_arguments_node_create(parser);
21391 arguments.
block = UP(block);
21394 return UP(pm_call_node_aref_create(parser, node, &arguments));
21396 case PM_TOKEN_KEYWORD_IN: {
21402 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21403 parser_lex(parser);
21406 pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_IN, (uint16_t) (depth + 1));
21410 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21412 case PM_TOKEN_EQUAL_GREATER: {
21418 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21419 parser_lex(parser);
21422 pm_node_t *pattern = parse_pattern(parser, &captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_HROCKET, (uint16_t) (depth + 1));
21426 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21429 assert(
false &&
"unreachable");
21434#undef PM_PARSE_PATTERN_SINGLE
21435#undef PM_PARSE_PATTERN_TOP
21436#undef PM_PARSE_PATTERN_MULTI
21452 pm_binding_power_t left = pm_binding_powers[parser->
current.type].
left;
21454 switch (PM_NODE_TYPE(node)) {
21455 case PM_MULTI_WRITE_NODE:
21456 case PM_RETURN_NODE:
21457 case PM_BREAK_NODE:
21459 return left > PM_BINDING_POWER_MODIFIER;
21460 case PM_CLASS_VARIABLE_WRITE_NODE:
21461 case PM_CONSTANT_PATH_WRITE_NODE:
21462 case PM_CONSTANT_WRITE_NODE:
21463 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21464 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21465 case PM_LOCAL_VARIABLE_WRITE_NODE:
21466 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
21467 case PM_CALL_NODE: {
21470 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
21471 return left > PM_BINDING_POWER_MODIFIER;
21477 if (pm_command_call_value_p(node)) {
21478 return left > PM_BINDING_POWER_COMPOSITION;
21484 if (pm_block_call_p(node)) {
21485 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL;
21490 case PM_SUPER_NODE:
21491 case PM_YIELD_NODE:
21494 if (pm_command_call_value_p(node)) {
21495 return left > PM_BINDING_POWER_COMPOSITION;
21502 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(node);
21503 case PM_RESCUE_MODIFIER_NODE:
21507 if (left > PM_BINDING_POWER_MODIFIER) {
21510 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
21529 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21530 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
21533 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
21538 switch (PM_NODE_TYPE(node)) {
21539 case PM_MISSING_NODE:
21541 case PM_PRE_EXECUTION_NODE:
21543 case PM_POST_EXECUTION_NODE:
21544 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
21545 case PM_ALIAS_METHOD_NODE:
21546 case PM_UNDEF_NODE:
21547 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21552 case PM_SUPER_NODE:
21553 case PM_YIELD_NODE:
21555 if (parse_expression_terminator(parser, node)) {
21559 case PM_SYMBOL_NODE:
21560 if (pm_symbol_node_label_p(parser, node)) {
21571 pm_token_type_t current_token_type;
21574 current_token_type = parser->
current.type,
21575 current_binding_powers = pm_binding_powers[current_token_type],
21576 binding_power <= current_binding_powers.
left &&
21577 current_binding_powers.
binary
21579 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
21580 if (parse_expression_terminator(parser, node))
return node;
21584 if (current_binding_powers.
nonassoc) {
21587 if (match1(parser, current_token_type)) {
21599 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
21600 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
21605 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21608 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21613 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
21622 switch (node->
type) {
21623 case PM_CALL_NODE: {
21637 cast->
block == NULL &&
21647 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
21650 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
21655 case PM_CONSTANT_PATH_NODE:
21658 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
21666 !next_binding_powers.
binary ||
21667 binding_power > next_binding_powers.
left ||
21668 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
21684 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21685 if (statements == NULL) {
21686 statements = pm_statements_node_create(parser);
21690 pm_arguments_node_arguments_append(
21693 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
21696 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
21699 pm_parser_constant_id_constant(parser,
"print", 5)
21703 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21704 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21705 if (statements == NULL) {
21706 statements = pm_statements_node_create(parser);
21710 pm_arguments_node_arguments_append(
21713 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
21716 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21717 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
21721 pm_parser_constant_id_constant(parser,
"$F", 2),
21725 pm_statements_node_body_prepend(parser->
arena, statements, UP(write));
21729 pm_arguments_node_arguments_append(
21732 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
21735 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21737 pm_keyword_hash_node_elements_append(parser->
arena, keywords, UP(pm_assoc_node_create(
21739 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
21741 UP(pm_true_node_synthesized_create(parser))
21744 pm_arguments_node_arguments_append(parser->
arena, arguments, UP(keywords));
21745 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
21749 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
21751 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
21755 statements = wrapped_statements;
21770 pm_parser_scope_push(parser,
true);
21774 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21776 parser_lex(parser);
21783 assert(statements->
body.
size > 0);
21784 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
21789 pm_parser_scope_pop(parser);
21794 statements = wrap_statements(parser, statements);
21796 flush_block_exits(parser, previous_block_exits);
21802 if (statements == NULL) {
21803 statements = pm_statements_node_create(parser);
21807 return UP(pm_program_node_create(parser, &locals, statements));
21824pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
21825 size_t little_length = strlen(little);
21827 for (
const char *max = big + big_length - little_length; big <= max; big++) {
21828 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
21835#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
21843pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
21844 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
21845 pm_parser_warn(parser, U32(start - parser->
start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
21856 const char *switches = pm_strnstr(engine,
" -", length);
21857 if (switches == NULL)
return;
21862 (
const uint8_t *) (switches + 1),
21863 length - ((
size_t) (switches - engine)) - 1,
21867 size_t encoding_length;
21870 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
21882 assert(arena != NULL);
21883 assert(source != NULL);
21888 .lex_state = PM_LEX_STATE_BEG,
21889 .enclosure_nesting = 0,
21890 .lambda_enclosure_nesting = -1,
21891 .brace_nesting = 0,
21892 .do_loop_stack = 0,
21893 .accepts_block_stack = 0,
21896 .stack = {{ .mode = PM_LEX_DEFAULT }},
21900 .end = source + size,
21901 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
21902 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
21903 .next_start = NULL,
21904 .heredoc_end = NULL,
21906 .comment_list = { 0 },
21907 .magic_comment_list = { 0 },
21908 .warning_list = { 0 },
21909 .error_list = { 0 },
21910 .current_scope = NULL,
21911 .current_context = NULL,
21913 .encoding_changed_callback = NULL,
21914 .encoding_comment_start = source,
21915 .lex_callback = NULL,
21917 .constant_pool = { 0 },
21918 .line_offsets = { 0 },
21922 .explicit_encoding = NULL,
21924 .parsing_eval =
false,
21925 .partial_script =
false,
21926 .command_start =
true,
21927 .recovering =
false,
21928 .continuable =
true,
21929 .encoding_locked =
false,
21930 .encoding_changed =
false,
21931 .pattern_matching_newlines =
false,
21932 .in_keyword_arg =
false,
21933 .current_block_exits = NULL,
21934 .semantic_token_seen =
false,
21936 .warn_mismatched_indentation =
true
21953 uint32_t constant_size = ((uint32_t) size) / 95;
21954 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
21959 size_t newline_size = size / 22;
21960 pm_line_offset_list_init(&parser->
line_offsets, newline_size < 4 ? 4 : newline_size);
21963 if (options != NULL) {
21972 if (encoding_length > 0) {
21974 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
21996 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
21998 pm_parser_scope_push(parser, scope_index == 0);
22004 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22010 void *allocated =
xmalloc(length);
22011 if (allocated == NULL)
continue;
22013 memcpy(allocated, source, length);
22014 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22025 pm_accepts_block_stack_push(parser,
true);
22028 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22041 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22058 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
22059 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
current.end);
22061 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22062 const char *engine;
22064 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22065 if (newline != NULL) {
22069 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22074 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22077 search_shebang =
false;
22079 search_shebang =
true;
22085 if (search_shebang) {
22088 bool found_shebang =
false;
22092 const uint8_t *cursor = parser->
start;
22096 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22098 while (newline != NULL) {
22099 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
22101 cursor = newline + 1;
22102 newline = next_newline(cursor, parser->
end - cursor);
22104 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22105 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22106 const char *engine;
22107 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22108 found_shebang =
true;
22110 if (newline != NULL) {
22111 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22116 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22124 if (found_shebang) {
22126 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22128 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
22155 for (node = list->
head; node != NULL; node = next) {
22167pm_magic_comment_list_free(
pm_list_t *list) {
22170 for (node = list->
head; node != NULL; node = next) {
22184 pm_diagnostic_list_free(&parser->
error_list);
22196 pm_parser_scope_pop(parser);
22200 lex_mode_pop(parser);
22212 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
22213 case PM_ERR_BEGIN_UPCASE_BRACE:
22214 case PM_ERR_CLASS_VARIABLE_BARE:
22215 case PM_ERR_END_UPCASE_BRACE:
22216 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
22217 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
22218 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
22219 case PM_ERR_EXPRESSION_NOT_WRITABLE:
22220 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
22221 case PM_ERR_FLOAT_PARSE:
22222 case PM_ERR_GLOBAL_VARIABLE_BARE:
22223 case PM_ERR_HASH_KEY:
22224 case PM_ERR_HEREDOC_IDENTIFIER:
22225 case PM_ERR_INSTANCE_VARIABLE_BARE:
22226 case PM_ERR_INVALID_BLOCK_EXIT:
22227 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
22228 case PM_ERR_INVALID_FLOAT_EXPONENT:
22229 case PM_ERR_INVALID_NUMBER_BINARY:
22230 case PM_ERR_INVALID_NUMBER_DECIMAL:
22231 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
22232 case PM_ERR_INVALID_NUMBER_OCTAL:
22233 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
22234 case PM_ERR_NO_LOCAL_VARIABLE:
22235 case PM_ERR_PARAMETER_ORDER:
22236 case PM_ERR_STATEMENT_UNDEF:
22237 case PM_ERR_VOID_EXPRESSION:
22287 size_t source_length = (size_t) (parser->
end - parser->
start);
22290 bool has_non_stray_error =
false;
22292 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE && error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT && !pm_parse_err_is_fatal(error->diag_id)) {
22293 has_non_stray_error =
true;
22301 size_t non_stray_min_start = SIZE_MAX;
22304 size_t error_start = (size_t) error->location.start;
22305 size_t error_end = error_start + (size_t) error->location.length;
22306 bool at_eof = error_end >= source_length;
22309 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
22315 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
22316 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
22317 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
22326 if (non_stray_min_start < error_start)
continue;
22333 if (at_eof && error_start > 0) {
22335 if (error->location.length == 1) {
22336 const uint8_t *
byte = parser->
start + error_start;
22337 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
22348 if (has_non_stray_error)
continue;
22355 if (error->location.length == 1) {
22356 const uint8_t *
byte = parser->
start + error_start;
22357 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
22371 pm_node_t *node = parse_program(parser);
22372 pm_parse_continuable(parser);
22383#define LINE_SIZE 4096
22384 char line[LINE_SIZE];
22386 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22387 size_t length = LINE_SIZE;
22388 while (length > 0 && line[length - 1] ==
'\n') length--;
22390 if (length == LINE_SIZE) {
22395 pm_buffer_append_string(buffer, line, length);
22401 pm_buffer_append_string(buffer, line, length);
22409 if (strncmp(line,
"__END__", 7) == 0)
return false;
22412 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22415 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22421 if (stream_feof(stream)) {
22440 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22446 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22449 pm_arena_free(arena);
22461pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22463 pm_options_read(&options, data);
22473 pm_arena_free(&arena);
22479#undef PM_CASE_KEYWORD
22480#undef PM_CASE_OPERATOR
22481#undef PM_CASE_WRITABLE
22482#undef PM_STRING_EMPTY
22487#ifndef PRISM_EXCLUDE_SERIALIZATION
22491 pm_buffer_append_string(buffer,
"PRISM", 5);
22495 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22503 pm_serialize_header(buffer);
22505 pm_buffer_append_byte(buffer,
'\0');
22513pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22515 pm_options_read(&options, data);
22523 pm_serialize_header(buffer);
22525 pm_buffer_append_byte(buffer,
'\0');
22528 pm_arena_free(&arena);
22541 pm_options_read(&options, data);
22545 pm_serialize_header(buffer);
22547 pm_buffer_append_byte(buffer,
'\0');
22551 pm_arena_free(&arena);
22559pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22561 pm_options_read(&options, data);
22568 pm_serialize_header(buffer);
22570 pm_buffer_append_varsint(buffer, parser.
start_line);
22574 pm_arena_free(&arena);
22587 PM_SLICE_TYPE_ERROR = -1,
22590 PM_SLICE_TYPE_NONE,
22593 PM_SLICE_TYPE_LOCAL,
22596 PM_SLICE_TYPE_CONSTANT,
22599 PM_SLICE_TYPE_METHOD_NAME
22606pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22608 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22609 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22612 if (length == 0)
return PM_SLICE_TYPE_NONE;
22615 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22617 }
else if (*source ==
'_') {
22620 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22624 return PM_SLICE_TYPE_NONE;
22628 const uint8_t *end = source + length;
22629 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22635 while (source < end) {
22636 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22639 }
else if (*source ==
'_') {
22642 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22652 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22654 result = PM_SLICE_TYPE_METHOD_NAME;
22658 return source == end ? result : PM_SLICE_TYPE_NONE;
22665pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22666 switch (pm_slice_type(source, length, encoding_name)) {
22667 case PM_SLICE_TYPE_ERROR:
22669 case PM_SLICE_TYPE_NONE:
22670 case PM_SLICE_TYPE_CONSTANT:
22671 case PM_SLICE_TYPE_METHOD_NAME:
22673 case PM_SLICE_TYPE_LOCAL:
22677 assert(
false &&
"unreachable");
22685pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22686 switch (pm_slice_type(source, length, encoding_name)) {
22687 case PM_SLICE_TYPE_ERROR:
22689 case PM_SLICE_TYPE_NONE:
22690 case PM_SLICE_TYPE_LOCAL:
22691 case PM_SLICE_TYPE_METHOD_NAME:
22693 case PM_SLICE_TYPE_CONSTANT:
22697 assert(
false &&
"unreachable");
22705pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22706#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22707#define C1(c) (*source == c)
22708#define C2(s) (memcmp(source, s, 2) == 0)
22709#define C3(s) (memcmp(source, s, 3) == 0)
22711 switch (pm_slice_type(source, length, encoding_name)) {
22712 case PM_SLICE_TYPE_ERROR:
22714 case PM_SLICE_TYPE_NONE:
22716 case PM_SLICE_TYPE_LOCAL:
22718 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22719 case PM_SLICE_TYPE_CONSTANT:
22721 case PM_SLICE_TYPE_METHOD_NAME:
22728 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22730 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22732 return B(C3(
"===") || C3(
"<=>") || C3(
"[]="));
pm_diagnostic_id_t
The diagnostic IDs of all of the diagnostics, used to communicate the types of errors between the par...
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
int len
Length of the buffer.
VALUE type(ANYARGS)
ANYARGS-ed function type.
PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options)
Free the internal memory associated with the options.
PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index)
Return a pointer to the local at the given index within the given scope.
PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope_get(const pm_options_t *options, size_t index)
Return a pointer to the scope at the given index within the given options.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
String literals may be frozen or mutable depending on the implementation default.
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
@ PM_OPTIONS_VERSION_LATEST
The current version of prism.
@ PM_OPTIONS_VERSION_CRUBY_4_1
The vendored version of prism in CRuby 4.1.x.
@ PM_OPTIONS_VERSION_UNSET
If an explicit version is not provided, the current version of prism will be used.
@ PM_OPTIONS_VERSION_CRUBY_3_4
The vendored version of prism in CRuby 3.4.x.
@ PM_OPTIONS_VERSION_CRUBY_4_0
The vendored version of prism in CRuby 4.0.x.
pm_heredoc_indent_t
The type of indentation that a heredoc uses.
struct pm_context_node pm_context_node_t
This is a node in a linked list of contexts.
#define PM_LEX_STACK_SIZE
We pre-allocate a certain number of lex states in order to avoid having to call malloc too many times...
struct pm_parser pm_parser_t
The parser used to parse Ruby source.
struct pm_comment pm_comment_t
This is a node in the linked list of comments that we've found while parsing.
pm_lex_state_t
This enum combines the various bits from the above enum into individual values that represent the var...
struct pm_scope pm_scope_t
This struct represents a node in a linked list of scopes.
pm_heredoc_quote_t
The type of quote that a heredoc uses.
void(* pm_encoding_changed_callback_t)(pm_parser_t *parser)
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
pm_context_t
While parsing, we keep track of a stack of contexts.
@ PM_CONTEXT_CLASS_RESCUE
a rescue statement within a class statement
@ PM_CONTEXT_ELSIF
an elsif clause
@ PM_CONTEXT_DEF_RESCUE
a rescue statement within a method definition
@ PM_CONTEXT_ELSE
an else clause
@ PM_CONTEXT_FOR_INDEX
a for loop's index
@ PM_CONTEXT_CASE_WHEN
a case when statements
@ PM_CONTEXT_BLOCK_RESCUE
a rescue statement within a do..end block
@ PM_CONTEXT_MODULE
a module declaration
@ PM_CONTEXT_DEF_PARAMS
a method definition's parameters
@ PM_CONTEXT_CASE_IN
a case in statements
@ PM_CONTEXT_BLOCK_ELSE
a rescue else statement within a do..end block
@ PM_CONTEXT_LOOP_PREDICATE
the predicate clause of a loop statement
@ PM_CONTEXT_SCLASS
a singleton class definition
@ PM_CONTEXT_UNLESS
an unless statement
@ PM_CONTEXT_POSTEXE
an END block
@ PM_CONTEXT_IF
an if statement
@ PM_CONTEXT_MULTI_TARGET
a multiple target expression
@ PM_CONTEXT_LAMBDA_RESCUE
a rescue statement within a lambda expression
@ PM_CONTEXT_BEGIN_ELSE
a rescue else statement with an explicit begin
@ PM_CONTEXT_NONE
a null context, used for returning a value from a function
@ PM_CONTEXT_CLASS_ELSE
a rescue else statement within a class statement
@ PM_CONTEXT_LAMBDA_ENSURE
an ensure statement within a lambda expression
@ PM_CONTEXT_BLOCK_ENSURE
an ensure statement within a do..end block
@ PM_CONTEXT_CLASS_ENSURE
an ensure statement within a class statement
@ PM_CONTEXT_LAMBDA_BRACES
a lambda expression with braces
@ PM_CONTEXT_MODULE_ELSE
a rescue else statement within a module statement
@ PM_CONTEXT_PARENS
a parenthesized expression
@ PM_CONTEXT_BLOCK_BRACES
expressions in block arguments using braces
@ PM_CONTEXT_BLOCK_PARAMETERS
expressions in block parameters foo do |...| end
@ PM_CONTEXT_DEF_ENSURE
an ensure statement within a method definition
@ PM_CONTEXT_SCLASS_RESCUE
a rescue statement with a singleton class
@ PM_CONTEXT_PREEXE
a BEGIN block
@ PM_CONTEXT_DEFINED
a defined? expression
@ PM_CONTEXT_MODULE_ENSURE
an ensure statement within a module statement
@ PM_CONTEXT_BEGIN_RESCUE
a rescue statement with an explicit begin
@ PM_CONTEXT_UNTIL
an until statement
@ PM_CONTEXT_DEF_ELSE
a rescue else statement within a method definition
@ PM_CONTEXT_FOR
a for loop
@ PM_CONTEXT_PREDICATE
a predicate inside an if/elsif/unless statement
@ PM_CONTEXT_BEGIN_ENSURE
an ensure statement with an explicit begin
@ PM_CONTEXT_SCLASS_ENSURE
an ensure statement with a singleton class
@ PM_CONTEXT_DEFAULT_PARAMS
a method definition's default parameter
@ PM_CONTEXT_LAMBDA_ELSE
a rescue else statement within a lambda expression
@ PM_CONTEXT_CLASS
a class declaration
@ PM_CONTEXT_MAIN
the top level context
@ PM_CONTEXT_LAMBDA_DO_END
a lambda expression with do..end
@ PM_CONTEXT_BEGIN
a begin statement
@ PM_CONTEXT_RESCUE_MODIFIER
a modifier rescue clause
@ PM_CONTEXT_EMBEXPR
an interpolated expression
@ PM_CONTEXT_TERNARY
a ternary expression
@ PM_CONTEXT_DEF
a method definition
@ PM_CONTEXT_SCLASS_ELSE
a rescue else statement with a singleton class
@ PM_CONTEXT_MODULE_RESCUE
a rescue statement within a module statement
@ PM_CONTEXT_BLOCK_KEYWORDS
expressions in block arguments using do..end
@ PM_CONTEXT_WHILE
a while statement
uint8_t pm_scope_parameters_t
The flags about scope parameters that can be set.
uint8_t pm_shareable_constant_value_t
The type of shareable constant value that can be set.
pm_comment_type_t
This is the type of a comment that we've found while parsing.
void pm_buffer_free(pm_buffer_t *buffer)
Free the memory associated with the buffer.
bool pm_buffer_init(pm_buffer_t *buffer)
Initialize a pm_buffer_t with its default values.
size_t pm_buffer_length(const pm_buffer_t *buffer)
Return the length of the buffer.
char * pm_buffer_value(const pm_buffer_t *buffer)
Return the value of the buffer.
#define PM_CONSTANT_ID_UNSET
When we allocate constants into the pool, we reserve 0 to mean that the slot is not yet filled.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string)
Returns the length associated with the string.
PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string)
Returns the start pointer associated with the string.
PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string)
Free the associated memory of the given string.
#define PM_STRING_EMPTY
Defines an empty string.
#define PRISM_ALIGNOF
Get the alignment requirement of a type.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_DEPTH_MAXIMUM
When we are parsing using recursive descent, we want to protect against malicious payloads that could...
#define PM_STATIC_ASSERT(line, condition, message)
We want to be able to use static assertions, but they weren't standardized until C11.
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
#define PM_ENCODING_US_ASCII_ENTRY
This is the US-ASCII encoding.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PRISM_ENCODING_ALPHABETIC_BIT
All of the lookup tables use the first bit of each embedded byte to indicate whether the codepoint is...
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser)
Parse the Ruby source associated with the given parser and return the tree.
PRISM_EXPORTED_FUNCTION void pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback)
Register a callback that will be called whenever prism changes the encoding it is using to parse base...
PRISM_EXPORTED_FUNCTION void pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options)
Initialize a parser with the given start and end pointers.
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser)
Free any memory associated with the given parser.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_arena_t *arena, pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const pm_options_t *options)
Parse a stream of Ruby source and return the tree.
The main header file for the prism parser.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the encoding, metadata, nodes, and constant pool.
char *() pm_parse_stream_fgets_t(char *string, int size, void *stream)
This function is used in pm_parse_stream() to retrieve a line of input from a stream.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
void pm_serialize_comment_list(pm_list_t *list, pm_buffer_t *buffer)
Serialize the given list of comments to the given buffer.
int() pm_parse_stream_feof_t(void *stream)
This function is used in pm_parse_stream to check whether a stream is EOF.
const char * pm_token_type_human(pm_token_type_t token_type)
Returns the human name of the given token type.
PM_NODE_ALIGNAS struct pm_node * left
AndNode::left.
PM_NODE_ALIGNAS struct pm_node * right
AndNode::right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode::arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode::elements.
PM_NODE_ALIGNAS struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
PM_NODE_ALIGNAS struct pm_node * value
AssocNode::value.
PM_NODE_ALIGNAS struct pm_node * key
AssocNode::key.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
BeginNode::else_clause.
PM_NODE_ALIGNAS struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
PM_NODE_ALIGNAS struct pm_statements_node * statements
BeginNode::statements.
PM_NODE_ALIGNAS struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
pm_node_t base
The embedded base node.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
size_t length
The length of the buffer in bytes.
char * value
A pointer to the start of the buffer.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
pm_constant_id_t name
CallNode::name.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
CallNode::arguments.
pm_location_t equal_loc
CallNode::equal_loc.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
PM_NODE_ALIGNAS struct pm_node * block
CallNode::block.
PM_NODE_ALIGNAS struct pm_node * receiver
CallNode::receiver.
struct pm_node_list conditions
CaseMatchNode::conditions.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
CaseMatchNode::else_clause.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
CaseNode::else_clause.
struct pm_node_list conditions
CaseNode::conditions.
size_t size
The number of constant ids in the list.
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
This is a node in a linked list of contexts.
pm_context_t context
The context that this node represents.
struct pm_context_node * prev
A pointer to the previous context in the linked list.
pm_location_t equal_loc
DefNode::equal_loc.
PM_NODE_ALIGNAS struct pm_node * body
DefNode::body.
This struct represents a diagnostic generated during parsing.
PM_NODE_ALIGNAS struct pm_statements_node * statements
ElseNode::statements.
This struct defines the functions necessary to implement the encoding interface so we can determine h...
size_t(* alpha_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphab...
size_t(* char_width)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding.
bool(* isupper_char)(const uint8_t *b, ptrdiff_t n)
Return true if the next character is valid in the encoding and is an uppercase character.
const char * name
The name of the encoding.
size_t(* alnum_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphan...
PM_NODE_ALIGNAS struct pm_statements_node * statements
EnsureNode::statements.
pm_location_t opening_loc
FindPatternNode::opening_loc.
PM_NODE_ALIGNAS struct pm_node * constant
FindPatternNode::constant.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
GlobalVariableTargetNode.
struct pm_node_list elements
HashNode::elements.
PM_NODE_ALIGNAS struct pm_node * constant
HashPatternNode::constant.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_location_t closing_loc
HashPatternNode::closing_loc.
All of the information necessary to store to lexing a heredoc.
size_t ident_length
The length of the heredoc identifier.
pm_heredoc_quote_t quote
The type of quote that the heredoc uses.
pm_heredoc_indent_t indent
The type of indentation that the heredoc uses.
const uint8_t * ident_start
A pointer to the start of the heredoc identifier.
PM_NODE_ALIGNAS struct pm_statements_node * statements
IfNode::statements.
PM_NODE_ALIGNAS struct pm_node * subsequent
IfNode::subsequent.
PM_NODE_ALIGNAS struct pm_statements_node * statements
InNode::statements.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
void(* callback)(void *data, pm_parser_t *parser, pm_token_t *token)
This is the callback that is called when a token is lexed.
void * data
This opaque pointer is used to provide whatever information the user deemed necessary to the callback...
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
uint8_t terminator
This is the terminator of the list literal.
size_t nesting
This keeps track of the nesting level of the list.
bool interpolation
Whether or not interpolation is allowed in this list.
uint8_t incrementor
When lexing a list, it takes into account balancing the terminator if the terminator is one of (),...
enum pm_lex_mode::@98 mode
The type of this lex mode.
uint8_t breakpoints[11]
This is the character set that should be used to delimit the tokens within the list.
pm_heredoc_lex_mode_t base
All of the data necessary to lex a heredoc.
bool line_continuation
True if the previous token ended with a line continuation.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
union pm_lex_mode::@99 as
The data associated with this type of lex mode.
size_t * common_whitespace
This is used to track the amount of common whitespace on each line so that we know how much to dedent...
int32_t line
The line number.
uint32_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
This struct represents an abstract linked list that provides common functionality.
struct pm_list_node * next
A pointer to the next node in the list.
This represents the overall linked list.
pm_list_node_t * head
A pointer to the head of the list.
size_t size
The size of the list.
This tracks an individual local variable in a certain lexical context, as well as the number of times...
pm_constant_id_t name
The name of the local variable.
pm_location_t location
The location of the local variable in the source.
uint32_t hash
The hash of the local variable.
uint32_t index
The index of the local variable in the local table.
uint32_t reads
The number of times the local variable is read.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
uint32_t depth
LocalVariableWriteNode::depth.
pm_constant_id_t name
LocalVariableWriteNode::name.
This is a set of local variables in a certain lexical context (method, class, module,...
pm_local_t * locals
The nullable allocated memory for the local variables in the set.
uint32_t capacity
The capacity of the local variables set.
uint32_t size
The number of local variables in the set.
This struct represents a slice in the source code, defined by an offset and a length.
uint32_t start
The offset of the location from the start of the source.
uint32_t length
The length of the location.
struct pm_node_list targets
MatchWriteNode::targets.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_location_t location
This is the location of the node in the source.
A scope of locals surrounding the code that is being parsed.
size_t locals_count
The number of locals in the scope.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
The options that can be passed to the parser.
uint8_t command_line
A bitset of the various options that were set on the command line.
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
bool encoding_locked
Whether or not the encoding magic comments should be respected.
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
pm_string_t encoding
The name of the encoding that the source file is in.
int32_t line
The line within the file that the parse starts on.
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
bool partial_script
When the file being parsed is considered a "partial" script, jumps will not be marked as errors if th...
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
pm_string_t filepath
The name of the file that is currently being parsed.
pm_options_version_t version
The version of prism that we should be parsing with.
PM_NODE_ALIGNAS struct pm_node * right
OrNode::right.
PM_NODE_ALIGNAS struct pm_node * left
OrNode::left.
PM_NODE_ALIGNAS struct pm_node * block
ParametersNode::block.
PM_NODE_ALIGNAS struct pm_node * rest
ParametersNode::rest.
PM_NODE_ALIGNAS struct pm_node * keyword_rest
ParametersNode::keyword_rest.
PM_NODE_ALIGNAS struct pm_node * body
ParenthesesNode::body.
This struct represents the overall parser.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
pm_lex_state_t lex_state
The current state of the lexer.
uint8_t command_line
The command line flags given from the options.
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool partial_script
Whether or not we are parsing a "partial" script, which is a script that will be evaluated in the con...
bool pattern_matching_newlines
This flag indicates that we are currently parsing a pattern matching expression and impacts that calc...
const uint8_t * end
The pointer to the end of the source.
bool recovering
Whether or not we're currently recovering from a syntax error.
pm_node_flags_t integer_base
We want to add a flag to integer nodes that indicates their base.
bool warn_mismatched_indentation
By default, Ruby always warns about mismatched indentation.
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
bool in_keyword_arg
This flag indicates that we are currently parsing a keyword argument.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
pm_token_t previous
The previous token we were considering.
pm_string_t current_string
This string is used to pass information from the lexer to the parser.
bool parsing_eval
Whether or not we are parsing an eval string.
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
pm_location_t data_loc
An optional location that represents the location of the END marker and the rest of the content of th...
pm_context_node_t * current_context
The current parsing context.
const uint8_t * start
The pointer to the start of the source.
int enclosure_nesting
Tracks the current nesting of (), [], and {}.
pm_line_offset_list_t line_offsets
This is the list of line offsets in the source file.
pm_list_t error_list
The list of errors that have been found while parsing.
int8_t frozen_string_literal
Whether or not we have found a frozen_string_literal magic comment with a true or false value.
pm_node_list_t * current_block_exits
When parsing block exits (e.g., break, next, redo), we need to validate that they are in correct cont...
const uint8_t * encoding_comment_start
This pointer indicates where a comment must start if it is to be considered an encoding comment.
bool continuable
Whether or not the source being parsed could become valid if more input were appended.
pm_lex_mode_t stack[PM_LEX_STACK_SIZE]
The stack of lexer modes.
pm_list_t warning_list
The list of warnings that have been found while parsing.
const uint8_t * heredoc_end
This field indicates the end of a heredoc whose identifier was found on the current line.
int brace_nesting
Used to track the nesting of braces to ensure we get the correct value when we are interpolating bloc...
pm_encoding_changed_callback_t encoding_changed_callback
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
struct pm_parser::@104 lex_modes
A stack of lex modes.
int32_t start_line
The line number at the start of the parse.
bool encoding_locked
This is very specialized behavior for when you want to parse in a context that does not respect encod...
pm_lex_mode_t * current
The current mode of the lexer.
pm_arena_t * arena
The arena used for all AST-lifetime allocations.
pm_list_t comment_list
The list of comments that have been found while parsing.
size_t index
The current index into the lexer mode stack.
pm_string_t filepath
This is the path of the file being parsed.
pm_scope_t * current_scope
The current local scope.
bool command_start
Whether or not we're at the beginning of a command.
bool semantic_token_seen
Whether or not the parser has seen a token that has semantic meaning (i.e., a token that is not a com...
PM_NODE_ALIGNAS struct pm_node * right
RangeNode::right.
PM_NODE_ALIGNAS struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
Accumulation state for named capture groups found during regexp parsing.
pm_call_node_t * call
The call node wrapping the regular expression node (for =~).
pm_constant_id_list_t names
The list of capture names found so far (for deduplication).
pm_match_write_node_t * match
The match write node being built, or NULL if no captures found yet.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
PM_NODE_ALIGNAS struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
PM_NODE_ALIGNAS struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
This struct represents a node in a linked list of scopes.
struct pm_scope * previous
A pointer to the previous scope in the linked list.
pm_node_list_t implicit_parameters
This is a list of the implicit parameters contained within the block.
pm_shareable_constant_value_t shareable_constant
The current state of constant shareability for this scope.
pm_locals_t locals
The IDs of the locals in the given scope.
pm_scope_parameters_t parameters
This is a bitfield that indicates the parameters that are being used in this scope.
bool closed
A boolean indicating whether or not this scope can see into its parent.
PM_NODE_ALIGNAS struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
pm_node_t base
The embedded base node.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t content_loc
StringNode::content_loc.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
size_t length
The length of the string in bytes of memory.
enum pm_string_t::@105 type
The type of the string.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
SuperNode::arguments.
pm_location_t lparen_loc
SuperNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_node * block
SuperNode::block.
pm_location_t value_loc
SymbolNode::value_loc.
pm_string_t unescaped
SymbolNode::unescaped.
When we're lexing certain types (strings, symbols, lists, etc.) we have string content associated wit...
pm_buffer_t buffer
The buffer that we're using to keep track of the string content.
const uint8_t * cursor
The cursor into the source string that points to how far we have currently copied into the buffer.
This struct represents a token in the Ruby source.
const uint8_t * end
A pointer to the end location of the token in the source.
const uint8_t * start
A pointer to the start location of the token in the source.
pm_token_type_t type
The type of the token.
PM_NODE_ALIGNAS struct pm_statements_node * statements
UnlessNode::statements.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
UnlessNode::else_clause.
PM_NODE_ALIGNAS struct pm_statements_node * statements
WhenNode::statements.
pm_location_t lparen_loc
YieldNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
YieldNode::arguments.