15#define PM_TAB_WHITESPACE_SIZE 8
18#define MIN(a,b) (((a)<(b))?(a):(b))
19#define MAX(a,b) (((a)>(b))?(a):(b))
25#define U32(value_) ((uint32_t) (value_))
27#define FL PM_NODE_FLAGS
28#define UP PM_NODE_UPCAST
30#define PM_LOCATION_START(location_) ((location_)->start)
31#define PM_LOCATION_END(location_) ((location_)->start + (location_)->length)
33#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
34#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
35#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
36#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
38#define PM_NODE_START(node_) (UP(node_)->location.start)
39#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
40#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
41#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
43#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
44#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
46#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
47#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
48#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
49#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
50#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
52#define PM_LOCATION_INIT(start_, length_) ((pm_location_t) { .start = (start_), .length = (length_) })
53#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
54#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
55#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
57#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
58#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
59#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
60#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
62#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
63#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
64#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
75lex_mode_incrementor(
const uint8_t start) {
92lex_mode_terminator(
const uint8_t start) {
134lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
135 uint8_t incrementor = lex_mode_incrementor(delimiter);
136 uint8_t terminator = lex_mode_terminator(delimiter);
142 .interpolation = interpolation,
143 .incrementor = incrementor,
144 .terminator = terminator
151 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
156 if (terminator !=
'\0') {
157 breakpoints[index++] = terminator;
163 breakpoints[index++] =
'#';
167 if (incrementor !=
'\0') {
168 breakpoints[index++] = incrementor;
172 return lex_mode_push(parser, lex_mode);
182 return lex_mode_push_list(parser,
false,
'\0');
189lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
191 .
mode = PM_LEX_REGEXP,
194 .incrementor = incrementor,
195 .terminator = terminator
203 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
207 if (terminator !=
'\0') {
208 breakpoints[index++] = terminator;
212 if (incrementor !=
'\0') {
213 breakpoints[index++] = incrementor;
217 return lex_mode_push(parser, lex_mode);
224lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
226 .
mode = PM_LEX_STRING,
229 .interpolation = interpolation,
230 .label_allowed = label_allowed,
231 .incrementor = incrementor,
232 .terminator = terminator
239 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
244 if (terminator !=
'\0') {
245 breakpoints[index++] = terminator;
251 breakpoints[index++] =
'#';
256 if (incrementor !=
'\0') {
257 breakpoints[index++] = incrementor;
261 return lex_mode_push(parser, lex_mode);
271 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
303 PM_IGNORED_NEWLINE_NONE = 0,
304 PM_IGNORED_NEWLINE_ALL,
305 PM_IGNORED_NEWLINE_PATTERN
306} pm_ignored_newline_type_t;
308static inline pm_ignored_newline_type_t
310 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);
313 return PM_IGNORED_NEWLINE_ALL;
314 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
315 return PM_IGNORED_NEWLINE_PATTERN;
317 return PM_IGNORED_NEWLINE_NONE;
323 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));
328 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
332lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
336 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
341 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
349 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
361#ifndef PM_DEBUG_LOGGING
366#define PM_DEBUG_LOGGING 0
372 fprintf(stderr,
"STATE: ");
375 if (parser->
lex_state == PM_LEX_STATE_NONE) {
376 fprintf(stderr,
"NONE\n");
380#define CHECK_STATE(state) \
381 if (parser->lex_state & state) { \
382 if (!first) fprintf(stderr, "|"); \
383 fprintf(stderr, "%s", #state); \
387 CHECK_STATE(PM_LEX_STATE_BEG)
388 CHECK_STATE(PM_LEX_STATE_END)
389 CHECK_STATE(PM_LEX_STATE_ENDARG)
390 CHECK_STATE(PM_LEX_STATE_ENDFN)
391 CHECK_STATE(PM_LEX_STATE_ARG)
392 CHECK_STATE(PM_LEX_STATE_CMDARG)
393 CHECK_STATE(PM_LEX_STATE_MID)
394 CHECK_STATE(PM_LEX_STATE_FNAME)
395 CHECK_STATE(PM_LEX_STATE_DOT)
396 CHECK_STATE(PM_LEX_STATE_CLASS)
397 CHECK_STATE(PM_LEX_STATE_LABEL)
398 CHECK_STATE(PM_LEX_STATE_LABELED)
399 CHECK_STATE(PM_LEX_STATE_FITEM)
403 fprintf(stderr,
"\n");
408 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
410 lex_state_set(parser, state);
411 fprintf(stderr,
"Now: ");
413 fprintf(stderr,
"\n");
416#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
424#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
427#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
430#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
433#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
436#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
439#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
442#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
453 pm_diagnostic_list_append(&parser->
error_list, start, length, diag_id);
462 pm_parser_err(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
471 pm_parser_err_token(parser, &parser->
current, diag_id);
480 pm_parser_err_token(parser, &parser->
previous, diag_id);
489 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
495#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
496 pm_diagnostic_list_append_format(&(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
502#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
503 PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
509#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
510 PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
516#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
517 PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id, __VA_ARGS__)
523#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
524 PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
531 pm_diagnostic_list_append(&parser->
warning_list, start, length, diag_id);
540 pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
549 pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
556#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
557 pm_diagnostic_list_append_format(&(parser_)->warning_list, start_, length_, diag_id_, __VA_ARGS__)
563#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
564 PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id_, __VA_ARGS__)
570#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
571 PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
577#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
578 PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
586pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
587 PM_PARSER_ERR_FORMAT(
589 U32(ident_start - parser->
start),
593 (
const char *) ident_start
605pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
607 if (scope == NULL)
return false;
612 .parameters = PM_SCOPE_PARAMETERS_NONE,
613 .implicit_parameters = { 0 },
631 if (scope->
previous == NULL)
return true;
632 if (scope->
closed)
return false;
633 }
while ((scope = scope->
previous) != NULL);
635 assert(
false &&
"unreachable");
643pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
646 while (depth-- > 0) {
647 assert(scope != NULL);
655 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
656 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
657 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
658} pm_scope_forwarding_param_check_result_t;
660static pm_scope_forwarding_param_check_result_t
661pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
663 bool conflict =
false;
665 while (scope != NULL) {
669 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
671 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
682 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
687 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
688 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
691 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
692 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
694 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
695 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
702 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
703 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
706 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
707 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
709 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
710 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
717 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
718 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
721 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
726 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
727 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
734 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
735 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
738 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
739 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
741 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
742 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
751pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
775#define PM_LOCALS_HASH_THRESHOLD 9
790 name = ((name >> 16) ^ name) * 0x45d9f3b;
791 name = ((name >> 16) ^ name) * 0x45d9f3b;
792 name = (name >> 16) ^ name;
802 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
803 assert(next_capacity > locals->
capacity);
806 if (next_locals == NULL) abort();
808 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
809 if (locals->
size > 0) {
815 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
816 uint32_t mask = next_capacity - 1;
818 for (uint32_t index = 0; index < locals->
capacity; index++) {
822 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
824 uint32_t hash = local->
hash;
826 next_locals[hash & mask] = *local;
831 pm_locals_free(locals);
832 locals->
locals = next_locals;
854 pm_locals_resize(locals);
857 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
858 for (uint32_t index = 0; index < locals->
capacity; index++) {
864 .location = { .start = start, .length = length },
865 .index = locals->
size++,
870 }
else if (local->
name == name) {
875 uint32_t mask = locals->
capacity - 1;
876 uint32_t hash = pm_locals_hash(name);
877 uint32_t initial_hash = hash;
885 .location = { .start = start, .length = length },
886 .index = locals->
size++,
891 }
else if (local->
name == name) {
896 }
while ((hash & mask) != initial_hash);
899 assert(
false &&
"unreachable");
909 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
910 for (uint32_t index = 0; index < locals->
size; index++) {
912 if (local->
name == name)
return index;
915 uint32_t mask = locals->
capacity - 1;
916 uint32_t hash = pm_locals_hash(name);
917 uint32_t initial_hash = hash & mask;
924 }
else if (local->
name == name) {
929 }
while ((hash & mask) != initial_hash);
941 uint32_t index = pm_locals_find(locals, name);
942 assert(index != UINT32_MAX);
945 assert(local->
reads < UINT32_MAX);
956 uint32_t index = pm_locals_find(locals, name);
957 assert(index != UINT32_MAX);
960 assert(local->
reads > 0);
970 uint32_t index = pm_locals_find(locals, name);
971 assert(index != UINT32_MAX);
986 pm_constant_id_list_init_capacity(list, locals->
size);
991 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
995 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
997 for (uint32_t index = 0; index < capacity; index++) {
1001 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
1003 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))) {
1004 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
1006 if (constant->
length >= 1 && *constant->
start !=
'_') {
1007 PM_PARSER_WARN_FORMAT(
1011 PM_WARN_UNUSED_LOCAL_VARIABLE,
1013 (
const char *) constant->
start
1029pm_parser_constant_id_raw(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1030 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
1037pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1038 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1045pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1046 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1054 return pm_parser_constant_id_raw(parser, token->start, token->end);
1061#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1062 case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1073 while (node != NULL) {
1074 switch (PM_NODE_TYPE(node)) {
1075 case PM_CASE_VOID_VALUE:
1076 return void_node != NULL ? void_node : node;
1077 case PM_MATCH_PREDICATE_NODE:
1079 case PM_BEGIN_NODE: {
1085 if (vn != NULL)
return vn;
1090 if (vn != NULL)
return vn;
1100 if (vn == NULL)
return NULL;
1101 if (void_node == NULL) void_node = vn;
1105 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1122 pm_node_t *vn = pm_check_value_expression(parser, node);
1123 if (vn != NULL)
return vn;
1134 case PM_CASE_NODE: {
1145 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1149 if (vn == NULL)
return NULL;
1150 if (void_node == NULL) void_node = vn;
1153 node = UP(cast->else_clause);
1156 case PM_CASE_MATCH_NODE: {
1167 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1171 if (vn == NULL)
return NULL;
1172 if (void_node == NULL) void_node = vn;
1175 node = UP(cast->else_clause);
1178 case PM_ENSURE_NODE: {
1183 case PM_PARENTHESES_NODE: {
1185 node = UP(cast->
body);
1188 case PM_STATEMENTS_NODE: {
1195 switch (PM_NODE_TYPE(body_part)) {
1196 case PM_CASE_VOID_VALUE:
1197 if (void_node == NULL) {
1198 void_node = body_part;
1218 if (void_node == NULL) {
1224 case PM_UNLESS_NODE: {
1233 if (void_node == NULL) {
1239 case PM_ELSE_NODE: {
1254 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1258 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1273 pm_node_t *void_node = pm_check_value_expression(parser, node);
1274 if (void_node != NULL) {
1275 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1284 const char *
type = NULL;
1287 switch (PM_NODE_TYPE(node)) {
1288 case PM_BACK_REFERENCE_READ_NODE:
1289 case PM_CLASS_VARIABLE_READ_NODE:
1290 case PM_GLOBAL_VARIABLE_READ_NODE:
1291 case PM_INSTANCE_VARIABLE_READ_NODE:
1292 case PM_LOCAL_VARIABLE_READ_NODE:
1293 case PM_NUMBERED_REFERENCE_READ_NODE:
1294 type =
"a variable";
1297 case PM_CALL_NODE: {
1302 switch (message->
length) {
1304 switch (message->
start[0]) {
1321 switch (message->
start[1]) {
1323 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1329 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1335 if (message->
start[0] ==
'*') {
1343 if (memcmp(message->
start,
"<=>", 3) == 0) {
1352 case PM_CONSTANT_PATH_NODE:
1356 case PM_CONSTANT_READ_NODE:
1357 type =
"a constant";
1360 case PM_DEFINED_NODE:
1369 case PM_IMAGINARY_NODE:
1370 case PM_INTEGER_NODE:
1371 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1372 case PM_INTERPOLATED_STRING_NODE:
1373 case PM_RATIONAL_NODE:
1374 case PM_REGULAR_EXPRESSION_NODE:
1375 case PM_SOURCE_ENCODING_NODE:
1376 case PM_SOURCE_FILE_NODE:
1377 case PM_SOURCE_LINE_NODE:
1378 case PM_STRING_NODE:
1379 case PM_SYMBOL_NODE:
1387 case PM_RANGE_NODE: {
1390 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1413 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1424 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1425 for (
size_t index = 0; index < size; index++) {
1426 pm_void_statement_check(parser, node->
body.
nodes[index]);
1436 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1437 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1438 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1439} pm_conditional_predicate_type_t;
1447 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1448 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1450 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1451 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1453 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1463pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1464 switch (PM_NODE_TYPE(node)) {
1465 case PM_ARRAY_NODE: {
1466 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1469 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1470 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1475 case PM_HASH_NODE: {
1476 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1479 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1481 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1484 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1491 case PM_IMAGINARY_NODE:
1492 case PM_INTEGER_NODE:
1494 case PM_RATIONAL_NODE:
1495 case PM_REGULAR_EXPRESSION_NODE:
1496 case PM_SOURCE_ENCODING_NODE:
1497 case PM_SOURCE_FILE_NODE:
1498 case PM_SOURCE_LINE_NODE:
1499 case PM_STRING_NODE:
1500 case PM_SYMBOL_NODE:
1514 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1533 switch (PM_NODE_TYPE(node)) {
1536 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1537 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1542 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1543 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1546 case PM_PARENTHESES_NODE: {
1549 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1551 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1556 case PM_BEGIN_NODE: {
1564 case PM_RANGE_NODE: {
1567 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1568 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1576 node->
type = PM_FLIP_FLOP_NODE;
1580 case PM_REGULAR_EXPRESSION_NODE:
1585 node->
type = PM_MATCH_LAST_LINE_NODE;
1587 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1588 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1592 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1597 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1599 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1600 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1604 case PM_INTEGER_NODE:
1605 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1606 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1607 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1610 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1613 case PM_STRING_NODE:
1614 case PM_SOURCE_FILE_NODE:
1615 case PM_INTERPOLATED_STRING_NODE:
1616 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1618 case PM_SYMBOL_NODE:
1619 case PM_INTERPOLATED_SYMBOL_NODE:
1620 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1622 case PM_SOURCE_LINE_NODE:
1623 case PM_SOURCE_ENCODING_NODE:
1625 case PM_RATIONAL_NODE:
1626 case PM_IMAGINARY_NODE:
1627 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1629 case PM_CLASS_VARIABLE_WRITE_NODE:
1632 case PM_CONSTANT_WRITE_NODE:
1635 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1638 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1641 case PM_LOCAL_VARIABLE_WRITE_NODE:
1644 case PM_MULTI_WRITE_NODE:
1680 if (arguments->
block != NULL) {
1681 uint32_t end = PM_NODE_END(arguments->
block);
1684 uint32_t arguments_end = PM_LOCATION_END(&arguments->
closing_loc);
1685 if (arguments_end > end) {
1728 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1742char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1743 if (n <= 0)
return 0;
1750 }
else if (*b ==
'_') {
1752 }
else if (*b >= 0x80) {
1757 }
else if (*b < 0x80) {
1760 return pm_encoding_utf_8_char_width(b, n);
1769char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1772 }
else if (*b < 0x80) {
1775 return pm_encoding_utf_8_char_width(b, n);
1785char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1793 }
else if (*b ==
'_') {
1795 }
else if (*b >= 0x80) {
1801 return char_is_identifier_utf8(b, n);
1808#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1809#define PUNCT(idx) ( \
1810 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', 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) | \
1817const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1823char_is_global_name_punctuation(const uint8_t b) {
1824 const unsigned int i = (const unsigned int) b;
1825 if (i <= 0x20 || 0x7e < i) return false;
1827 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1831token_is_setter_name(pm_token_t *token) {
1833 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1834 ((token->type == PM_TOKEN_IDENTIFIER) &&
1835 (token->end - token->start >= 2) &&
1836 (token->end[-1] == '='))
1844pm_local_is_keyword(const char *source, size_t length) {
1845#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1849 switch (source[0]) {
1850 case 'd': KEYWORD("do"); return false;
1851 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1852 case 'o': KEYWORD("or"); return false;
1853 default: return false;
1856 switch (source[0]) {
1857 case 'a': KEYWORD("and"); return false;
1858 case 'd': KEYWORD("def"); return false;
1859 case 'e': KEYWORD("end"); return false;
1860 case 'f': KEYWORD("for"); return false;
1861 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1862 default: return false;
1865 switch (source[0]) {
1866 case 'c': KEYWORD("case"); return false;
1867 case 'e': KEYWORD("else"); return false;
1868 case 'n': KEYWORD("next"); return false;
1869 case 'r': KEYWORD("redo"); return false;
1870 case 's': KEYWORD("self"); return false;
1871 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1872 case 'w': KEYWORD("when"); return false;
1873 default: return false;
1876 switch (source[0]) {
1877 case 'a': KEYWORD("alias"); return false;
1878 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1879 case 'c': KEYWORD("class"); return false;
1880 case 'e': KEYWORD("elsif"); return false;
1881 case 'f': KEYWORD("false"); return false;
1882 case 'r': KEYWORD("retry"); return false;
1883 case 's': KEYWORD("super"); return false;
1884 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1885 case 'w': KEYWORD("while"); return false;
1886 case 'y': KEYWORD("yield"); return false;
1887 default: return false;
1890 switch (source[0]) {
1891 case 'e': KEYWORD("ensure"); return false;
1892 case 'm': KEYWORD("module"); return false;
1893 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1894 case 'u': KEYWORD("unless"); return false;
1895 default: return false;
1898 KEYWORD("__LINE__");
1899 KEYWORD("__FILE__");
1902 KEYWORD("__ENCODING__");
1911/******************************************************************************/
1912/* Node flag handling functions */
1913/******************************************************************************/
1919pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1920 node->flags |= flag;
1927pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1928 node->flags &= (pm_node_flags_t) ~flag;
1935pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1936 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1937 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1938 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1939 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1940 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1941 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1942 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1943 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1945 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1948/******************************************************************************/
1949/* Node creation functions */
1950/******************************************************************************/
1957#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)
1962static inline pm_node_flags_t
1963pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1964 pm_node_flags_t flags = 0;
1966 if (closing->type == PM_TOKEN_REGEXP_END) {
1967 pm_buffer_t unknown_flags = { 0 };
1969 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1971 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1972 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1973 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1974 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1976 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1977 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1978 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1979 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1981 default: pm_buffer_append_byte(&unknown_flags, *flag);
1985 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1986 if (unknown_flags_length != 0) {
1987 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1988 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1990 pm_buffer_free(&unknown_flags);
1996#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1998static pm_statements_node_t *
1999pm_statements_node_create(pm_parser_t *parser);
2002pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
2005pm_statements_node_body_length(pm_statements_node_t *node);
2012pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
2013 void *memory = xcalloc(1, size);
2014 if (memory == NULL) {
2015 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
2021#define PM_NODE_ALLOC(parser_, type_) (type_ *) pm_node_alloc(parser_, sizeof(type_))
2022#define PM_NODE_INIT(parser_, type_, flags_, location_) (pm_node_t) { \
2024 .flags = (flags_), \
2025 .node_id = ++(parser_)->node_id, \
2026 .location = location_ \
2032static pm_missing_node_t *
2033pm_missing_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
2034 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
2036 *node = (pm_missing_node_t) {
2037 .base = PM_NODE_INIT(parser, PM_MISSING_NODE, 0, ((pm_location_t) { .start = start, .length = length }))
2046static pm_alias_global_variable_node_t *
2047pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2048 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2049 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
2051 *node = (pm_alias_global_variable_node_t) {
2052 .base = PM_NODE_INIT(parser, PM_ALIAS_GLOBAL_VARIABLE_NODE, 0, PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name)),
2053 .new_name = new_name,
2054 .old_name = old_name,
2055 .keyword_loc = TOK2LOC(parser, keyword)
2064static pm_alias_method_node_t *
2065pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2066 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2067 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
2069 *node = (pm_alias_method_node_t) {
2070 .base = PM_NODE_INIT(parser, PM_ALIAS_METHOD_NODE, 0, PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name)),
2071 .new_name = new_name,
2072 .old_name = old_name,
2073 .keyword_loc = TOK2LOC(parser, keyword)
2082static pm_alternation_pattern_node_t *
2083pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2084 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2086 *node = (pm_alternation_pattern_node_t) {
2087 .base = PM_NODE_INIT(parser, PM_ALTERNATION_PATTERN_NODE, 0, PM_LOCATION_INIT_NODES(left, right)),
2090 .operator_loc = TOK2LOC(parser, operator)
2099static pm_and_node_t *
2100pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2101 pm_assert_value_expression(parser, left);
2103 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2105 *node = (pm_and_node_t) {
2106 .base = PM_NODE_INIT(parser, PM_AND_NODE, 0, PM_LOCATION_INIT_NODES(left, right)),
2108 .operator_loc = TOK2LOC(parser, operator),
2118static pm_arguments_node_t *
2119pm_arguments_node_create(pm_parser_t *parser) {
2120 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2122 *node = (pm_arguments_node_t) {
2123 .base = PM_NODE_INIT(parser, PM_ARGUMENTS_NODE, 0, PM_LOCATION_INIT_UNSET),
2134pm_arguments_node_size(pm_arguments_node_t *node) {
2135 return node->arguments.size;
2142pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2143 if (pm_arguments_node_size(node) == 0) {
2144 PM_NODE_START_SET_NODE(node, argument);
2147 if (PM_NODE_END(node) < PM_NODE_END(argument)) {
2148 PM_NODE_LENGTH_SET_NODE(node, argument);
2151 pm_node_list_append(&node->arguments, argument);
2153 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2154 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2155 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2157 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2165static pm_array_node_t *
2166pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2167 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2169 if (opening == NULL) {
2170 *node = (pm_array_node_t) {
2171 .base = PM_NODE_INIT(parser, PM_ARRAY_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_UNSET),
2172 .opening_loc = { 0 },
2173 .closing_loc = { 0 },
2177 *node = (pm_array_node_t) {
2178 .base = PM_NODE_INIT(parser, PM_ARRAY_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, opening)),
2179 .opening_loc = TOK2LOC(parser, opening),
2180 .closing_loc = TOK2LOC(parser, opening),
2192pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2193 if (!node->elements.size && !node->opening_loc.length) {
2194 PM_NODE_START_SET_NODE(node, element);
2197 pm_node_list_append(&node->elements, element);
2198 PM_NODE_LENGTH_SET_NODE(node, element);
2200 // If the element is not a static literal, then the array is not a static
2201 // literal. Turn that flag off.
2202 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)) {
2203 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2206 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2207 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2215pm_array_node_close_set(const pm_parser_t *parser, pm_array_node_t *node, const pm_token_t *closing) {
2216 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == 0);
2217 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2218 node->closing_loc = TOK2LOC(parser, closing);
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2227 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2229 *node = (pm_array_pattern_node_t) {
2230 .base = PM_NODE_INIT(parser, PM_ARRAY_PATTERN_NODE, 0, PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1])),
2235 .opening_loc = { 0 },
2236 .closing_loc = { 0 }
2239 // For now we're going to just copy over each pointer manually. This could be
2240 // much more efficient, as we could instead resize the node list.
2241 bool found_rest = false;
2244 PM_NODE_LIST_FOREACH(nodes, index, child) {
2245 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2248 } else if (found_rest) {
2249 pm_node_list_append(&node->posts, child);
2251 pm_node_list_append(&node->requireds, child);
2261static pm_array_pattern_node_t *
2262pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2263 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2265 *node = (pm_array_pattern_node_t) {
2266 .base = PM_NODE_INIT(parser, PM_ARRAY_PATTERN_NODE, 0, PM_LOCATION_INIT_NODE(rest)),
2271 .opening_loc = { 0 },
2272 .closing_loc = { 0 }
2282static pm_array_pattern_node_t *
2283pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2284 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2286 *node = (pm_array_pattern_node_t) {
2287 .base = PM_NODE_INIT(parser, PM_ARRAY_PATTERN_NODE, 0, PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing)),
2288 .constant = constant,
2290 .opening_loc = TOK2LOC(parser, opening),
2291 .closing_loc = TOK2LOC(parser, closing),
2303static pm_array_pattern_node_t *
2304pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2305 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2307 *node = (pm_array_pattern_node_t) {
2308 .base = PM_NODE_INIT(parser, PM_ARRAY_PATTERN_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
2311 .opening_loc = TOK2LOC(parser, opening),
2312 .closing_loc = TOK2LOC(parser, closing),
2321pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2322 pm_node_list_append(&node->requireds, inner);
2328static pm_assoc_node_t *
2329pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2330 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2333 if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
2334 end = PM_NODE_END(value);
2335 } else if (operator != NULL) {
2336 end = PM_TOKEN_END(parser, operator);
2338 end = PM_NODE_END(key);
2341 // Hash string keys will be frozen, so we can mark them as frozen here so
2342 // that the compiler picks them up and also when we check for static literal
2343 // on the keys it gets factored in.
2344 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2345 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2348 // If the key and value of this assoc node are both static literals, then
2349 // we can mark this node as a static literal.
2350 pm_node_flags_t flags = 0;
2352 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2353 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)
2355 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2358 *node = (pm_assoc_node_t) {
2359 .base = PM_NODE_INIT(parser, PM_ASSOC_NODE, flags, ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) })),
2361 .operator_loc = NTOK2LOC(parser, operator),
2371static pm_assoc_splat_node_t *
2372pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2373 assert(operator->type == PM_TOKEN_USTAR_STAR);
2374 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2376 *node = (pm_assoc_splat_node_t) {
2377 .base = PM_NODE_INIT(parser, PM_ASSOC_SPLAT_NODE, 0, (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value)),
2379 .operator_loc = TOK2LOC(parser, operator)
2388static pm_back_reference_read_node_t *
2389pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2390 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2391 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2393 *node = (pm_back_reference_read_node_t) {
2394 .base = PM_NODE_INIT(parser, PM_BACK_REFERENCE_READ_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, name)),
2395 .name = pm_parser_constant_id_token(parser, name)
2404static pm_begin_node_t *
2405pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2406 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2408 uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
2409 uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
2411 *node = (pm_begin_node_t) {
2412 .base = PM_NODE_INIT(parser, PM_BEGIN_NODE, 0, ((pm_location_t) { .start = start, .length = U32(end - start) })),
2413 .begin_keyword_loc = NTOK2LOC(parser, begin_keyword),
2414 .statements = statements,
2415 .end_keyword_loc = { 0 }
2425pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2426 if (node->begin_keyword_loc.length == 0) {
2427 PM_NODE_START_SET_NODE(node, rescue_clause);
2429 PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
2430 node->rescue_clause = rescue_clause;
2437pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2438 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2439 PM_NODE_START_SET_NODE(node, else_clause);
2441 PM_NODE_LENGTH_SET_NODE(node, else_clause);
2442 node->else_clause = else_clause;
2449pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2450 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2451 PM_NODE_START_SET_NODE(node, ensure_clause);
2453 PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
2454 node->ensure_clause = ensure_clause;
2461pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
2462 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
2463 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
2464 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
2470static pm_block_argument_node_t *
2471pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2472 assert(operator->type == PM_TOKEN_UAMPERSAND);
2473 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2475 *node = (pm_block_argument_node_t) {
2476 .base = PM_NODE_INIT(parser, PM_BLOCK_ARGUMENT_NODE, 0, (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression)),
2477 .expression = expression,
2478 .operator_loc = TOK2LOC(parser, operator)
2487static pm_block_node_t *
2488pm_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) {
2489 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2491 *node = (pm_block_node_t) {
2492 .base = PM_NODE_INIT(parser, PM_BLOCK_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
2494 .parameters = parameters,
2496 .opening_loc = TOK2LOC(parser, opening),
2497 .closing_loc = TOK2LOC(parser, closing)
2506static pm_block_parameter_node_t *
2507pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2508 assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2509 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2511 *node = (pm_block_parameter_node_t) {
2512 .base = PM_NODE_INIT(parser, PM_BLOCK_PARAMETER_NODE, 0, (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name)),
2513 .name = name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
2514 .name_loc = NTOK2LOC(parser, name),
2515 .operator_loc = TOK2LOC(parser, operator)
2524static pm_block_parameters_node_t *
2525pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2526 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2529 if (opening != NULL) {
2530 start = PM_TOKEN_START(parser, opening);
2531 } else if (parameters != NULL) {
2532 start = PM_NODE_START(parameters);
2538 if (parameters != NULL) {
2539 end = PM_NODE_END(parameters);
2540 } else if (opening != NULL) {
2541 end = PM_TOKEN_END(parser, opening);
2546 *node = (pm_block_parameters_node_t) {
2547 .base = PM_NODE_INIT(parser, PM_BLOCK_PARAMETERS_NODE, 0, ((pm_location_t) { .start = start, .length = U32(end - start) })),
2548 .parameters = parameters,
2549 .opening_loc = NTOK2LOC(parser, opening),
2550 .closing_loc = { 0 },
2561pm_block_parameters_node_closing_set(const pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_token_t *closing) {
2562 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == 0);
2563 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2564 node->closing_loc = TOK2LOC(parser, closing);
2570static pm_block_local_variable_node_t *
2571pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2572 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2574 *node = (pm_block_local_variable_node_t) {
2575 .base = PM_NODE_INIT(parser, PM_BLOCK_LOCAL_VARIABLE_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, name)),
2576 .name = pm_parser_constant_id_token(parser, name)
2586pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2587 pm_node_list_append(&node->locals, UP(local));
2589 if (PM_NODE_LENGTH(node) == 0) {
2590 PM_NODE_START_SET_NODE(node, local);
2593 PM_NODE_LENGTH_SET_NODE(node, local);
2599static pm_break_node_t *
2600pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2601 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2602 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2604 *node = (pm_break_node_t) {
2605 .base = PM_NODE_INIT(parser, PM_BREAK_NODE, 0, (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments)),
2606 .arguments = arguments,
2607 .keyword_loc = TOK2LOC(parser, keyword)
2613// There are certain flags that we want to use internally but don't want to
2614// expose because they are not relevant beyond parsing. Therefore we'll define
2615// them here and not define them in config.yml/a header file.
2616static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2618static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2619static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2620static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2627static pm_call_node_t *
2628pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2629 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2631 *node = (pm_call_node_t) {
2632 .base = PM_NODE_INIT(parser, PM_CALL_NODE, flags, PM_LOCATION_INIT_UNSET),
2634 .call_operator_loc = { 0 },
2635 .message_loc = { 0 },
2636 .opening_loc = { 0 },
2638 .closing_loc = { 0 },
2651static inline pm_node_flags_t
2652pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2653 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2660static pm_call_node_t *
2661pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2662 pm_assert_value_expression(parser, receiver);
2664 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2665 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2666 flags |= PM_CALL_NODE_FLAGS_INDEX;
2669 pm_call_node_t *node = pm_call_node_create(parser, flags);
2671 PM_NODE_START_SET_NODE(node, receiver);
2673 const pm_location_t *end = pm_arguments_end(arguments);
2674 assert(end != NULL && "unreachable");
2675 PM_NODE_LENGTH_SET_LOCATION(node, end);
2677 node->receiver = receiver;
2678 node->message_loc.start = arguments->opening_loc.start;
2679 node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
2681 node->opening_loc = arguments->opening_loc;
2682 node->arguments = arguments->arguments;
2683 node->closing_loc = arguments->closing_loc;
2684 node->block = arguments->block;
2686 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2693static pm_call_node_t *
2694pm_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) {
2695 pm_assert_value_expression(parser, receiver);
2696 pm_assert_value_expression(parser, argument);
2698 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2700 PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
2701 PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
2703 node->receiver = receiver;
2704 node->message_loc = TOK2LOC(parser, operator);
2706 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2707 pm_arguments_node_arguments_append(arguments, argument);
2708 node->arguments = arguments;
2710 node->name = pm_parser_constant_id_token(parser, operator);
2714static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
2719static pm_call_node_t *
2720pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2721 pm_assert_value_expression(parser, receiver);
2723 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2725 PM_NODE_START_SET_NODE(node, receiver);
2726 const pm_location_t *end = pm_arguments_end(arguments);
2728 PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
2730 PM_NODE_LENGTH_SET_LOCATION(node, end);
2733 node->receiver = receiver;
2734 node->call_operator_loc = TOK2LOC(parser, operator);
2735 node->message_loc = TOK2LOC(parser, message);
2736 node->opening_loc = arguments->opening_loc;
2737 node->arguments = arguments->arguments;
2738 node->closing_loc = arguments->closing_loc;
2739 node->block = arguments->block;
2741 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2742 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2749 node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
2756static pm_call_node_t *
2757pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2758 pm_call_node_t *node = pm_call_node_create(parser, 0);
2759 node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
2761 node->receiver = receiver;
2762 node->arguments = arguments;
2764 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2772static pm_call_node_t *
2773pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2774 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2776 PM_NODE_START_SET_TOKEN(parser, node, message);
2777 const pm_location_t *end = pm_arguments_end(arguments);
2778 assert(end != NULL && "unreachable");
2779 PM_NODE_LENGTH_SET_LOCATION(node, end);
2781 node->message_loc = TOK2LOC(parser, message);
2782 node->opening_loc = arguments->opening_loc;
2783 node->arguments = arguments->arguments;
2784 node->closing_loc = arguments->closing_loc;
2785 node->block = arguments->block;
2787 node->name = pm_parser_constant_id_token(parser, message);
2795static pm_call_node_t *
2796pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2797 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2799 node->base.location = (pm_location_t) { 0 };
2800 node->arguments = arguments;
2809static pm_call_node_t *
2810pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2811 pm_assert_value_expression(parser, receiver);
2812 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2814 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2816 PM_NODE_START_SET_TOKEN(parser, node, message);
2817 if (arguments->closing_loc.length > 0) {
2818 PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
2820 assert(receiver != NULL);
2821 PM_NODE_LENGTH_SET_NODE(node, receiver);
2824 node->receiver = receiver;
2825 node->message_loc = TOK2LOC(parser, message);
2826 node->opening_loc = arguments->opening_loc;
2827 node->arguments = arguments->arguments;
2828 node->closing_loc = arguments->closing_loc;
2830 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2837static pm_call_node_t *
2838pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2839 pm_assert_value_expression(parser, receiver);
2841 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2843 PM_NODE_START_SET_NODE(node, receiver);
2844 const pm_location_t *end = pm_arguments_end(arguments);
2845 assert(end != NULL && "unreachable");
2846 PM_NODE_LENGTH_SET_LOCATION(node, end);
2848 node->receiver = receiver;
2849 node->call_operator_loc = TOK2LOC(parser, operator);
2850 node->opening_loc = arguments->opening_loc;
2851 node->arguments = arguments->arguments;
2852 node->closing_loc = arguments->closing_loc;
2853 node->block = arguments->block;
2855 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2856 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2859 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2866static pm_call_node_t *
2867pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2868 pm_assert_value_expression(parser, receiver);
2870 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2872 PM_NODE_START_SET_TOKEN(parser, node, operator);
2873 PM_NODE_LENGTH_SET_NODE(node, receiver);
2875 node->receiver = receiver;
2876 node->message_loc = TOK2LOC(parser, operator);
2878 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2886static pm_call_node_t *
2887pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2888 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2890 node->base.location = TOK2LOC(parser, message);
2891 node->message_loc = TOK2LOC(parser, message);
2893 node->name = pm_parser_constant_id_token(parser, message);
2902pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2904 (node->message_loc.length > 0) &&
2905 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
2906 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
2907 char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
2908 (node->opening_loc.length == 0) &&
2909 (node->arguments == NULL) &&
2910 (node->block == NULL)
2918pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2919 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2921 if (write_constant->length > 0) {
2922 size_t length = write_constant->length - 1;
2924 void *memory = xmalloc(length);
2925 memcpy(memory, write_constant->start, length);
2927 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2929 // We can get here if the message was missing because of a syntax error.
2930 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2937static pm_call_and_write_node_t *
2938pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2939 assert(target->block == NULL);
2940 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2941 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2943 *node = (pm_call_and_write_node_t) {
2944 .base = PM_NODE_INIT(parser, PM_CALL_AND_WRITE_NODE, FL(target), PM_LOCATION_INIT_NODES(target, value)),
2945 .receiver = target->receiver,
2946 .call_operator_loc = target->call_operator_loc,
2947 .message_loc = target->message_loc,
2949 .write_name = target->name,
2950 .operator_loc = TOK2LOC(parser, operator),
2954 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2956 // Here we're going to free the target, since it is no longer necessary.
2957 // However, we don't want to call `pm_node_destroy` because we want to keep
2958 // around all of its children since we just reused them.
2959 xfree_sized(target, sizeof(pm_call_node_t));
2969pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2970 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2971 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2973 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2974 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2975 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2981 if (block != NULL) {
2982 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2990static pm_index_and_write_node_t *
2991pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2992 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2993 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
2995 pm_index_arguments_check(parser, target->arguments, target->block);
2997 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2998 *node = (pm_index_and_write_node_t) {
2999 .base = PM_NODE_INIT(parser, PM_INDEX_AND_WRITE_NODE, FL(target), PM_LOCATION_INIT_NODES(target, value)),
3000 .receiver = target->receiver,
3001 .call_operator_loc = target->call_operator_loc,
3002 .opening_loc = target->opening_loc,
3003 .arguments = target->arguments,
3004 .closing_loc = target->closing_loc,
3005 .block = (pm_block_argument_node_t *) target->block,
3006 .operator_loc = TOK2LOC(parser, operator),
3010 // Here we're going to free the target, since it is no longer necessary.
3011 // However, we don't want to call `pm_node_destroy` because we want to keep
3012 // around all of its children since we just reused them.
3013 xfree_sized(target, sizeof(pm_call_node_t));
3021static pm_call_operator_write_node_t *
3022pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3023 assert(target->block == NULL);
3024 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3026 *node = (pm_call_operator_write_node_t) {
3027 .base = PM_NODE_INIT(parser, PM_CALL_OPERATOR_WRITE_NODE, FL(target), PM_LOCATION_INIT_NODES(target, value)),
3028 .receiver = target->receiver,
3029 .call_operator_loc = target->call_operator_loc,
3030 .message_loc = target->message_loc,
3032 .write_name = target->name,
3033 .binary_operator = pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3034 .binary_operator_loc = TOK2LOC(parser, operator),
3038 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3040 // Here we're going to free the target, since it is no longer necessary.
3041 // However, we don't want to call `pm_node_destroy` because we want to keep
3042 // around all of its children since we just reused them.
3043 xfree_sized(target, sizeof(pm_call_node_t));
3051static pm_index_operator_write_node_t *
3052pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3053 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3055 pm_index_arguments_check(parser, target->arguments, target->block);
3057 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3058 *node = (pm_index_operator_write_node_t) {
3059 .base = PM_NODE_INIT(parser, PM_INDEX_OPERATOR_WRITE_NODE, FL(target), PM_LOCATION_INIT_NODES(target, value)),
3060 .receiver = target->receiver,
3061 .call_operator_loc = target->call_operator_loc,
3062 .opening_loc = target->opening_loc,
3063 .arguments = target->arguments,
3064 .closing_loc = target->closing_loc,
3065 .block = (pm_block_argument_node_t *) target->block,
3066 .binary_operator = pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3067 .binary_operator_loc = TOK2LOC(parser, operator),
3071 // Here we're going to free the target, since it is no longer necessary.
3072 // However, we don't want to call `pm_node_destroy` because we want to keep
3073 // around all of its children since we just reused them.
3074 xfree_sized(target, sizeof(pm_call_node_t));
3082static pm_call_or_write_node_t *
3083pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3084 assert(target->block == NULL);
3085 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3086 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3088 *node = (pm_call_or_write_node_t) {
3089 .base = PM_NODE_INIT(parser, PM_CALL_OR_WRITE_NODE, FL(target), PM_LOCATION_INIT_NODES(target, value)),
3090 .receiver = target->receiver,
3091 .call_operator_loc = target->call_operator_loc,
3092 .message_loc = target->message_loc,
3094 .write_name = target->name,
3095 .operator_loc = TOK2LOC(parser, operator),
3099 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3101 // Here we're going to free the target, since it is no longer necessary.
3102 // However, we don't want to call `pm_node_destroy` because we want to keep
3103 // around all of its children since we just reused them.
3104 xfree_sized(target, sizeof(pm_call_node_t));
3112static pm_index_or_write_node_t *
3113pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3114 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3115 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3117 pm_index_arguments_check(parser, target->arguments, target->block);
3119 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3120 *node = (pm_index_or_write_node_t) {
3121 .base = PM_NODE_INIT(parser, PM_INDEX_OR_WRITE_NODE, FL(target), PM_LOCATION_INIT_NODES(target, value)),
3122 .receiver = target->receiver,
3123 .call_operator_loc = target->call_operator_loc,
3124 .opening_loc = target->opening_loc,
3125 .arguments = target->arguments,
3126 .closing_loc = target->closing_loc,
3127 .block = (pm_block_argument_node_t *) target->block,
3128 .operator_loc = TOK2LOC(parser, operator),
3132 // Here we're going to free the target, since it is no longer necessary.
3133 // However, we don't want to call `pm_node_destroy` because we want to keep
3134 // around all of its children since we just reused them.
3135 xfree_sized(target, sizeof(pm_call_node_t));
3144static pm_call_target_node_t *
3145pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3146 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3148 *node = (pm_call_target_node_t) {
3149 .base = PM_NODE_INIT(parser, PM_CALL_TARGET_NODE, FL(target), PM_LOCATION_INIT_NODE(target)),
3150 .receiver = target->receiver,
3151 .call_operator_loc = target->call_operator_loc,
3152 .name = target->name,
3153 .message_loc = target->message_loc
3156 /* It is possible to get here where we have parsed an invalid syntax tree
3157 * where the call operator was not present. In that case we will have a
3158 * problem because it is a required location. In this case we need to fill
3159 * it in with a fake location so that the syntax tree remains valid. */
3160 if (node->call_operator_loc.length == 0) {
3161 node->call_operator_loc = target->base.location;
3164 // Here we're going to free the target, since it is no longer necessary.
3165 // However, we don't want to call `pm_node_destroy` because we want to keep
3166 // around all of its children since we just reused them.
3167 xfree_sized(target, sizeof(pm_call_node_t));
3176static pm_index_target_node_t *
3177pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3178 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3180 pm_index_arguments_check(parser, target->arguments, target->block);
3181 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3183 *node = (pm_index_target_node_t) {
3184 .base = PM_NODE_INIT(parser, PM_INDEX_TARGET_NODE, FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE, PM_LOCATION_INIT_NODE(target)),
3185 .receiver = target->receiver,
3186 .opening_loc = target->opening_loc,
3187 .arguments = target->arguments,
3188 .closing_loc = target->closing_loc,
3189 .block = (pm_block_argument_node_t *) target->block,
3192 // Here we're going to free the target, since it is no longer necessary.
3193 // However, we don't want to call `pm_node_destroy` because we want to keep
3194 // around all of its children since we just reused them.
3195 xfree_sized(target, sizeof(pm_call_node_t));
3203static pm_capture_pattern_node_t *
3204pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3205 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3207 *node = (pm_capture_pattern_node_t) {
3208 .base = PM_NODE_INIT(parser, PM_CAPTURE_PATTERN_NODE, 0, PM_LOCATION_INIT_NODES(value, target)),
3211 .operator_loc = TOK2LOC(parser, operator)
3220static pm_case_node_t *
3221pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3222 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3224 *node = (pm_case_node_t) {
3225 .base = PM_NODE_INIT(parser, PM_CASE_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword)),
3226 .predicate = predicate,
3227 .else_clause = NULL,
3228 .case_keyword_loc = TOK2LOC(parser, case_keyword),
3229 .end_keyword_loc = NTOK2LOC(parser, end_keyword),
3240pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3241 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3243 pm_node_list_append(&node->conditions, condition);
3244 PM_NODE_LENGTH_SET_NODE(node, condition);
3251pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3252 node->else_clause = else_clause;
3253 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3260pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
3261 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3262 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3268static pm_case_match_node_t *
3269pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
3270 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3272 *node = (pm_case_match_node_t) {
3273 .base = PM_NODE_INIT(parser, PM_CASE_MATCH_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, case_keyword)),
3274 .predicate = predicate,
3275 .else_clause = NULL,
3276 .case_keyword_loc = TOK2LOC(parser, case_keyword),
3277 .end_keyword_loc = { 0 },
3288pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3289 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3291 pm_node_list_append(&node->conditions, condition);
3292 PM_NODE_LENGTH_SET_NODE(node, condition);
3299pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3300 node->else_clause = else_clause;
3301 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3308pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3309 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3310 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3316static pm_class_node_t *
3317pm_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) {
3318 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3320 *node = (pm_class_node_t) {
3321 .base = PM_NODE_INIT(parser, PM_CLASS_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword)),
3323 .class_keyword_loc = TOK2LOC(parser, class_keyword),
3324 .constant_path = constant_path,
3325 .inheritance_operator_loc = NTOK2LOC(parser, inheritance_operator),
3326 .superclass = superclass,
3328 .end_keyword_loc = TOK2LOC(parser, end_keyword),
3329 .name = pm_parser_constant_id_token(parser, name)
3338static pm_class_variable_and_write_node_t *
3339pm_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) {
3340 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3341 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3343 *node = (pm_class_variable_and_write_node_t) {
3344 .base = PM_NODE_INIT(parser, PM_CLASS_VARIABLE_AND_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3345 .name = target->name,
3346 .name_loc = target->base.location,
3347 .operator_loc = TOK2LOC(parser, operator),
3357static pm_class_variable_operator_write_node_t *
3358pm_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) {
3359 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3361 *node = (pm_class_variable_operator_write_node_t) {
3362 .base = PM_NODE_INIT(parser, PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3363 .name = target->name,
3364 .name_loc = target->base.location,
3365 .binary_operator_loc = TOK2LOC(parser, operator),
3367 .binary_operator = pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3376static pm_class_variable_or_write_node_t *
3377pm_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) {
3378 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3379 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3381 *node = (pm_class_variable_or_write_node_t) {
3382 .base = PM_NODE_INIT(parser, PM_CLASS_VARIABLE_OR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3383 .name = target->name,
3384 .name_loc = target->base.location,
3385 .operator_loc = TOK2LOC(parser, operator),
3395static pm_class_variable_read_node_t *
3396pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3397 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3398 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3400 *node = (pm_class_variable_read_node_t) {
3401 .base = PM_NODE_INIT(parser, PM_CLASS_VARIABLE_READ_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token)),
3402 .name = pm_parser_constant_id_token(parser, token)
3414static inline pm_node_flags_t
3415pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3416 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
3425static pm_class_variable_write_node_t *
3426pm_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) {
3427 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3428 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3430 *node = (pm_class_variable_write_node_t) {
3431 .base = PM_NODE_INIT(parser, PM_CLASS_VARIABLE_WRITE_NODE, flags, PM_LOCATION_INIT_NODES(read_node, value)),
3432 .name = read_node->name,
3433 .name_loc = read_node->base.location,
3434 .operator_loc = TOK2LOC(parser, operator),
3444static pm_constant_path_and_write_node_t *
3445pm_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) {
3446 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3447 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3449 *node = (pm_constant_path_and_write_node_t) {
3450 .base = PM_NODE_INIT(parser, PM_CONSTANT_PATH_AND_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3452 .operator_loc = TOK2LOC(parser, operator),
3462static pm_constant_path_operator_write_node_t *
3463pm_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) {
3464 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3466 *node = (pm_constant_path_operator_write_node_t) {
3467 .base = PM_NODE_INIT(parser, PM_CONSTANT_PATH_OPERATOR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3469 .binary_operator_loc = TOK2LOC(parser, operator),
3471 .binary_operator = pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3480static pm_constant_path_or_write_node_t *
3481pm_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) {
3482 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3483 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3485 *node = (pm_constant_path_or_write_node_t) {
3486 .base = PM_NODE_INIT(parser, PM_CONSTANT_PATH_OR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3488 .operator_loc = TOK2LOC(parser, operator),
3498static pm_constant_path_node_t *
3499pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3500 pm_assert_value_expression(parser, parent);
3501 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3503 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3504 if (name_token->type == PM_TOKEN_CONSTANT) {
3505 name = pm_parser_constant_id_token(parser, name_token);
3508 *node = (pm_constant_path_node_t) {
3509 .base = PM_NODE_INIT(parser, PM_CONSTANT_PATH_NODE, 0, (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token)),
3512 .delimiter_loc = TOK2LOC(parser, delimiter),
3513 .name_loc = TOK2LOC(parser, name_token)
3522static pm_constant_path_write_node_t *
3523pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3524 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3525 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3527 *node = (pm_constant_path_write_node_t) {
3528 .base = PM_NODE_INIT(parser, PM_CONSTANT_PATH_WRITE_NODE, flags, PM_LOCATION_INIT_NODES(target, value)),
3530 .operator_loc = TOK2LOC(parser, operator),
3540static pm_constant_and_write_node_t *
3541pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3542 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3543 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3545 *node = (pm_constant_and_write_node_t) {
3546 .base = PM_NODE_INIT(parser, PM_CONSTANT_AND_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3547 .name = target->name,
3548 .name_loc = target->base.location,
3549 .operator_loc = TOK2LOC(parser, operator),
3559static pm_constant_operator_write_node_t *
3560pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3561 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3563 *node = (pm_constant_operator_write_node_t) {
3564 .base = PM_NODE_INIT(parser, PM_CONSTANT_OPERATOR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3565 .name = target->name,
3566 .name_loc = target->base.location,
3567 .binary_operator_loc = TOK2LOC(parser, operator),
3569 .binary_operator = pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3578static pm_constant_or_write_node_t *
3579pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3580 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3581 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3583 *node = (pm_constant_or_write_node_t) {
3584 .base = PM_NODE_INIT(parser, PM_CONSTANT_OR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
3585 .name = target->name,
3586 .name_loc = target->base.location,
3587 .operator_loc = TOK2LOC(parser, operator),
3597static pm_constant_read_node_t *
3598pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3599 assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
3600 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3602 *node = (pm_constant_read_node_t) {
3603 .base = PM_NODE_INIT(parser, PM_CONSTANT_READ_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, name)),
3604 .name = pm_parser_constant_id_token(parser, name)
3613static pm_constant_write_node_t *
3614pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3615 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3616 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3618 *node = (pm_constant_write_node_t) {
3619 .base = PM_NODE_INIT(parser, PM_CONSTANT_WRITE_NODE, flags, PM_LOCATION_INIT_NODES(target, value)),
3620 .name = target->name,
3621 .name_loc = target->base.location,
3622 .operator_loc = TOK2LOC(parser, operator),
3633pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3634 switch (PM_NODE_TYPE(node)) {
3635 case PM_BEGIN_NODE: {
3636 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3637 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3640 case PM_PARENTHESES_NODE: {
3641 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3642 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3645 case PM_STATEMENTS_NODE: {
3646 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3647 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3652 case PM_IMAGINARY_NODE:
3653 case PM_INTEGER_NODE:
3654 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3655 case PM_INTERPOLATED_STRING_NODE:
3656 case PM_INTERPOLATED_SYMBOL_NODE:
3657 case PM_INTERPOLATED_X_STRING_NODE:
3658 case PM_RATIONAL_NODE:
3659 case PM_REGULAR_EXPRESSION_NODE:
3660 case PM_SOURCE_ENCODING_NODE:
3661 case PM_SOURCE_FILE_NODE:
3662 case PM_SOURCE_LINE_NODE:
3663 case PM_STRING_NODE:
3664 case PM_SYMBOL_NODE:
3665 case PM_X_STRING_NODE:
3666 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3676static pm_def_node_t *
3678 pm_parser_t *parser,
3679 pm_constant_id_t name,
3680 const pm_token_t *name_loc,
3681 pm_node_t *receiver,
3682 pm_parameters_node_t *parameters,
3684 pm_constant_id_list_t *locals,
3685 const pm_token_t *def_keyword,
3686 const pm_token_t *operator,
3687 const pm_token_t *lparen,
3688 const pm_token_t *rparen,
3689 const pm_token_t *equal,
3690 const pm_token_t *end_keyword
3692 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3694 if (receiver != NULL) {
3695 pm_def_node_receiver_check(parser, receiver);
3698 *node = (pm_def_node_t) {
3699 .base = PM_NODE_INIT(parser, PM_DEF_NODE, 0, (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword)),
3701 .name_loc = TOK2LOC(parser, name_loc),
3702 .receiver = receiver,
3703 .parameters = parameters,
3706 .def_keyword_loc = TOK2LOC(parser, def_keyword),
3707 .operator_loc = NTOK2LOC(parser, operator),
3708 .lparen_loc = NTOK2LOC(parser, lparen),
3709 .rparen_loc = NTOK2LOC(parser, rparen),
3710 .equal_loc = NTOK2LOC(parser, equal),
3711 .end_keyword_loc = NTOK2LOC(parser, end_keyword)
3720static pm_defined_node_t *
3721pm_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) {
3722 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3724 *node = (pm_defined_node_t) {
3725 .base = PM_NODE_INIT(parser, PM_DEFINED_NODE, 0, (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen)),
3726 .lparen_loc = NTOK2LOC(parser, lparen),
3728 .rparen_loc = NTOK2LOC(parser, rparen),
3729 .keyword_loc = TOK2LOC(parser, keyword)
3738static pm_else_node_t *
3739pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3740 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3742 *node = (pm_else_node_t) {
3743 .base = PM_NODE_INIT(parser, PM_ELSE_NODE, 0, ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword)),
3744 .else_keyword_loc = TOK2LOC(parser, else_keyword),
3745 .statements = statements,
3746 .end_keyword_loc = NTOK2LOC(parser, end_keyword)
3755static pm_embedded_statements_node_t *
3756pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3757 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3759 *node = (pm_embedded_statements_node_t) {
3760 .base = PM_NODE_INIT(parser, PM_EMBEDDED_STATEMENTS_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
3761 .opening_loc = TOK2LOC(parser, opening),
3762 .statements = statements,
3763 .closing_loc = TOK2LOC(parser, closing)
3772static pm_embedded_variable_node_t *
3773pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3774 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3776 *node = (pm_embedded_variable_node_t) {
3777 .base = PM_NODE_INIT(parser, PM_EMBEDDED_VARIABLE_NODE, 0, PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable)),
3778 .operator_loc = TOK2LOC(parser, operator),
3779 .variable = variable
3788static pm_ensure_node_t *
3789pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3790 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
3792 *node = (pm_ensure_node_t) {
3793 .base = PM_NODE_INIT(parser, PM_ENSURE_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword)),
3794 .ensure_keyword_loc = TOK2LOC(parser, ensure_keyword),
3795 .statements = statements,
3796 .end_keyword_loc = TOK2LOC(parser, end_keyword)
3805static pm_false_node_t *
3806pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
3807 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
3808 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
3810 *node = (pm_false_node_t) {
3811 .base = PM_NODE_INIT(parser, PM_FALSE_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token))
3821static pm_find_pattern_node_t *
3822pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
3823 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
3825 pm_node_t *left = nodes->nodes[0];
3826 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
3827 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
3831 if (nodes->size == 1) {
3832 right = UP(pm_missing_node_create(parser, PM_NODE_END(left), 0));
3834 right = nodes->nodes[nodes->size - 1];
3835 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
3838#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
3839 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
3840 // The resulting AST will anyway be ignored, but this file still needs to compile.
3841 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
3843 pm_node_t *right_splat_node = right;
3845 *node = (pm_find_pattern_node_t) {
3846 .base = PM_NODE_INIT(parser, PM_FIND_PATTERN_NODE, 0, PM_LOCATION_INIT_NODES(left, right)),
3848 .left = left_splat_node,
3849 .right = right_splat_node,
3851 .opening_loc = { 0 },
3852 .closing_loc = { 0 }
3855 // For now we're going to just copy over each pointer manually. This could be
3856 // much more efficient, as we could instead resize the node list to only point
3858 for (size_t index = 1; index < nodes->size - 1; index++) {
3859 pm_node_list_append(&node->requireds, nodes->nodes[index]);
3870pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
3871 ptrdiff_t diff = token->end - token->start;
3872 if (diff <= 0) return 0.0;
3874 // First, get a buffer of the content.
3875 size_t length = (size_t) diff;
3876 const size_t buffer_size = sizeof(char) * (length + 1);
3877 char *buffer = xmalloc(buffer_size);
3878 memcpy((void *) buffer, token->start, length);
3880 // Next, determine if we need to replace the decimal point because of
3881 // locale-specific options, and then normalize them if we have to.
3882 char decimal_point = *localeconv()->decimal_point;
3883 if (decimal_point != '.') {
3884 for (size_t index = 0; index < length; index++) {
3885 if (buffer[index] == '.') buffer[index] = decimal_point;
3889 // Next, handle underscores by removing them from the buffer.
3890 for (size_t index = 0; index < length; index++) {
3891 if (buffer[index] == '_') {
3892 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
3897 // Null-terminate the buffer so that strtod cannot read off the end.
3898 buffer[length] = '\0';
3900 // Now, call strtod to parse the value. Note that CRuby has their own
3901 // version of strtod which avoids locales. We're okay using the locale-aware
3902 // version because we've already validated through the parser that the token
3903 // is in a valid format.
3906 double value = strtod(buffer, &eptr);
3908 // This should never happen, because we've already checked that the token
3909 // is in a valid format. However it's good to be safe.
3910 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
3911 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
3912 xfree_sized(buffer, buffer_size);
3916 // If errno is set, then it should only be ERANGE. At this point we need to
3917 // check if it's infinity (it should be).
3918 if (errno == ERANGE && PRISM_ISINF(value)) {
3920 const char *ellipsis;
3926 warn_width = (int) length;
3930 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);
3931 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
3934 // Finally we can free the buffer and return the value.
3935 xfree_sized(buffer, buffer_size);
3942static pm_float_node_t *
3943pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
3944 assert(token->type == PM_TOKEN_FLOAT);
3945 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
3947 *node = (pm_float_node_t) {
3948 .base = PM_NODE_INIT(parser, PM_FLOAT_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token)),
3949 .value = pm_double_parse(parser, token)
3958static pm_imaginary_node_t *
3959pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3960 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
3962 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3963 *node = (pm_imaginary_node_t) {
3964 .base = PM_NODE_INIT(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token)),
3965 .numeric = UP(pm_float_node_create(parser, &((pm_token_t) {
3966 .type = PM_TOKEN_FLOAT,
3967 .start = token->start,
3968 .end = token->end - 1
3978static pm_rational_node_t *
3979pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
3980 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
3982 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
3983 *node = (pm_rational_node_t) {
3984 .base = PM_NODE_INIT(parser, PM_RATIONAL_NODE, PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token)),
3986 .denominator = { 0 }
3989 const uint8_t *start = token->start;
3990 const uint8_t *end = token->end - 1; // r
3992 while (start < end && *start == '0') start++; // 0.1 -> .1
3993 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
3995 size_t length = (size_t) (end - start);
3997 node->denominator.value = 1;
4001 const uint8_t *point = memchr(start, '.', length);
4002 assert(point && "should have a decimal point");
4004 uint8_t *digits = xmalloc(length);
4005 if (digits == NULL) {
4006 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4010 memcpy(digits, start, (unsigned long) (point - start));
4011 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4012 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4014 size_t fract_length = 0;
4015 for (const uint8_t *fract = point; fract < end; ++fract) {
4016 if (*fract != '_') ++fract_length;
4019 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
4020 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
4021 xfree_sized(digits, length);
4023 pm_integers_reduce(&node->numerator, &node->denominator);
4031static pm_imaginary_node_t *
4032pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4033 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4035 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4036 *node = (pm_imaginary_node_t) {
4037 .base = PM_NODE_INIT(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token)),
4038 .numeric = UP(pm_float_node_rational_create(parser, &((pm_token_t) {
4039 .type = PM_TOKEN_FLOAT_RATIONAL,
4040 .start = token->start,
4041 .end = token->end - 1
4051static pm_for_node_t *
4053 pm_parser_t *parser,
4055 pm_node_t *collection,
4056 pm_statements_node_t *statements,
4057 const pm_token_t *for_keyword,
4058 const pm_token_t *in_keyword,
4059 const pm_token_t *do_keyword,
4060 const pm_token_t *end_keyword
4062 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4064 *node = (pm_for_node_t) {
4065 .base = PM_NODE_INIT(parser, PM_FOR_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword)),
4067 .collection = collection,
4068 .statements = statements,
4069 .for_keyword_loc = TOK2LOC(parser, for_keyword),
4070 .in_keyword_loc = TOK2LOC(parser, in_keyword),
4071 .do_keyword_loc = NTOK2LOC(parser, do_keyword),
4072 .end_keyword_loc = TOK2LOC(parser, end_keyword)
4081static pm_forwarding_arguments_node_t *
4082pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4083 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4084 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4086 *node = (pm_forwarding_arguments_node_t) {
4087 .base = PM_NODE_INIT(parser, PM_FORWARDING_ARGUMENTS_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token))
4096static pm_forwarding_parameter_node_t *
4097pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4098 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4099 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4101 *node = (pm_forwarding_parameter_node_t) {
4102 .base = PM_NODE_INIT(parser, PM_FORWARDING_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token))
4111static pm_forwarding_super_node_t *
4112pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4113 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4114 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4115 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4117 pm_block_node_t *block = NULL;
4118 if (arguments->block != NULL) {
4119 block = (pm_block_node_t *) arguments->block;
4122 *node = (pm_forwarding_super_node_t) {
4123 .base = PM_NODE_INIT(parser, PM_FORWARDING_SUPER_NODE, 0, (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block)),
4134static pm_hash_pattern_node_t *
4135pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4136 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4138 *node = (pm_hash_pattern_node_t) {
4139 .base = PM_NODE_INIT(parser, PM_HASH_PATTERN_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
4141 .opening_loc = TOK2LOC(parser, opening),
4142 .closing_loc = TOK2LOC(parser, closing),
4153static pm_hash_pattern_node_t *
4154pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4155 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4160 if (elements->size > 0) {
4162 start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
4163 end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
4165 start = PM_NODE_START(elements->nodes[0]);
4166 end = PM_NODE_END(elements->nodes[elements->size - 1]);
4169 assert(rest != NULL);
4170 start = PM_NODE_START(rest);
4171 end = PM_NODE_END(rest);
4174 *node = (pm_hash_pattern_node_t) {
4175 .base = PM_NODE_INIT(parser, PM_HASH_PATTERN_NODE, 0, ((pm_location_t) { .start = start, .length = U32(end - start) })),
4179 .opening_loc = { 0 },
4180 .closing_loc = { 0 }
4183 pm_node_list_concat(&node->elements, elements);
4190static pm_constant_id_t
4191pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4192 switch (PM_NODE_TYPE(target)) {
4193 case PM_GLOBAL_VARIABLE_READ_NODE:
4194 return ((pm_global_variable_read_node_t *) target)->name;
4195 case PM_BACK_REFERENCE_READ_NODE:
4196 return ((pm_back_reference_read_node_t *) target)->name;
4197 case PM_NUMBERED_REFERENCE_READ_NODE:
4198 // This will only ever happen in the event of a syntax error, but we
4199 // still need to provide something for the node.
4200 return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
4202 assert(false && "unreachable");
4203 return (pm_constant_id_t) -1;
4210static pm_global_variable_and_write_node_t *
4211pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4212 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4213 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4215 *node = (pm_global_variable_and_write_node_t) {
4216 .base = PM_NODE_INIT(parser, PM_GLOBAL_VARIABLE_AND_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
4217 .name = pm_global_variable_write_name(parser, target),
4218 .name_loc = target->location,
4219 .operator_loc = TOK2LOC(parser, operator),
4229static pm_global_variable_operator_write_node_t *
4230pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4231 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4233 *node = (pm_global_variable_operator_write_node_t) {
4234 .base = PM_NODE_INIT(parser, PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
4235 .name = pm_global_variable_write_name(parser, target),
4236 .name_loc = target->location,
4237 .binary_operator_loc = TOK2LOC(parser, operator),
4239 .binary_operator = pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4248static pm_global_variable_or_write_node_t *
4249pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4250 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4251 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4253 *node = (pm_global_variable_or_write_node_t) {
4254 .base = PM_NODE_INIT(parser, PM_GLOBAL_VARIABLE_OR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
4255 .name = pm_global_variable_write_name(parser, target),
4256 .name_loc = target->location,
4257 .operator_loc = TOK2LOC(parser, operator),
4267static pm_global_variable_read_node_t *
4268pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4269 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4271 *node = (pm_global_variable_read_node_t) {
4272 .base = PM_NODE_INIT(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, name)),
4273 .name = pm_parser_constant_id_token(parser, name)
4282static pm_global_variable_read_node_t *
4283pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4284 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4286 *node = (pm_global_variable_read_node_t) {
4287 .base = PM_NODE_INIT(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0, PM_LOCATION_INIT_UNSET),
4297static pm_global_variable_write_node_t *
4298pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4299 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4300 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4302 *node = (pm_global_variable_write_node_t) {
4303 .base = PM_NODE_INIT(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, flags, PM_LOCATION_INIT_NODES(target, value)),
4304 .name = pm_global_variable_write_name(parser, target),
4305 .name_loc = target->location,
4306 .operator_loc = TOK2LOC(parser, operator),
4316static pm_global_variable_write_node_t *
4317pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4318 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4320 *node = (pm_global_variable_write_node_t) {
4321 .base = PM_NODE_INIT(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, 0, PM_LOCATION_INIT_UNSET),
4324 .operator_loc = { 0 },
4334static pm_hash_node_t *
4335pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4336 assert(opening != NULL);
4337 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4339 *node = (pm_hash_node_t) {
4340 .base = PM_NODE_INIT(parser, PM_HASH_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, opening)),
4341 .opening_loc = TOK2LOC(parser, opening),
4342 .closing_loc = { 0 },
4353pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4354 pm_node_list_append(&hash->elements, element);
4356 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4357 if (static_literal) {
4358 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4359 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);
4360 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4361 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4364 if (!static_literal) {
4365 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4370pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
4371 PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
4372 hash->closing_loc = TOK2LOC(parser, token);
4378static pm_if_node_t *
4379pm_if_node_create(pm_parser_t *parser,
4380 const pm_token_t *if_keyword,
4381 pm_node_t *predicate,
4382 const pm_token_t *then_keyword,
4383 pm_statements_node_t *statements,
4384 pm_node_t *subsequent,
4385 const pm_token_t *end_keyword
4387 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4388 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4390 uint32_t start = PM_TOKEN_START(parser, if_keyword);
4393 if (end_keyword != NULL) {
4394 end = PM_TOKEN_END(parser, end_keyword);
4395 } else if (subsequent != NULL) {
4396 end = PM_NODE_END(subsequent);
4397 } else if (pm_statements_node_body_length(statements) != 0) {
4398 end = PM_NODE_END(statements);
4400 end = PM_NODE_END(predicate);
4403 *node = (pm_if_node_t) {
4404 .base = PM_NODE_INIT(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, ((pm_location_t) { .start = start, .length = U32(end - start) })),
4405 .if_keyword_loc = TOK2LOC(parser, if_keyword),
4406 .predicate = predicate,
4407 .then_keyword_loc = NTOK2LOC(parser, then_keyword),
4408 .statements = statements,
4409 .subsequent = subsequent,
4410 .end_keyword_loc = NTOK2LOC(parser, end_keyword)
4419static pm_if_node_t *
4420pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4421 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4422 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4424 pm_statements_node_t *statements = pm_statements_node_create(parser);
4425 pm_statements_node_body_append(parser, statements, statement, true);
4427 *node = (pm_if_node_t) {
4428 .base = PM_NODE_INIT(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, PM_LOCATION_INIT_NODES(statement, predicate)),
4429 .if_keyword_loc = TOK2LOC(parser, if_keyword),
4430 .predicate = predicate,
4431 .then_keyword_loc = { 0 },
4432 .statements = statements,
4434 .end_keyword_loc = { 0 }
4443static pm_if_node_t *
4444pm_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) {
4445 pm_assert_value_expression(parser, predicate);
4446 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4448 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4449 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4451 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4452 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4454 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
4455 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4457 *node = (pm_if_node_t) {
4458 .base = PM_NODE_INIT(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, PM_LOCATION_INIT_NODES(predicate, false_expression)),
4459 .if_keyword_loc = { 0 },
4460 .predicate = predicate,
4461 .then_keyword_loc = TOK2LOC(parser, qmark),
4462 .statements = if_statements,
4463 .subsequent = UP(else_node),
4464 .end_keyword_loc = { 0 }
4472pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
4473 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4474 node->end_keyword_loc = TOK2LOC(parser, keyword);
4478pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
4479 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4480 node->end_keyword_loc = TOK2LOC(parser, keyword);
4486static pm_implicit_node_t *
4487pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4488 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4490 *node = (pm_implicit_node_t) {
4491 .base = PM_NODE_INIT(parser, PM_IMPLICIT_NODE, 0, PM_LOCATION_INIT_NODE(value)),
4501static pm_implicit_rest_node_t *
4502pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4503 assert(token->type == PM_TOKEN_COMMA);
4505 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4507 *node = (pm_implicit_rest_node_t) {
4508 .base = PM_NODE_INIT(parser, PM_IMPLICIT_REST_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token))
4517static pm_integer_node_t *
4518pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4519 assert(token->type == PM_TOKEN_INTEGER);
4520 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4522 *node = (pm_integer_node_t) {
4523 .base = PM_NODE_INIT(parser, PM_INTEGER_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token)),
4527 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4529 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4530 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4531 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4532 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4533 default: assert(false && "unreachable"); break;
4536 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4544static pm_imaginary_node_t *
4545pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4546 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4548 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4549 *node = (pm_imaginary_node_t) {
4550 .base = PM_NODE_INIT(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token)),
4551 .numeric = UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4552 .type = PM_TOKEN_INTEGER,
4553 .start = token->start,
4554 .end = token->end - 1
4565static pm_rational_node_t *
4566pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4567 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4569 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4570 *node = (pm_rational_node_t) {
4571 .base = PM_NODE_INIT(parser, PM_RATIONAL_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token)),
4573 .denominator = { .value = 1, 0 }
4576 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4578 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4579 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4580 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4581 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4582 default: assert(false && "unreachable"); break;
4585 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4594static pm_imaginary_node_t *
4595pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4596 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4598 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4599 *node = (pm_imaginary_node_t) {
4600 .base = PM_NODE_INIT(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token)),
4601 .numeric = UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4602 .type = PM_TOKEN_INTEGER_RATIONAL,
4603 .start = token->start,
4604 .end = token->end - 1
4614static pm_in_node_t *
4615pm_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) {
4616 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4618 uint32_t start = PM_TOKEN_START(parser, in_keyword);
4621 if (statements != NULL) {
4622 end = PM_NODE_END(statements);
4623 } else if (then_keyword != NULL) {
4624 end = PM_TOKEN_END(parser, then_keyword);
4626 end = PM_NODE_END(pattern);
4629 *node = (pm_in_node_t) {
4630 .base = PM_NODE_INIT(parser, PM_IN_NODE, 0, ((pm_location_t) { .start = start, .length = U32(end - start) })),
4632 .statements = statements,
4633 .in_loc = TOK2LOC(parser, in_keyword),
4634 .then_loc = NTOK2LOC(parser, then_keyword)
4643static pm_instance_variable_and_write_node_t *
4644pm_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) {
4645 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4646 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
4648 *node = (pm_instance_variable_and_write_node_t) {
4649 .base = PM_NODE_INIT(parser, PM_INSTANCE_VARIABLE_AND_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
4650 .name = target->name,
4651 .name_loc = target->base.location,
4652 .operator_loc = TOK2LOC(parser, operator),
4662static pm_instance_variable_operator_write_node_t *
4663pm_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) {
4664 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
4666 *node = (pm_instance_variable_operator_write_node_t) {
4667 .base = PM_NODE_INIT(parser, PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
4668 .name = target->name,
4669 .name_loc = target->base.location,
4670 .binary_operator_loc = TOK2LOC(parser, operator),
4672 .binary_operator = pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4681static pm_instance_variable_or_write_node_t *
4682pm_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) {
4683 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4684 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
4686 *node = (pm_instance_variable_or_write_node_t) {
4687 .base = PM_NODE_INIT(parser, PM_INSTANCE_VARIABLE_OR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
4688 .name = target->name,
4689 .name_loc = target->base.location,
4690 .operator_loc = TOK2LOC(parser, operator),
4700static pm_instance_variable_read_node_t *
4701pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4702 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4703 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
4705 *node = (pm_instance_variable_read_node_t) {
4706 .base = PM_NODE_INIT(parser, PM_INSTANCE_VARIABLE_READ_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token)),
4707 .name = pm_parser_constant_id_token(parser, token)
4717static pm_instance_variable_write_node_t *
4718pm_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) {
4719 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
4720 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4722 *node = (pm_instance_variable_write_node_t) {
4723 .base = PM_NODE_INIT(parser, PM_INSTANCE_VARIABLE_WRITE_NODE, flags, PM_LOCATION_INIT_NODES(read_node, value)),
4724 .name = read_node->name,
4725 .name_loc = read_node->base.location,
4726 .operator_loc = TOK2LOC(parser, operator),
4739pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4740 switch (PM_NODE_TYPE(part)) {
4741 case PM_STRING_NODE:
4742 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4744 case PM_EMBEDDED_STATEMENTS_NODE: {
4745 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4746 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4748 if (embedded == NULL) {
4749 // If there are no statements or more than one statement, then
4750 // we lose the static literal flag.
4751 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4752 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4753 // If the embedded statement is a string, then we can keep the
4754 // static literal flag and mark the string as frozen.
4755 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4756 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4757 // If the embedded statement is an interpolated string and it's
4758 // a static literal, then we can keep the static literal flag.
4760 // Otherwise we lose the static literal flag.
4761 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4766 case PM_EMBEDDED_VARIABLE_NODE:
4767 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4770 assert(false && "unexpected node type");
4774 pm_node_list_append(parts, part);
4780static pm_interpolated_regular_expression_node_t *
4781pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4782 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
4784 *node = (pm_interpolated_regular_expression_node_t) {
4785 .base = PM_NODE_INIT(parser, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, opening)),
4786 .opening_loc = TOK2LOC(parser, opening),
4787 .closing_loc = TOK2LOC(parser, opening),
4795pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
4796 if (PM_NODE_START(node) > PM_NODE_START(part)) {
4797 PM_NODE_START_SET_NODE(node, part);
4799 if (PM_NODE_END(node) < PM_NODE_END(part)) {
4800 PM_NODE_LENGTH_SET_NODE(node, part);
4803 pm_interpolated_node_append(UP(node), &node->parts, part);
4807pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
4808 node->closing_loc = TOK2LOC(parser, closing);
4809 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
4810 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
4837pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
4838#define CLEAR_FLAGS(node) \
4839 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))
4841#define MUTABLE_FLAGS(node) \
4842 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
4844 if (node->parts.size == 0 && node->opening_loc.length == 0) {
4845 PM_NODE_START_SET_NODE(node, part);
4848 if (PM_NODE_END(part) > PM_NODE_END(node)) {
4849 PM_NODE_LENGTH_SET_NODE(node, part);
4852 switch (PM_NODE_TYPE(part)) {
4853 case PM_STRING_NODE:
4854 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
4855 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
4856 // as long as this interpolation only consists of other string literals.
4857 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
4858 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4860 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4862 case PM_INTERPOLATED_STRING_NODE:
4863 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
4864 // If the string that we're concatenating is a static literal,
4865 // then we can keep the static literal flag for this string.
4867 // Otherwise, we lose the static literal flag here and we should
4868 // also clear the mutability flags.
4872 case PM_EMBEDDED_STATEMENTS_NODE: {
4873 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4874 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4876 if (embedded == NULL) {
4877 // If we're embedding multiple statements or no statements, then
4878 // the string is not longer a static literal.
4880 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4881 // If the embedded statement is a string, then we can make that
4882 // string as frozen and static literal, and not touch the static
4883 // literal status of this string.
4884 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4886 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4887 MUTABLE_FLAGS(node);
4889 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4890 // If the embedded statement is an interpolated string, but that
4891 // string is marked as static literal, then we can keep our
4892 // static literal status for this string.
4893 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4894 MUTABLE_FLAGS(node);
4897 // In all other cases, we lose the static literal flag here and
4904 case PM_EMBEDDED_VARIABLE_NODE:
4905 // Embedded variables clear static literal, which means we also
4906 // should clear the mutability flags.
4909 case PM_X_STRING_NODE:
4910 case PM_INTERPOLATED_X_STRING_NODE:
4911 case PM_SYMBOL_NODE:
4912 case PM_INTERPOLATED_SYMBOL_NODE:
4913 // These will only happen in error cases. But we want to handle it
4914 // here so that we don't fail the assertion.
4918 assert(false && "unexpected node type");
4922 pm_node_list_append(&node->parts, part);
4931static pm_interpolated_string_node_t *
4932pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4933 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
4934 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
4936 switch (parser->frozen_string_literal) {
4937 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
4938 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
4940 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
4941 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
4945 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
4946 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
4948 *node = (pm_interpolated_string_node_t) {
4949 .base = PM_NODE_INIT(parser, PM_INTERPOLATED_STRING_NODE, flags, ((pm_location_t) { .start = start, .length = U32(end - start) })),
4950 .opening_loc = NTOK2LOC(parser, opening),
4951 .closing_loc = NTOK2LOC(parser, closing),
4955 if (parts != NULL) {
4957 PM_NODE_LIST_FOREACH(parts, index, part) {
4958 pm_interpolated_string_node_append(node, part);
4969pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
4970 node->closing_loc = TOK2LOC(parser, closing);
4971 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
4975pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
4976 if (node->parts.size == 0 && node->opening_loc.length == 0) {
4977 PM_NODE_START_SET_NODE(node, part);
4980 pm_interpolated_node_append(UP(node), &node->parts, part);
4982 if (PM_NODE_END(part) > PM_NODE_END(node)) {
4983 PM_NODE_LENGTH_SET_NODE(node, part);
4988pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
4989 node->closing_loc = TOK2LOC(parser, closing);
4990 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
4996static pm_interpolated_symbol_node_t *
4997pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4998 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5000 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5001 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5003 *node = (pm_interpolated_symbol_node_t) {
5004 .base = PM_NODE_INIT(parser, PM_INTERPOLATED_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, ((pm_location_t) { .start = start, .length = U32(end - start) })),
5005 .opening_loc = NTOK2LOC(parser, opening),
5006 .closing_loc = NTOK2LOC(parser, closing),
5010 if (parts != NULL) {
5012 PM_NODE_LIST_FOREACH(parts, index, part) {
5013 pm_interpolated_symbol_node_append(node, part);
5023static pm_interpolated_x_string_node_t *
5024pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5025 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5027 *node = (pm_interpolated_x_string_node_t) {
5028 .base = PM_NODE_INIT(parser, PM_INTERPOLATED_X_STRING_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
5029 .opening_loc = TOK2LOC(parser, opening),
5030 .closing_loc = TOK2LOC(parser, closing),
5038pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5039 pm_interpolated_node_append(UP(node), &node->parts, part);
5040 PM_NODE_LENGTH_SET_NODE(node, part);
5044pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5045 node->closing_loc = TOK2LOC(parser, closing);
5046 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5052static pm_it_local_variable_read_node_t *
5053pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5054 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5056 *node = (pm_it_local_variable_read_node_t) {
5057 .base = PM_NODE_INIT(parser, PM_IT_LOCAL_VARIABLE_READ_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, name)),
5066static pm_it_parameters_node_t *
5067pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5068 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5070 *node = (pm_it_parameters_node_t) {
5071 .base = PM_NODE_INIT(parser, PM_IT_PARAMETERS_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
5080static pm_keyword_hash_node_t *
5081pm_keyword_hash_node_create(pm_parser_t *parser) {
5082 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5084 *node = (pm_keyword_hash_node_t) {
5085 .base = PM_NODE_INIT(parser, PM_KEYWORD_HASH_NODE, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS, PM_LOCATION_INIT_UNSET),
5096pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5097 // If the element being added is not an AssocNode or does not have a symbol
5098 // key, then we want to turn the SYMBOL_KEYS flag off.
5099 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5100 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5103 pm_node_list_append(&hash->elements, element);
5104 if (PM_NODE_LENGTH(hash) == 0) {
5105 PM_NODE_START_SET_NODE(hash, element);
5107 PM_NODE_LENGTH_SET_NODE(hash, element);
5113static pm_required_keyword_parameter_node_t *
5114pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5115 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5117 *node = (pm_required_keyword_parameter_node_t) {
5118 .base = PM_NODE_INIT(parser, PM_REQUIRED_KEYWORD_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, name)),
5119 .name = pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5120 .name_loc = TOK2LOC(parser, name),
5129static pm_optional_keyword_parameter_node_t *
5130pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5131 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5133 *node = (pm_optional_keyword_parameter_node_t) {
5134 .base = PM_NODE_INIT(parser, PM_OPTIONAL_KEYWORD_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKEN_NODE(parser, name, value)),
5135 .name = pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5136 .name_loc = TOK2LOC(parser, name),
5146static pm_keyword_rest_parameter_node_t *
5147pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5148 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5150 *node = (pm_keyword_rest_parameter_node_t) {
5151 .base = PM_NODE_INIT(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name)),
5152 .name = name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
5153 .name_loc = NTOK2LOC(parser, name),
5154 .operator_loc = TOK2LOC(parser, operator)
5163static pm_lambda_node_t *
5164pm_lambda_node_create(
5165 pm_parser_t *parser,
5166 pm_constant_id_list_t *locals,
5167 const pm_token_t *operator,
5168 const pm_token_t *opening,
5169 const pm_token_t *closing,
5170 pm_node_t *parameters,
5173 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5175 *node = (pm_lambda_node_t) {
5176 .base = PM_NODE_INIT(parser, PM_LAMBDA_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, operator, closing)),
5178 .operator_loc = TOK2LOC(parser, operator),
5179 .opening_loc = TOK2LOC(parser, opening),
5180 .closing_loc = TOK2LOC(parser, closing),
5181 .parameters = parameters,
5191static pm_local_variable_and_write_node_t *
5192pm_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) {
5193 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));
5194 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5195 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5197 *node = (pm_local_variable_and_write_node_t) {
5198 .base = PM_NODE_INIT(parser, PM_LOCAL_VARIABLE_AND_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
5199 .name_loc = target->location,
5200 .operator_loc = TOK2LOC(parser, operator),
5212static pm_local_variable_operator_write_node_t *
5213pm_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) {
5214 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5216 *node = (pm_local_variable_operator_write_node_t) {
5217 .base = PM_NODE_INIT(parser, PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
5218 .name_loc = target->location,
5219 .binary_operator_loc = TOK2LOC(parser, operator),
5222 .binary_operator = pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
5232static pm_local_variable_or_write_node_t *
5233pm_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) {
5234 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));
5235 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5236 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5238 *node = (pm_local_variable_or_write_node_t) {
5239 .base = PM_NODE_INIT(parser, PM_LOCAL_VARIABLE_OR_WRITE_NODE, 0, PM_LOCATION_INIT_NODES(target, value)),
5240 .name_loc = target->location,
5241 .operator_loc = TOK2LOC(parser, operator),
5253static pm_local_variable_read_node_t *
5254pm_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) {
5255 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5257 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5259 *node = (pm_local_variable_read_node_t) {
5260 .base = PM_NODE_INIT(parser, PM_LOCAL_VARIABLE_READ_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, name)),
5271static pm_local_variable_read_node_t *
5272pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5273 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5274 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5281static pm_local_variable_read_node_t *
5282pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5283 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5284 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5290static pm_local_variable_write_node_t *
5291pm_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) {
5292 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5293 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5295 *node = (pm_local_variable_write_node_t) {
5296 .base = PM_NODE_INIT(parser, PM_LOCAL_VARIABLE_WRITE_NODE, flags, ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start })),
5300 .name_loc = *name_loc,
5301 .operator_loc = TOK2LOC(parser, operator)
5311pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5312 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5320pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
5323 (parser->start[start] == '_') &&
5324 (parser->start[start + 1] != '0') &&
5325 pm_char_is_decimal_digit(parser->start[start + 1])
5334pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
5335 if (pm_token_is_numbered_parameter(parser, start, length)) {
5336 PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
5344static pm_local_variable_target_node_t *
5345pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5346 pm_refute_numbered_parameter(parser, location->start, location->length);
5347 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5349 *node = (pm_local_variable_target_node_t) {
5350 .base = PM_NODE_INIT(parser, PM_LOCAL_VARIABLE_TARGET_NODE, 0, ((pm_location_t) { .start = location->start, .length = location->length })),
5361static pm_match_predicate_node_t *
5362pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5363 pm_assert_value_expression(parser, value);
5365 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5367 *node = (pm_match_predicate_node_t) {
5368 .base = PM_NODE_INIT(parser, PM_MATCH_PREDICATE_NODE, 0, PM_LOCATION_INIT_NODES(value, pattern)),
5371 .operator_loc = TOK2LOC(parser, operator)
5380static pm_match_required_node_t *
5381pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5382 pm_assert_value_expression(parser, value);
5384 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5386 *node = (pm_match_required_node_t) {
5387 .base = PM_NODE_INIT(parser, PM_MATCH_REQUIRED_NODE, 0, PM_LOCATION_INIT_NODES(value, pattern)),
5390 .operator_loc = TOK2LOC(parser, operator)
5399static pm_match_write_node_t *
5400pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5401 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5403 *node = (pm_match_write_node_t) {
5404 .base = PM_NODE_INIT(parser, PM_MATCH_WRITE_NODE, 0, PM_LOCATION_INIT_NODE(call)),
5415static pm_module_node_t *
5416pm_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) {
5417 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5419 *node = (pm_module_node_t) {
5420 .base = PM_NODE_INIT(parser, PM_MODULE_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword)),
5421 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5422 .module_keyword_loc = TOK2LOC(parser, module_keyword),
5423 .constant_path = constant_path,
5425 .end_keyword_loc = TOK2LOC(parser, end_keyword),
5426 .name = pm_parser_constant_id_token(parser, name)
5435static pm_multi_target_node_t *
5436pm_multi_target_node_create(pm_parser_t *parser) {
5437 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5439 *node = (pm_multi_target_node_t) {
5440 .base = PM_NODE_INIT(parser, PM_MULTI_TARGET_NODE, 0, PM_LOCATION_INIT_UNSET),
5444 .lparen_loc = { 0 },
5455pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5456 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5457 if (node->rest == NULL) {
5458 node->rest = target;
5460 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5461 pm_node_list_append(&node->rights, target);
5463 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5464 if (node->rest == NULL) {
5465 node->rest = target;
5467 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5468 pm_node_list_append(&node->rights, target);
5470 } else if (node->rest == NULL) {
5471 pm_node_list_append(&node->lefts, target);
5473 pm_node_list_append(&node->rights, target);
5476 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
5477 PM_NODE_START_SET_NODE(node, target);
5480 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
5481 PM_NODE_LENGTH_SET_NODE(node, target);
5489pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
5490 PM_NODE_START_SET_TOKEN(parser, node, lparen);
5491 PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
5492 node->lparen_loc = TOK2LOC(parser, lparen);
5499pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
5500 PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
5501 node->rparen_loc = TOK2LOC(parser, rparen);
5507static pm_multi_write_node_t *
5508pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5509 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
5510 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5512 *node = (pm_multi_write_node_t) {
5513 .base = PM_NODE_INIT(parser, PM_MULTI_WRITE_NODE, flags, PM_LOCATION_INIT_NODES(target, value)),
5514 .lefts = target->lefts,
5515 .rest = target->rest,
5516 .rights = target->rights,
5517 .lparen_loc = target->lparen_loc,
5518 .rparen_loc = target->rparen_loc,
5519 .operator_loc = TOK2LOC(parser, operator),
5523 // Explicitly do not call pm_node_destroy here because we want to keep
5524 // around all of the information within the MultiWriteNode node.
5525 xfree_sized(target, sizeof(pm_multi_target_node_t));
5533static pm_next_node_t *
5534pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5535 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5536 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
5538 *node = (pm_next_node_t) {
5539 .base = PM_NODE_INIT(parser, PM_NEXT_NODE, 0, (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments)),
5540 .keyword_loc = TOK2LOC(parser, keyword),
5541 .arguments = arguments
5550static pm_nil_node_t *
5551pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5552 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5553 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
5555 *node = (pm_nil_node_t) {
5556 .base = PM_NODE_INIT(parser, PM_NIL_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token))
5565static pm_no_block_parameter_node_t *
5566pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5567 assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5568 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5569 pm_no_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_block_parameter_node_t);
5571 *node = (pm_no_block_parameter_node_t) {
5572 .base = PM_NODE_INIT(parser, PM_NO_BLOCK_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, operator, keyword)),
5573 .operator_loc = TOK2LOC(parser, operator),
5574 .keyword_loc = TOK2LOC(parser, keyword)
5583static pm_no_keywords_parameter_node_t *
5584pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5585 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5586 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5587 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
5589 *node = (pm_no_keywords_parameter_node_t) {
5590 .base = PM_NODE_INIT(parser, PM_NO_KEYWORDS_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, operator, keyword)),
5591 .operator_loc = TOK2LOC(parser, operator),
5592 .keyword_loc = TOK2LOC(parser, keyword)
5601static pm_numbered_parameters_node_t *
5602pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
5603 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
5605 *node = (pm_numbered_parameters_node_t) {
5606 .base = PM_NODE_INIT(parser, PM_NUMBERED_PARAMETERS_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
5617#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5626pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5627 const uint8_t *start = token->start + 1;
5628 const uint8_t *end = token->end;
5630 ptrdiff_t diff = end - start;
5632#if PTRDIFF_MAX > SIZE_MAX
5633 assert(diff < (ptrdiff_t) SIZE_MAX);
5635 size_t length = (size_t) diff;
5637 char *digits = xcalloc(length + 1, sizeof(char));
5638 memcpy(digits, start, length);
5639 digits[length] = '\0';
5643 unsigned long value = strtoul(digits, &endptr, 10);
5645 if ((digits == endptr) || (*endptr != '\0')) {
5646 pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
5650 xfree_sized(digits, sizeof(char) * (length + 1));
5652 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5653 PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5657 return (uint32_t) value;
5665static pm_numbered_reference_read_node_t *
5666pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5667 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5668 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
5670 *node = (pm_numbered_reference_read_node_t) {
5671 .base = PM_NODE_INIT(parser, PM_NUMBERED_REFERENCE_READ_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, name)),
5672 .number = pm_numbered_reference_read_node_number(parser, name)
5681static pm_optional_parameter_node_t *
5682pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5683 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
5685 *node = (pm_optional_parameter_node_t) {
5686 .base = PM_NODE_INIT(parser, PM_OPTIONAL_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKEN_NODE(parser, name, value)),
5687 .name = pm_parser_constant_id_token(parser, name),
5688 .name_loc = TOK2LOC(parser, name),
5689 .operator_loc = TOK2LOC(parser, operator),
5699static pm_or_node_t *
5700pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5701 pm_assert_value_expression(parser, left);
5703 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
5705 *node = (pm_or_node_t) {
5706 .base = PM_NODE_INIT(parser, PM_OR_NODE, 0, PM_LOCATION_INIT_NODES(left, right)),
5709 .operator_loc = TOK2LOC(parser, operator)
5718static pm_parameters_node_t *
5719pm_parameters_node_create(pm_parser_t *parser) {
5720 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
5722 *node = (pm_parameters_node_t) {
5723 .base = PM_NODE_INIT(parser, PM_PARAMETERS_NODE, 0, PM_LOCATION_INIT_UNSET),
5725 .keyword_rest = NULL,
5740pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5741 if ((params->base.location.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
5742 PM_NODE_START_SET_NODE(params, param);
5745 if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
5746 PM_NODE_LENGTH_SET_NODE(params, param);
5754pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
5755 pm_parameters_node_location_set(params, param);
5756 pm_node_list_append(¶ms->requireds, param);
5763pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
5764 pm_parameters_node_location_set(params, UP(param));
5765 pm_node_list_append(¶ms->optionals, UP(param));
5772pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
5773 pm_parameters_node_location_set(params, param);
5774 pm_node_list_append(¶ms->posts, param);
5781pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5782 pm_parameters_node_location_set(params, param);
5783 params->rest = param;
5790pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
5791 pm_parameters_node_location_set(params, param);
5792 pm_node_list_append(¶ms->keywords, param);
5799pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5800 assert(params->keyword_rest == NULL);
5801 pm_parameters_node_location_set(params, param);
5802 params->keyword_rest = param;
5809pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
5810 assert(params->block == NULL);
5811 pm_parameters_node_location_set(params, param);
5812 params->block = param;
5818static pm_program_node_t *
5819pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
5820 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
5822 *node = (pm_program_node_t) {
5823 .base = PM_NODE_INIT(parser, PM_PROGRAM_NODE, 0, PM_LOCATION_INIT_NODE(statements)),
5825 .statements = statements
5834static pm_parentheses_node_t *
5835pm_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) {
5836 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
5838 *node = (pm_parentheses_node_t) {
5839 .base = PM_NODE_INIT(parser, PM_PARENTHESES_NODE, flags, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
5841 .opening_loc = TOK2LOC(parser, opening),
5842 .closing_loc = TOK2LOC(parser, closing)
5851static pm_pinned_expression_node_t *
5852pm_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) {
5853 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
5855 *node = (pm_pinned_expression_node_t) {
5856 .base = PM_NODE_INIT(parser, PM_PINNED_EXPRESSION_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, operator, rparen)),
5857 .expression = expression,
5858 .operator_loc = TOK2LOC(parser, operator),
5859 .lparen_loc = TOK2LOC(parser, lparen),
5860 .rparen_loc = TOK2LOC(parser, rparen)
5869static pm_pinned_variable_node_t *
5870pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
5871 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
5873 *node = (pm_pinned_variable_node_t) {
5874 .base = PM_NODE_INIT(parser, PM_PINNED_VARIABLE_NODE, 0, PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable)),
5875 .variable = variable,
5876 .operator_loc = TOK2LOC(parser, operator)
5885static pm_post_execution_node_t *
5886pm_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) {
5887 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
5889 *node = (pm_post_execution_node_t) {
5890 .base = PM_NODE_INIT(parser, PM_POST_EXECUTION_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, keyword, closing)),
5891 .statements = statements,
5892 .keyword_loc = TOK2LOC(parser, keyword),
5893 .opening_loc = TOK2LOC(parser, opening),
5894 .closing_loc = TOK2LOC(parser, closing)
5903static pm_pre_execution_node_t *
5904pm_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) {
5905 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
5907 *node = (pm_pre_execution_node_t) {
5908 .base = PM_NODE_INIT(parser, PM_PRE_EXECUTION_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, keyword, closing)),
5909 .statements = statements,
5910 .keyword_loc = TOK2LOC(parser, keyword),
5911 .opening_loc = TOK2LOC(parser, opening),
5912 .closing_loc = TOK2LOC(parser, closing)
5921static pm_range_node_t *
5922pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5923 pm_assert_value_expression(parser, left);
5924 pm_assert_value_expression(parser, right);
5926 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
5927 pm_node_flags_t flags = 0;
5929 // Indicate that this node is an exclusive range if the operator is `...`.
5930 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
5931 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
5934 // Indicate that this node is a static literal (i.e., can be compiled with
5935 // a putobject in CRuby) if the left and right are implicit nil, explicit
5936 // nil, or integers.
5938 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
5939 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
5941 flags |= PM_NODE_FLAG_STATIC_LITERAL;
5944 uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
5945 uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
5947 *node = (pm_range_node_t) {
5948 .base = PM_NODE_INIT(parser, PM_RANGE_NODE, flags, ((pm_location_t) { .start = start, .length = U32(end - start) })),
5951 .operator_loc = TOK2LOC(parser, operator)
5960static pm_redo_node_t *
5961pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
5962 assert(token->type == PM_TOKEN_KEYWORD_REDO);
5963 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
5965 *node = (pm_redo_node_t) {
5966 .base = PM_NODE_INIT(parser, PM_REDO_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token))
5976static pm_regular_expression_node_t *
5977pm_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) {
5978 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
5979 pm_node_flags_t flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL;
5981 *node = (pm_regular_expression_node_t) {
5982 .base = PM_NODE_INIT(parser, PM_REGULAR_EXPRESSION_NODE, flags, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
5983 .opening_loc = TOK2LOC(parser, opening),
5984 .content_loc = TOK2LOC(parser, content),
5985 .closing_loc = TOK2LOC(parser, closing),
5986 .unescaped = *unescaped
5995static inline pm_regular_expression_node_t *
5996pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
5997 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6003static pm_required_parameter_node_t *
6004pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6005 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6007 *node = (pm_required_parameter_node_t) {
6008 .base = PM_NODE_INIT(parser, PM_REQUIRED_PARAMETER_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token)),
6009 .name = pm_parser_constant_id_token(parser, token)
6018static pm_rescue_modifier_node_t *
6019pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6020 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6022 *node = (pm_rescue_modifier_node_t) {
6023 .base = PM_NODE_INIT(parser, PM_RESCUE_MODIFIER_NODE, 0, PM_LOCATION_INIT_NODES(expression, rescue_expression)),
6024 .expression = expression,
6025 .keyword_loc = TOK2LOC(parser, keyword),
6026 .rescue_expression = rescue_expression
6035static pm_rescue_node_t *
6036pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6037 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6039 *node = (pm_rescue_node_t) {
6040 .base = PM_NODE_INIT(parser, PM_RESCUE_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, keyword)),
6041 .keyword_loc = TOK2LOC(parser, keyword),
6042 .operator_loc = { 0 },
6043 .then_keyword_loc = { 0 },
6054pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
6055 node->operator_loc = TOK2LOC(parser, operator);
6062pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6063 node->reference = reference;
6064 PM_NODE_LENGTH_SET_NODE(node, reference);
6071pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6072 node->statements = statements;
6073 if (pm_statements_node_body_length(statements) > 0) {
6074 PM_NODE_LENGTH_SET_NODE(node, statements);
6082pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6083 node->subsequent = subsequent;
6084 PM_NODE_LENGTH_SET_NODE(node, subsequent);
6091pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6092 pm_node_list_append(&node->exceptions, exception);
6093 PM_NODE_LENGTH_SET_NODE(node, exception);
6099static pm_rest_parameter_node_t *
6100pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6101 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6103 *node = (pm_rest_parameter_node_t) {
6104 .base = PM_NODE_INIT(parser, PM_REST_PARAMETER_NODE, 0, (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name)),
6105 .name = name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
6106 .name_loc = NTOK2LOC(parser, name),
6107 .operator_loc = TOK2LOC(parser, operator)
6116static pm_retry_node_t *
6117pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6118 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6119 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6121 *node = (pm_retry_node_t) {
6122 .base = PM_NODE_INIT(parser, PM_RETRY_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token))
6131static pm_return_node_t *
6132pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6133 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6135 *node = (pm_return_node_t) {
6136 .base = PM_NODE_INIT(parser, PM_RETURN_NODE, 0, (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments)),
6137 .keyword_loc = TOK2LOC(parser, keyword),
6138 .arguments = arguments
6147static pm_self_node_t *
6148pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6149 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6150 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6152 *node = (pm_self_node_t) {
6153 .base = PM_NODE_INIT(parser, PM_SELF_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token))
6162static pm_shareable_constant_node_t *
6163pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6164 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6166 *node = (pm_shareable_constant_node_t) {
6167 .base = PM_NODE_INIT(parser, PM_SHAREABLE_CONSTANT_NODE, (pm_node_flags_t) value, PM_LOCATION_INIT_NODE(write)),
6177static pm_singleton_class_node_t *
6178pm_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) {
6179 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6181 *node = (pm_singleton_class_node_t) {
6182 .base = PM_NODE_INIT(parser, PM_SINGLETON_CLASS_NODE, 0, PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword)),
6184 .class_keyword_loc = TOK2LOC(parser, class_keyword),
6185 .operator_loc = TOK2LOC(parser, operator),
6186 .expression = expression,
6188 .end_keyword_loc = TOK2LOC(parser, end_keyword)
6197static pm_source_encoding_node_t *
6198pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6199 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6200 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6202 *node = (pm_source_encoding_node_t) {
6203 .base = PM_NODE_INIT(parser, PM_SOURCE_ENCODING_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token))
6212static pm_source_file_node_t*
6213pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6214 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6215 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6217 pm_node_flags_t flags = 0;
6219 switch (parser->frozen_string_literal) {
6220 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6221 flags |= PM_STRING_FLAGS_MUTABLE;
6223 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6224 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6228 *node = (pm_source_file_node_t) {
6229 .base = PM_NODE_INIT(parser, PM_SOURCE_FILE_NODE, flags, PM_LOCATION_INIT_TOKEN(parser, file_keyword)),
6230 .filepath = parser->filepath
6239static pm_source_line_node_t *
6240pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6241 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6242 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6244 *node = (pm_source_line_node_t) {
6245 .base = PM_NODE_INIT(parser, PM_SOURCE_LINE_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token))
6254static pm_splat_node_t *
6255pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6256 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6258 *node = (pm_splat_node_t) {
6259 .base = PM_NODE_INIT(parser, PM_SPLAT_NODE, 0, (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression)),
6260 .operator_loc = TOK2LOC(parser, operator),
6261 .expression = expression
6270static pm_statements_node_t *
6271pm_statements_node_create(pm_parser_t *parser) {
6272 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6274 *node = (pm_statements_node_t) {
6275 .base = PM_NODE_INIT(parser, PM_STATEMENTS_NODE, 0, PM_LOCATION_INIT_UNSET),
6286pm_statements_node_body_length(pm_statements_node_t *node) {
6287 return node && node->body.size;
6295pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6296 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6297 PM_NODE_START_SET_NODE(node, statement);
6300 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6301 PM_NODE_LENGTH_SET_NODE(node, statement);
6309pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6310 pm_statements_node_body_update(node, statement);
6312 if (node->body.size > 0) {
6313 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6315 switch (PM_NODE_TYPE(previous)) {
6320 case PM_RETURN_NODE:
6321 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6328 pm_node_list_append(&node->body, statement);
6329 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6336pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
6337 pm_statements_node_body_update(node, statement);
6338 pm_node_list_prepend(&node->body, statement);
6339 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6345static inline pm_string_node_t *
6346pm_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) {
6347 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
6348 pm_node_flags_t flags = 0;
6350 switch (parser->frozen_string_literal) {
6351 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6352 flags = PM_STRING_FLAGS_MUTABLE;
6354 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6355 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6359 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6360 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6362 *node = (pm_string_node_t) {
6363 .base = PM_NODE_INIT(parser, PM_STRING_NODE, flags, ((pm_location_t) { .start = start, .length = U32(end - start) })),
6364 .opening_loc = NTOK2LOC(parser, opening),
6365 .content_loc = TOK2LOC(parser, content),
6366 .closing_loc = NTOK2LOC(parser, closing),
6367 .unescaped = *string
6376static pm_string_node_t *
6377pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6378 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6385static pm_string_node_t *
6386pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6387 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6388 parser->current_string = PM_STRING_EMPTY;
6395static pm_super_node_t *
6396pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6397 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6398 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
6400 const pm_location_t *end = pm_arguments_end(arguments);
6401 assert(end != NULL && "unreachable");
6403 *node = (pm_super_node_t) {
6404 .base = PM_NODE_INIT(parser, PM_SUPER_NODE, 0, ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) })),
6405 .keyword_loc = TOK2LOC(parser, keyword),
6406 .lparen_loc = arguments->opening_loc,
6407 .arguments = arguments->arguments,
6408 .rparen_loc = arguments->closing_loc,
6409 .block = arguments->block
6420pm_ascii_only_p(const pm_string_t *contents) {
6421 const size_t length = pm_string_length(contents);
6422 const uint8_t *source = pm_string_source(contents);
6424 for (size_t index = 0; index < length; index++) {
6425 if (source[index] & 0x80) return false;
6435parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6436 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6437 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6440 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6453parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6454 const pm_encoding_t *encoding = parser->encoding;
6456 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6457 size_t width = encoding->char_width(cursor, end - cursor);
6460 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6477static inline pm_node_flags_t
6478parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6479 if (parser->explicit_encoding != NULL) {
6480 // A Symbol may optionally have its encoding explicitly set. This will
6481 // happen if an escape sequence results in a non-ASCII code point.
6482 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6483 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6484 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6485 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6486 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6487 } else if (validate) {
6488 parse_symbol_encoding_validate_other(parser, location, contents);
6490 } else if (pm_ascii_only_p(contents)) {
6491 // Ruby stipulates that all source files must use an ASCII-compatible
6492 // encoding. Thus, all symbols appearing in source are eligible for
6493 // "downgrading" to US-ASCII.
6494 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6495 } else if (validate) {
6496 parse_symbol_encoding_validate_other(parser, location, contents);
6502static pm_node_flags_t
6503parse_and_validate_regular_expression_encoding_modifier(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags, char modifier, const pm_encoding_t *modifier_encoding) {
6504 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
6505 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
6506 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
6507 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
6509 // There's special validation logic used if a string does not contain any character escape sequences.
6510 if (parser->explicit_encoding == NULL) {
6511 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
6512 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
6513 // the US-ASCII encoding.
6515 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
6518 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6520 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6522 } else if (parser->encoding != modifier_encoding) {
6523 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
6525 if (modifier == 'n' && !ascii_only) {
6526 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) pm_string_length(source), (const char *) pm_string_source(source));
6533 // TODO (nirvdrum 21-Feb-2024): To validate regexp sources with character escape sequences we need to know whether hex or Unicode escape sequences were used and Prism doesn't currently provide that data. We handle a subset of unambiguous cases in the meanwhile.
6534 bool mixed_encoding = false;
6536 if (mixed_encoding) {
6537 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6538 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
6539 // TODO (nirvdrum 21-Feb-2024): Validate the content is valid in the modifier encoding. Do this on-demand so we don't pay the cost of computation unnecessarily.
6540 bool valid_string_in_modifier_encoding = true;
6542 if (!valid_string_in_modifier_encoding) {
6543 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6545 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6546 // TODO (nirvdrum 21-Feb-2024): There's currently no way to tell if the source used hex or Unicode character escapes from `explicit_encoding` alone. If the source encoding was already UTF-8, both character escape types would set `explicit_encoding` to UTF-8, but need to be processed differently. Skip for now.
6547 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
6548 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, (int) pm_string_length(source), (const char *) pm_string_source(source));
6552 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
6562static pm_node_flags_t
6563parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
6564 // TODO (nirvdrum 22-Feb-2024): CRuby reports a special Regexp-specific error for invalid Unicode ranges. We either need to scan again or modify the "invalid Unicode escape sequence" message we already report.
6565 bool valid_unicode_range = true;
6566 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
6567 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_REGEXP_INVALID_UNICODE_RANGE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6571 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
6572 // to multi-byte characters are allowed.
6573 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
6574 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
6575 // following error message appearing twice. We do the same for compatibility.
6576 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6587 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
6588 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
6591 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
6592 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
6595 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
6596 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
6599 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
6600 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
6603 // At this point no encoding modifiers will be present on the regular expression as they would have already
6604 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
6605 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
6607 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
6610 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
6611 // or by specifying a modifier.
6613 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
6614 if (parser->explicit_encoding != NULL) {
6615 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6616 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
6617 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6618 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
6629static pm_symbol_node_t *
6630pm_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) {
6631 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6633 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6634 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6636 *node = (pm_symbol_node_t) {
6637 .base = PM_NODE_INIT(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | flags, ((pm_location_t) { .start = start, .length = U32(end - start) })),
6638 .opening_loc = NTOK2LOC(parser, opening),
6639 .value_loc = NTOK2LOC(parser, value),
6640 .closing_loc = NTOK2LOC(parser, closing),
6641 .unescaped = *unescaped
6650static inline pm_symbol_node_t *
6651pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6652 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6658static pm_symbol_node_t *
6659pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6660 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));
6661 parser->current_string = PM_STRING_EMPTY;
6668static pm_symbol_node_t *
6669pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6670 assert(token->type == PM_TOKEN_LABEL);
6672 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6673 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6674 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6676 assert((label.end - label.start) >= 0);
6677 pm_string_shared_init(&node->unescaped, label.start, label.end);
6678 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
6686static pm_symbol_node_t *
6687pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6688 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6690 *node = (pm_symbol_node_t) {
6691 .base = PM_NODE_INIT(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING, PM_LOCATION_INIT_UNSET),
6696 pm_string_constant_init(&node->unescaped, content, strlen(content));
6704pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6705 const pm_location_t *location = NULL;
6707 switch (PM_NODE_TYPE(node)) {
6708 case PM_SYMBOL_NODE: {
6709 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6710 if (cast->closing_loc.length > 0) {
6711 location = &cast->closing_loc;
6715 case PM_INTERPOLATED_SYMBOL_NODE: {
6716 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6717 if (cast->closing_loc.length > 0) {
6718 location = &cast->closing_loc;
6726 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6732static pm_symbol_node_t *
6733pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6734 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6736 *new_node = (pm_symbol_node_t) {
6737 .base = PM_NODE_INIT(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
6738 .opening_loc = TOK2LOC(parser, opening),
6739 .value_loc = node->content_loc,
6740 .closing_loc = TOK2LOC(parser, closing),
6741 .unescaped = node->unescaped
6744 pm_token_t content = {
6745 .type = PM_TOKEN_IDENTIFIER,
6746 .start = parser->start + node->content_loc.start,
6747 .end = parser->start + node->content_loc.start + node->content_loc.length
6750 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
6752 // We are explicitly _not_ using pm_node_destroy here because we don't want
6753 // to trash the unescaped string. We could instead copy the string if we
6754 // know that it is owned, but we're taking the fast path for now.
6755 xfree_sized(node, sizeof(pm_string_node_t));
6763static pm_string_node_t *
6764pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6765 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
6766 pm_node_flags_t flags = 0;
6768 switch (parser->frozen_string_literal) {
6769 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6770 flags = PM_STRING_FLAGS_MUTABLE;
6772 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6773 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6777 *new_node = (pm_string_node_t) {
6778 .base = PM_NODE_INIT(parser, PM_STRING_NODE, flags, PM_LOCATION_INIT_NODE(node)),
6779 .opening_loc = node->opening_loc,
6780 .content_loc = node->value_loc,
6781 .closing_loc = node->closing_loc,
6782 .unescaped = node->unescaped
6785 // We are explicitly _not_ using pm_node_destroy here because we don't want
6786 // to trash the unescaped string. We could instead copy the string if we
6787 // know that it is owned, but we're taking the fast path for now.
6788 xfree_sized(node, sizeof(pm_symbol_node_t));
6796static pm_true_node_t *
6797pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6798 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6799 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6801 *node = (pm_true_node_t) {
6802 .base = PM_NODE_INIT(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_TOKEN(parser, token))
6811static pm_true_node_t *
6812pm_true_node_synthesized_create(pm_parser_t *parser) {
6813 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6815 *node = (pm_true_node_t) {
6816 .base = PM_NODE_INIT(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL, PM_LOCATION_INIT_UNSET)
6825static pm_undef_node_t *
6826pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6827 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6828 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
6830 *node = (pm_undef_node_t) {
6831 .base = PM_NODE_INIT(parser, PM_UNDEF_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, token)),
6832 .keyword_loc = TOK2LOC(parser, token),
6843pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
6844 PM_NODE_LENGTH_SET_NODE(node, name);
6845 pm_node_list_append(&node->names, name);
6851static pm_unless_node_t *
6852pm_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) {
6853 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6855 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6856 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6858 *node = (pm_unless_node_t) {
6859 .base = PM_NODE_INIT(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end)),
6860 .keyword_loc = TOK2LOC(parser, keyword),
6861 .predicate = predicate,
6862 .then_keyword_loc = NTOK2LOC(parser, then_keyword),
6863 .statements = statements,
6864 .else_clause = NULL,
6865 .end_keyword_loc = { 0 }
6874static pm_unless_node_t *
6875pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6876 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6877 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6879 pm_statements_node_t *statements = pm_statements_node_create(parser);
6880 pm_statements_node_body_append(parser, statements, statement, true);
6882 *node = (pm_unless_node_t) {
6883 .base = PM_NODE_INIT(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, PM_LOCATION_INIT_NODES(statement, predicate)),
6884 .keyword_loc = TOK2LOC(parser, unless_keyword),
6885 .predicate = predicate,
6886 .then_keyword_loc = { 0 },
6887 .statements = statements,
6888 .else_clause = NULL,
6889 .end_keyword_loc = { 0 }
6896pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
6897 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
6898 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
6907pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
6908 assert(parser->current_block_exits != NULL);
6910 // All of the block exits that we want to remove should be within the
6911 // statements, and since we are modifying the statements, we shouldn't have
6912 // to check the end location.
6913 uint32_t start = statements->base.location.start;
6915 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
6916 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
6917 if (block_exit->location.start < start) break;
6919 // Implicitly remove from the list by lowering the size.
6920 parser->current_block_exits->size--;
6927static pm_until_node_t *
6928pm_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) {
6929 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6930 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6932 *node = (pm_until_node_t) {
6933 .base = PM_NODE_INIT(parser, PM_UNTIL_NODE, flags, PM_LOCATION_INIT_TOKENS(parser, keyword, closing)),
6934 .keyword_loc = TOK2LOC(parser, keyword),
6935 .do_keyword_loc = NTOK2LOC(parser, do_keyword),
6936 .closing_loc = TOK2LOC(parser, closing),
6937 .predicate = predicate,
6938 .statements = statements
6947static pm_until_node_t *
6948pm_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) {
6949 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6950 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6951 pm_loop_modifier_block_exits(parser, statements);
6953 *node = (pm_until_node_t) {
6954 .base = PM_NODE_INIT(parser, PM_UNTIL_NODE, flags, PM_LOCATION_INIT_NODES(statements, predicate)),
6955 .keyword_loc = TOK2LOC(parser, keyword),
6956 .do_keyword_loc = { 0 },
6957 .closing_loc = { 0 },
6958 .predicate = predicate,
6959 .statements = statements
6968static pm_when_node_t *
6969pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6970 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
6972 *node = (pm_when_node_t) {
6973 .base = PM_NODE_INIT(parser, PM_WHEN_NODE, 0, PM_LOCATION_INIT_TOKEN(parser, keyword)),
6974 .keyword_loc = TOK2LOC(parser, keyword),
6976 .then_keyword_loc = { 0 },
6987pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
6988 PM_NODE_LENGTH_SET_NODE(node, condition);
6989 pm_node_list_append(&node->conditions, condition);
6996pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
6997 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
6998 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
7005pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7006 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
7007 PM_NODE_LENGTH_SET_NODE(node, statements);
7010 node->statements = statements;
7016static pm_while_node_t *
7017pm_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) {
7018 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7019 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7021 *node = (pm_while_node_t) {
7022 .base = PM_NODE_INIT(parser, PM_WHILE_NODE, flags, PM_LOCATION_INIT_TOKENS(parser, keyword, closing)),
7023 .keyword_loc = TOK2LOC(parser, keyword),
7024 .do_keyword_loc = NTOK2LOC(parser, do_keyword),
7025 .closing_loc = TOK2LOC(parser, closing),
7026 .predicate = predicate,
7027 .statements = statements
7036static pm_while_node_t *
7037pm_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) {
7038 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7039 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7040 pm_loop_modifier_block_exits(parser, statements);
7042 *node = (pm_while_node_t) {
7043 .base = PM_NODE_INIT(parser, PM_WHILE_NODE, flags, PM_LOCATION_INIT_NODES(statements, predicate)),
7044 .keyword_loc = TOK2LOC(parser, keyword),
7045 .do_keyword_loc = { 0 },
7046 .closing_loc = { 0 },
7047 .predicate = predicate,
7048 .statements = statements
7057static pm_while_node_t *
7058pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7059 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7061 *node = (pm_while_node_t) {
7062 .base = PM_NODE_INIT(parser, PM_WHILE_NODE, 0, PM_LOCATION_INIT_UNSET),
7063 .keyword_loc = { 0 },
7064 .do_keyword_loc = { 0 },
7065 .closing_loc = { 0 },
7066 .predicate = predicate,
7067 .statements = statements
7077static pm_x_string_node_t *
7078pm_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) {
7079 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7081 *node = (pm_x_string_node_t) {
7082 .base = PM_NODE_INIT(parser, PM_X_STRING_NODE, PM_STRING_FLAGS_FROZEN, PM_LOCATION_INIT_TOKENS(parser, opening, closing)),
7083 .opening_loc = TOK2LOC(parser, opening),
7084 .content_loc = TOK2LOC(parser, content),
7085 .closing_loc = TOK2LOC(parser, closing),
7086 .unescaped = *unescaped
7095static inline pm_x_string_node_t *
7096pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7097 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7103static pm_yield_node_t *
7104pm_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) {
7105 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7107 uint32_t start = PM_TOKEN_START(parser, keyword);
7110 if (rparen_loc->length > 0) {
7111 end = PM_LOCATION_END(rparen_loc);
7112 } else if (arguments != NULL) {
7113 end = PM_NODE_END(arguments);
7114 } else if (lparen_loc->length > 0) {
7115 end = PM_LOCATION_END(lparen_loc);
7117 end = PM_TOKEN_END(parser, keyword);
7120 *node = (pm_yield_node_t) {
7121 .base = PM_NODE_INIT(parser, PM_YIELD_NODE, 0, ((pm_location_t) { .start = start, .length = U32(end - start) })),
7122 .keyword_loc = TOK2LOC(parser, keyword),
7123 .lparen_loc = *lparen_loc,
7124 .arguments = arguments,
7125 .rparen_loc = *rparen_loc
7136pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7137 pm_scope_t *scope = parser->current_scope;
7140 while (scope != NULL) {
7141 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7142 if (scope->closed) break;
7144 scope = scope->previous;
7157pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7158 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7165pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7166 pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
7172static pm_constant_id_t
7173pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7174 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
7175 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7182static inline pm_constant_id_t
7183pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
7184 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
7190static inline pm_constant_id_t
7191pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7192 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
7198static pm_constant_id_t
7199pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7200 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7201 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7208static pm_constant_id_t
7209pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7210 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7211 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7223pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7224 // We want to check whether the parameter name is a numbered parameter or
7226 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7228 // Otherwise we'll fetch the constant id for the parameter name and check
7229 // whether it's already in the current scope.
7230 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7232 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7233 // Add an error if the parameter doesn't start with _ and has been seen before
7234 if ((name->start < name->end) && (*name->start != '_')) {
7235 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7246pm_parser_scope_pop(pm_parser_t *parser) {
7247 pm_scope_t *scope = parser->current_scope;
7248 parser->current_scope = scope->previous;
7249 pm_locals_free(&scope->locals);
7250 pm_node_list_free(&scope->implicit_parameters);
7251 xfree_sized(scope, sizeof(pm_scope_t));
7254/******************************************************************************/
7256/******************************************************************************/
7262pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7263 *stack = (*stack << 1) | (value & 1);
7270pm_state_stack_pop(pm_state_stack_t *stack) {
7278pm_state_stack_p(const pm_state_stack_t *stack) {
7283pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7284 // Use the negation of the value to prevent stack overflow.
7285 pm_state_stack_push(&parser->accepts_block_stack, !value);
7289pm_accepts_block_stack_pop(pm_parser_t *parser) {
7290 pm_state_stack_pop(&parser->accepts_block_stack);
7294pm_accepts_block_stack_p(pm_parser_t *parser) {
7295 return !pm_state_stack_p(&parser->accepts_block_stack);
7299pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7300 pm_state_stack_push(&parser->do_loop_stack, value);
7304pm_do_loop_stack_pop(pm_parser_t *parser) {
7305 pm_state_stack_pop(&parser->do_loop_stack);
7309pm_do_loop_stack_p(pm_parser_t *parser) {
7310 return pm_state_stack_p(&parser->do_loop_stack);
7313/******************************************************************************/
7314/* Lexer check helpers */
7315/******************************************************************************/
7321static inline uint8_t
7322peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7323 if (cursor < parser->end) {
7335static inline uint8_t
7336peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7337 return peek_at(parser, parser->current.end + offset);
7344static inline uint8_t
7345peek(const pm_parser_t *parser) {
7346 return peek_at(parser, parser->current.end);
7354match(pm_parser_t *parser, uint8_t value) {
7355 if (peek(parser) == value) {
7356 parser->current.end++;
7367match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7368 if (peek_at(parser, cursor) == '\n') {
7371 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7383match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7384 return match_eol_at(parser, parser->current.end + offset);
7393match_eol(pm_parser_t *parser) {
7394 return match_eol_at(parser, parser->current.end);
7400static inline const uint8_t *
7401next_newline(const uint8_t *cursor, ptrdiff_t length) {
7402 assert(length >= 0);
7404 // Note that it's okay for us to use memchr here to look for \n because none
7405 // of the encodings that we support have \n as a component of a multi-byte
7407 return memchr(cursor, '\n', (size_t) length);
7414ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7415 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));
7423parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7424 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7426 if (encoding != NULL) {
7427 if (parser->encoding != encoding) {
7428 parser->encoding = encoding;
7429 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7432 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7444parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7445 const uint8_t *cursor = parser->current.start + 1;
7446 const uint8_t *end = parser->current.end;
7448 bool separator = false;
7450 if (end - cursor <= 6) return;
7451 switch (cursor[6]) {
7452 case 'C': case 'c': cursor += 6; continue;
7453 case 'O': case 'o': cursor += 5; continue;
7454 case 'D': case 'd': cursor += 4; continue;
7455 case 'I': case 'i': cursor += 3; continue;
7456 case 'N': case 'n': cursor += 2; continue;
7457 case 'G': case 'g': cursor += 1; continue;
7464 if (pm_char_is_whitespace(*cursor)) break;
7467 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7473 if (++cursor >= end) return;
7474 } while (pm_char_is_whitespace(*cursor));
7476 if (separator) break;
7477 if (*cursor != '=' && *cursor != ':') return;
7483 const uint8_t *value_start = cursor;
7484 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7486 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7487 // If we were unable to parse the encoding value, then we've got an
7488 // issue because we didn't understand the encoding that the user was
7489 // trying to use. In this case we'll keep using the default encoding but
7490 // add an error to the parser to indicate an unsuccessful parse.
7491 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7496 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7497 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7498 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7499} pm_magic_comment_boolean_value_t;
7505static pm_magic_comment_boolean_value_t
7506parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7507 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7508 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7509 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7510 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7512 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7517pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7518 return b == '\'' || b == '"' || b == ':' || b == ';';
7526static inline const uint8_t *
7527parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7528 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
7529 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
7548parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7551 const uint8_t *start = parser->
current.start + 1;
7552 const uint8_t *end = parser->
current.end;
7553 if (end - start <= 7)
return false;
7555 const uint8_t *cursor;
7556 bool indicator =
false;
7558 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7561 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7572 while (cursor < end) {
7573 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7575 const uint8_t *key_start = cursor;
7576 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7578 const uint8_t *key_end = cursor;
7579 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7580 if (cursor == end)
break;
7582 if (*cursor ==
':') {
7585 if (!indicator)
return false;
7589 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7590 if (cursor == end)
break;
7592 const uint8_t *value_start;
7593 const uint8_t *value_end;
7595 if (*cursor ==
'"') {
7596 value_start = ++cursor;
7597 for (; cursor < end && *cursor !=
'"'; cursor++) {
7598 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7601 if (cursor < end && *cursor ==
'"') cursor++;
7603 value_start = cursor;
7604 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7609 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7611 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7612 if (cursor != end)
return false;
7618 const size_t key_length = (size_t) (key_end - key_start);
7622 pm_string_shared_init(&key, key_start, key_end);
7624 uint8_t *buffer =
xmalloc(key_length);
7625 if (buffer == NULL)
break;
7627 memcpy(buffer, key_start, key_length);
7628 buffer[dash - key_start] =
'_';
7630 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
7631 buffer[dash - key_start] =
'_';
7634 pm_string_owned_init(&key, buffer, key_length);
7640 uint32_t value_length = (uint32_t) (value_end - value_start);
7646 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7647 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7649 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7653 if (key_length == 11) {
7654 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7655 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7656 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7657 PM_PARSER_WARN_TOKEN_FORMAT(
7660 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7662 (
const char *) key_source,
7664 (
const char *) value_start
7667 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7670 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7675 }
else if (key_length == 21) {
7676 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7679 if (semantic_token_seen) {
7680 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7682 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7683 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7684 PM_PARSER_WARN_TOKEN_FORMAT(
7687 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7689 (
const char *) key_source,
7691 (
const char *) value_start
7694 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7697 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7703 }
else if (key_length == 24) {
7704 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7705 const uint8_t *cursor = parser->
current.start;
7706 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7708 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
7709 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7710 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7711 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7712 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7713 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7714 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7715 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7716 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7717 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7719 PM_PARSER_WARN_TOKEN_FORMAT(
7722 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7724 (
const char *) key_source,
7726 (
const char *) value_start
7752static const uint32_t context_terminators[] = {
7754 [
PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7757 [
PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7759 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7763 [
PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7764 [
PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7765 [
PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7766 [
PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7769 [
PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7770 [
PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7773 [
PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7778 [
PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7782 [
PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7784 [
PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7787 [
PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7790 [
PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7793 [
PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7797 [
PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7800 [
PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7803 [
PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7805 [
PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7812 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7823 while (context_node != NULL) {
7824 if (context_terminator(context_node->
context, token))
return context_node->
context;
7825 context_node = context_node->
prev;
7834 if (context_node == NULL)
return false;
7859 while (context_node != NULL) {
7860 if (context_node->
context == context)
return true;
7861 context_node = context_node->
prev;
7871 while (context_node != NULL) {
7872 switch (context_node->
context) {
7893 context_node = context_node->
prev;
7908 assert(
false &&
"unreachable");
7966 assert(
false &&
"unreachable");
7975pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
7976 if (invalid != NULL) {
7977 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
7978 pm_parser_err(parser, U32(invalid - parser->
start), 1, diag_id);
7983pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7984 const uint8_t *invalid = NULL;
7985 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
7986 pm_strspn_number_validate(parser,
string, length, invalid);
7991pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7992 const uint8_t *invalid = NULL;
7993 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
7994 pm_strspn_number_validate(parser,
string, length, invalid);
7999pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8000 const uint8_t *invalid = NULL;
8001 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8002 pm_strspn_number_validate(parser,
string, length, invalid);
8007pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8008 const uint8_t *invalid = NULL;
8009 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8010 pm_strspn_number_validate(parser,
string, length, invalid);
8014static pm_token_type_t
8015lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8016 pm_token_type_t
type = PM_TOKEN_INTEGER;
8020 if (peek(parser) ==
'.') {
8021 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8023 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8024 type = PM_TOKEN_FLOAT;
8034 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8035 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8038 if (pm_char_is_decimal_digit(peek(parser))) {
8040 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8042 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8044 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8046 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8052 type = PM_TOKEN_FLOAT;
8058static pm_token_type_t
8059lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8060 pm_token_type_t
type = PM_TOKEN_INTEGER;
8063 if (peek_offset(parser, -1) ==
'0') {
8064 switch (*parser->
current.end) {
8069 if (pm_char_is_decimal_digit(peek(parser))) {
8070 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8073 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8082 if (pm_char_is_binary_digit(peek(parser))) {
8083 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8086 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8096 if (pm_char_is_octal_digit(peek(parser))) {
8097 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8100 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8116 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8124 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8125 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8128 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8131 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8136 type = lex_optional_float_suffix(parser, seen_e);
8143 type = lex_optional_float_suffix(parser, seen_e);
8150 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8153 type = lex_optional_float_suffix(parser, seen_e);
8159 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8160 const uint8_t *fraction_start = parser->
current.end;
8161 const uint8_t *fraction_end = parser->
current.end + 2;
8162 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8163 pm_parser_err(parser, U32(fraction_start - parser->
start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
8169static pm_token_type_t
8171 pm_token_type_t
type = PM_TOKEN_INTEGER;
8175 bool seen_e =
false;
8176 type = lex_numeric_prefix(parser, &seen_e);
8178 const uint8_t *end = parser->
current.end;
8179 pm_token_type_t suffix_type =
type;
8181 if (
type == PM_TOKEN_INTEGER) {
8182 if (match(parser,
'r')) {
8183 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8185 if (match(parser,
'i')) {
8186 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8188 }
else if (match(parser,
'i')) {
8189 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8192 if (!seen_e && match(parser,
'r')) {
8193 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8195 if (match(parser,
'i')) {
8196 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8198 }
else if (match(parser,
'i')) {
8199 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8203 const uint8_t b = peek(parser);
8204 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8214static pm_token_type_t
8217 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8218 return PM_TOKEN_GLOBAL_VARIABLE;
8223 bool allow_multiple =
true;
8225 switch (*parser->
current.end) {
8243 return PM_TOKEN_GLOBAL_VARIABLE;
8250 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8256 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8259 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8263 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->
current, diag_id);
8266 return PM_TOKEN_GLOBAL_VARIABLE;
8279 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8283 allow_multiple =
false;
8288 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8291 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8292 }
else if (pm_char_is_whitespace(peek(parser))) {
8295 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8301 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);
8304 return PM_TOKEN_GLOBAL_VARIABLE;
8321static inline pm_token_type_t
8322lex_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) {
8323 if (memcmp(current_start, value, vlen) == 0) {
8326 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
8327 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8329 lex_state_set(parser, state);
8330 if (state == PM_LEX_STATE_BEG) {
8334 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8335 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8336 return modifier_type;
8343 return PM_TOKEN_EOF;
8346static pm_token_type_t
8347lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8350 const uint8_t *end = parser->
end;
8351 const uint8_t *current_start = parser->
current.start;
8352 const uint8_t *current_end = parser->
current.end;
8355 if (encoding_changed) {
8356 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8357 current_end += width;
8360 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8361 current_end += width;
8364 parser->
current.end = current_end;
8368 width = (size_t) (current_end - current_start);
8370 if (current_end < end) {
8371 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8377 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8378 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8382 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8383 (void) match(parser,
':');
8384 return PM_TOKEN_LABEL;
8387 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8388 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8389 return PM_TOKEN_KEYWORD_DEFINED;
8393 return PM_TOKEN_METHOD_NAME;
8396 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,
'=')) {
8399 return PM_TOKEN_IDENTIFIER;
8403 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8404 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8408 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8409 (void) match(parser,
':');
8410 return PM_TOKEN_LABEL;
8414 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8415 pm_token_type_t
type;
8418 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8419 if (pm_do_loop_stack_p(parser)) {
8420 return PM_TOKEN_KEYWORD_DO_LOOP;
8422 return PM_TOKEN_KEYWORD_DO;
8425 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;
8426 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;
8427 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;
8430 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;
8431 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;
8432 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;
8433 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;
8434 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;
8435 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;
8436 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;
8439 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;
8440 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;
8441 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;
8442 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;
8443 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;
8444 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;
8445 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;
8446 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;
8449 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;
8450 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;
8451 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;
8452 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;
8453 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;
8454 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;
8455 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;
8456 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;
8457 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;
8458 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;
8459 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;
8460 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;
8461 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;
8464 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;
8465 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;
8466 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;
8467 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;
8468 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;
8471 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;
8472 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;
8475 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;
8480 if (encoding_changed) {
8481 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8483 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8509static pm_token_type_t
8510lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8513 if (pound + 1 >= parser->
end) {
8514 parser->
current.end = pound + 1;
8515 return PM_TOKEN_STRING_CONTENT;
8524 if (pound + 2 >= parser->
end) {
8525 parser->
current.end = pound + 1;
8526 return PM_TOKEN_STRING_CONTENT;
8531 const uint8_t *variable = pound + 2;
8532 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
8534 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
8538 if (pound > parser->
current.start) {
8540 return PM_TOKEN_STRING_CONTENT;
8545 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8546 parser->
current.end = pound + 1;
8547 return PM_TOKEN_EMBVAR;
8553 parser->
current.end = pound + 1;
8559 if (pound + 2 >= parser->
end) {
8560 parser->
current.end = pound + 1;
8561 return PM_TOKEN_STRING_CONTENT;
8567 const uint8_t *check = pound + 2;
8569 if (pound[2] ==
'-') {
8570 if (pound + 3 >= parser->
end) {
8571 parser->
current.end = pound + 2;
8572 return PM_TOKEN_STRING_CONTENT;
8583 char_is_identifier_start(parser, check, parser->
end - check) ||
8584 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8589 if (pound > parser->
current.start) {
8591 return PM_TOKEN_STRING_CONTENT;
8596 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8597 parser->
current.end = pound + 1;
8598 return PM_TOKEN_EMBVAR;
8603 parser->
current.end = pound + 1;
8609 if (pound > parser->
current.start) {
8611 return PM_TOKEN_STRING_CONTENT;
8618 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8619 parser->
current.end = pound + 2;
8621 pm_do_loop_stack_push(parser,
false);
8622 return PM_TOKEN_EMBEXPR_BEGIN;
8627 parser->
current.end = pound + 1;
8632static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8633static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8634static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8635static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8636static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8641static const bool ascii_printable_chars[] = {
8642 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8643 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8644 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8645 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8646 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8647 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8648 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8649 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8653char_is_ascii_printable(
const uint8_t b) {
8654 return (b < 0x80) && ascii_printable_chars[b];
8661static inline uint8_t
8662escape_hexadecimal_digit(
const uint8_t value) {
8663 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8671static inline uint32_t
8674 for (
size_t index = 0; index < length; index++) {
8675 if (index != 0) value <<= 4;
8676 value |= escape_hexadecimal_digit(
string[index]);
8681 if (value >= 0xD800 && value <= 0xDFFF) {
8682 if (error_location != NULL) {
8683 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
8685 pm_parser_err(parser, U32(
string - parser->
start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
8696static inline uint8_t
8697escape_byte(uint8_t value,
const uint8_t flags) {
8698 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8699 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8707escape_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) {
8711 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8713 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->
start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->
explicit_encoding->
name);
8719 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8720 pm_parser_err(parser, U32(start - parser->
start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
8721 pm_buffer_append_byte(buffer, 0xEF);
8722 pm_buffer_append_byte(buffer, 0xBF);
8723 pm_buffer_append_byte(buffer, 0xBD);
8735 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
8741 pm_buffer_append_byte(buffer,
byte);
8761 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8762 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
8765 escape_write_byte_encoded(parser, buffer,
byte);
8777 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
8781 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
8782 }
else if (width > 1) {
8784 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
8785 pm_buffer_append_bytes(b, parser->
current.end, width);
8791 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8801escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
8802#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
8804 PM_PARSER_WARN_TOKEN_FORMAT(
8807 PM_WARN_INVALID_CHARACTER,
8821 uint8_t peeked = peek(parser);
8825 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
8830 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
8835 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
8840 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
8845 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
8850 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
8855 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
8860 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
8865 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
8870 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
8875 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
8878 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
8879 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
8882 if (pm_char_is_octal_digit(peek(parser))) {
8883 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8886 if (pm_char_is_octal_digit(peek(parser))) {
8887 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
8892 value = escape_byte(value, flags);
8893 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
8897 const uint8_t *start = parser->
current.end - 1;
8900 uint8_t
byte = peek(parser);
8902 if (pm_char_is_hexadecimal_digit(
byte)) {
8903 uint8_t value = escape_hexadecimal_digit(
byte);
8906 byte = peek(parser);
8907 if (pm_char_is_hexadecimal_digit(
byte)) {
8908 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
8912 value = escape_byte(value, flags);
8913 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8914 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
8915 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
8917 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8921 escape_write_byte_encoded(parser, buffer, value);
8923 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
8929 const uint8_t *start = parser->
current.end - 1;
8933 const uint8_t *start = parser->
current.end - 2;
8934 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->
start), U32(parser->
current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8935 }
else if (peek(parser) ==
'{') {
8936 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
8941 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8942 parser->
current.end += whitespace;
8943 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
8954 const uint8_t *extra_codepoints_start = NULL;
8955 int codepoints_count = 0;
8958 const uint8_t *unicode_start = parser->
current.end;
8959 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
8961 if (hexadecimal_length > 6) {
8963 pm_parser_err(parser, U32(unicode_start - parser->
start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
8964 }
else if (hexadecimal_length == 0) {
8967 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8971 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8973 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->
current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
8974 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->
current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8980 parser->
current.end += hexadecimal_length;
8982 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
8983 extra_codepoints_start = unicode_start;
8986 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL);
8987 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
8994 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
8995 pm_parser_err(parser, U32(extra_codepoints_start - parser->
start), U32(parser->
current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
8999 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);
9000 }
else if (peek(parser) ==
'}') {
9003 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9007 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9009 pm_parser_err(parser, U32(unicode_codepoints_start - parser->
start), U32(parser->
current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9013 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9014 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9017 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9020 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9021 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9023 const uint8_t *start = parser->
current.end - 2;
9024 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->
start), U32(parser->
current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9026 }
else if (length == 4) {
9027 uint32_t value = escape_unicode(parser, parser->
current.end, 4, NULL);
9029 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9030 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9033 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9036 parser->
current.end += length;
9038 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9042 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9044 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9053 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9054 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9058 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9062 uint8_t peeked = peek(parser);
9066 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9072 if (match(parser,
'u') || match(parser,
'U')) {
9073 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9077 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9081 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9082 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9086 escape_read_warn(parser, flags, 0,
"\\t");
9087 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9090 if (!char_is_ascii_printable(peeked)) {
9091 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9096 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9103 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9104 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9107 if (peek(parser) !=
'-') {
9109 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9115 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9119 uint8_t peeked = peek(parser);
9123 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9129 if (match(parser,
'u') || match(parser,
'U')) {
9130 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9134 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9138 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9139 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9143 escape_read_warn(parser, flags, 0,
"\\t");
9144 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9147 if (!char_is_ascii_printable(peeked)) {
9149 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9154 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9161 if (flags & PM_ESCAPE_FLAG_META) {
9162 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9165 if (peek(parser) !=
'-') {
9167 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9173 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9177 uint8_t peeked = peek(parser);
9182 if (match(parser,
'u') || match(parser,
'U')) {
9183 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9187 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9191 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9192 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9196 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9197 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9200 if (!char_is_ascii_printable(peeked)) {
9202 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9207 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9212 if (peek_offset(parser, 1) ==
'\n') {
9214 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
9220 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9222 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9226 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9228 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9260static pm_token_type_t
9262 if (lex_state_end_p(parser)) {
9263 lex_state_set(parser, PM_LEX_STATE_BEG);
9264 return PM_TOKEN_QUESTION_MARK;
9268 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9270 return PM_TOKEN_CHARACTER_LITERAL;
9273 if (pm_char_is_whitespace(*parser->
current.end)) {
9274 lex_state_set(parser, PM_LEX_STATE_BEG);
9275 return PM_TOKEN_QUESTION_MARK;
9278 lex_state_set(parser, PM_LEX_STATE_BEG);
9280 if (match(parser,
'\\')) {
9281 lex_state_set(parser, PM_LEX_STATE_END);
9284 pm_buffer_init_capacity(&buffer, 3);
9286 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9289 return PM_TOKEN_CHARACTER_LITERAL;
9298 (parser->
current.end + encoding_width >= parser->
end) ||
9299 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
9302 lex_state_set(parser, PM_LEX_STATE_END);
9303 parser->
current.end += encoding_width;
9305 return PM_TOKEN_CHARACTER_LITERAL;
9309 return PM_TOKEN_QUESTION_MARK;
9316static pm_token_type_t
9318 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9319 const uint8_t *end = parser->
end;
9322 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9325 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9328 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
9329 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9331 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9335 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
9337 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9338 pm_parser_err_token(parser, &parser->
current, diag_id);
9344 lex_mode_pop(parser);
9366 if (comment == NULL)
return NULL;
9370 .location = TOK2LOC(parser, &parser->
current)
9381static pm_token_type_t
9384 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9386 if (newline == NULL) {
9389 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
9390 parser->
current.end = newline + 1;
9393 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
9394 parser_lex_callback(parser);
9397 const uint8_t *comment_start = parser->
current.start;
9398 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9399 if (comment == NULL)
return PM_TOKEN_EOF;
9403 while (parser->
current.end + 4 <= parser->
end) {
9409 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
9412 pm_char_is_whitespace(parser->
current.end[4]) ||
9413 (parser->
current.end[4] ==
'\0') ||
9414 (parser->
current.end[4] ==
'\004') ||
9415 (parser->
current.end[4] ==
'\032')
9418 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9420 if (newline == NULL) {
9423 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
9424 parser->
current.end = newline + 1;
9427 parser->
current.type = PM_TOKEN_EMBDOC_END;
9428 parser_lex_callback(parser);
9433 return PM_TOKEN_EMBDOC_END;
9438 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9440 if (newline == NULL) {
9443 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
9444 parser->
current.end = newline + 1;
9447 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
9448 parser_lex_callback(parser);
9451 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9456 return PM_TOKEN_EOF;
9466 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
9467 parser_lex_callback(parser);
9491 const uint8_t *cursor = parser->
current.end;
9493 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9494 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9557 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9574 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9579 return (width == 0 ? 1 : width);
9587 size_t width = parser_char_width(parser);
9588 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
9594 size_t width = parser_char_width(parser);
9601pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
9602 for (
size_t index = 0; index < length; index++) {
9603 if (value[index] & 0x80)
return false;
9638 if (token_buffer->
cursor == NULL) {
9641 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
9642 pm_token_buffer_copy(parser, token_buffer);
9654 pm_regexp_token_buffer_copy(parser, token_buffer);
9658#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9670 const uint8_t *start;
9671 if (token_buffer->
cursor == NULL) {
9672 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9673 start = parser->
current.start;
9675 start = token_buffer->
cursor;
9678 const uint8_t *end = parser->
current.end - 1;
9679 assert(end >= start);
9680 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9682 token_buffer->
cursor = end;
9687 const uint8_t *start;
9689 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9690 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9691 start = parser->
current.start;
9696 const uint8_t *end = parser->
current.end - 1;
9697 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9698 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9703#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9711 size_t whitespace = 0;
9714 case PM_HEREDOC_INDENT_NONE:
9719 case PM_HEREDOC_INDENT_DASH:
9721 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
9723 case PM_HEREDOC_INDENT_TILDE:
9726 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
9727 if (**cursor ==
'\t') {
9728 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
9747 size_t eol_length = match_eol(parser);
9754 parser_flush_heredoc_end(parser);
9757 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + U32(eol_length));
9760 uint8_t delimiter = *parser->
current.end;
9764 if (eol_length == 2) {
9765 delimiter = *(parser->
current.end + 1);
9768 parser->
current.end += eol_length;
9772 return *parser->
current.end++;
9779#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
9798 bool lexed_comment =
false;
9812 case PM_LEX_DEFAULT:
9813 case PM_LEX_EMBEXPR:
9830 bool space_seen =
false;
9834 bool chomping =
true;
9835 while (parser->
current.end < parser->
end && chomping) {
9836 switch (*parser->
current.end) {
9845 if (match_eol_offset(parser, 1)) {
9848 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->
current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
9854 size_t eol_length = match_eol_offset(parser, 1);
9860 parser->
current.end += eol_length + 1;
9861 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current));
9864 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
9888 lex_mode_pop(parser);
9889 goto switch_lex_modes;
9905 switch (*parser->
current.end++) {
9913 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9914 parser->
current.end = ending == NULL ? parser->
end : ending;
9919 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
9922 if (ending) parser->
current.end++;
9923 parser->
current.type = PM_TOKEN_COMMENT;
9924 parser_lex_callback(parser);
9936 parser_lex_magic_comment_encoding(parser);
9940 lexed_comment =
true;
9946 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
9958 if (!lexed_comment) {
9959 parser->
current.end += eol_length - 1;
9963 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current));
9968 parser_flush_heredoc_end(parser);
9973 switch (lex_state_ignored_p(parser)) {
9974 case PM_IGNORED_NEWLINE_NONE:
9976 case PM_IGNORED_NEWLINE_PATTERN:
9978 if (!lexed_comment) parser_lex_ignored_newline(parser);
9979 lex_state_set(parser, PM_LEX_STATE_BEG);
9981 parser->
current.type = PM_TOKEN_NEWLINE;
9985 case PM_IGNORED_NEWLINE_ALL:
9986 if (!lexed_comment) parser_lex_ignored_newline(parser);
9987 lexed_comment =
false;
9988 goto lex_next_token;
9996 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
9998 if (next_content < parser->end) {
10004 if (next_content[0] ==
'#') {
10006 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10008 while (following && (following + 1 < parser->
end)) {
10010 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10014 if (peek_at(parser, following) !=
'#')
break;
10018 following = next_newline(following, parser->
end - following);
10023 if (lex_state_ignored_p(parser)) {
10024 if (!lexed_comment) parser_lex_ignored_newline(parser);
10025 lexed_comment =
false;
10026 goto lex_next_token;
10032 (peek_at(parser, following) ==
'.') ||
10033 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10035 if (!lexed_comment) parser_lex_ignored_newline(parser);
10036 lexed_comment =
false;
10037 goto lex_next_token;
10047 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10048 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10049 (peek_at(parser, following) ==
'a' && peek_at(parser, following + 1) ==
'n' && peek_at(parser, following + 2) ==
'd' && !char_is_identifier(parser, following + 3, parser->
end - (following + 3))) ||
10050 (peek_at(parser, following) ==
'o' && peek_at(parser, following + 1) ==
'r' && !char_is_identifier(parser, following + 2, parser->
end - (following + 2)))
10053 if (!lexed_comment) parser_lex_ignored_newline(parser);
10054 lexed_comment =
false;
10055 goto lex_next_token;
10061 if (next_content[0] ==
'.') {
10065 if (peek_at(parser, next_content + 1) ==
'.') {
10066 if (!lexed_comment) parser_lex_ignored_newline(parser);
10067 lex_state_set(parser, PM_LEX_STATE_BEG);
10069 parser->
current.type = PM_TOKEN_NEWLINE;
10073 if (!lexed_comment) parser_lex_ignored_newline(parser);
10074 lex_state_set(parser, PM_LEX_STATE_DOT);
10075 parser->
current.start = next_content;
10076 parser->
current.end = next_content + 1;
10083 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10084 if (!lexed_comment) parser_lex_ignored_newline(parser);
10085 lex_state_set(parser, PM_LEX_STATE_DOT);
10086 parser->
current.start = next_content;
10087 parser->
current.end = next_content + 2;
10089 LEX(PM_TOKEN_AMPERSAND_DOT);
10095 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10096 if (!lexed_comment) parser_lex_ignored_newline(parser);
10097 lex_state_set(parser, PM_LEX_STATE_BEG);
10098 parser->
current.start = next_content;
10099 parser->
current.end = next_content + 2;
10101 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10106 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10107 if (!lexed_comment) parser_lex_ignored_newline(parser);
10108 lex_state_set(parser, PM_LEX_STATE_BEG);
10109 parser->
current.start = next_content;
10110 parser->
current.end = next_content + 2;
10112 LEX(PM_TOKEN_PIPE_PIPE);
10118 peek_at(parser, next_content) ==
'a' &&
10119 peek_at(parser, next_content + 1) ==
'n' &&
10120 peek_at(parser, next_content + 2) ==
'd' &&
10121 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10123 if (!lexed_comment) parser_lex_ignored_newline(parser);
10124 lex_state_set(parser, PM_LEX_STATE_BEG);
10125 parser->
current.start = next_content;
10126 parser->
current.end = next_content + 3;
10129 LEX(PM_TOKEN_KEYWORD_AND);
10135 peek_at(parser, next_content) ==
'o' &&
10136 peek_at(parser, next_content + 1) ==
'r' &&
10137 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10139 if (!lexed_comment) parser_lex_ignored_newline(parser);
10140 lex_state_set(parser, PM_LEX_STATE_BEG);
10141 parser->
current.start = next_content;
10142 parser->
current.end = next_content + 2;
10145 LEX(PM_TOKEN_KEYWORD_OR);
10152 lex_state_set(parser, PM_LEX_STATE_BEG);
10154 parser->
current.type = PM_TOKEN_NEWLINE;
10155 if (!lexed_comment) parser_lex_callback(parser);
10165 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10166 LEX(PM_TOKEN_COMMA);
10170 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10172 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10173 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10177 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10178 pm_do_loop_stack_push(parser,
false);
10185 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10186 pm_do_loop_stack_pop(parser);
10187 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10191 lex_state_set(parser, PM_LEX_STATE_BEG);
10193 LEX(PM_TOKEN_SEMICOLON);
10198 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10200 if (lex_state_operator_p(parser)) {
10201 if (match(parser,
']')) {
10203 lex_state_set(parser, PM_LEX_STATE_ARG);
10204 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10207 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10211 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10212 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10215 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10216 pm_do_loop_stack_push(parser,
false);
10222 lex_state_set(parser, PM_LEX_STATE_END);
10223 pm_do_loop_stack_pop(parser);
10224 LEX(PM_TOKEN_BRACKET_RIGHT);
10228 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10233 lex_state_set(parser, PM_LEX_STATE_BEG);
10234 type = PM_TOKEN_LAMBDA_BEGIN;
10235 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10237 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10238 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10241 lex_state_set(parser, PM_LEX_STATE_BEG);
10242 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10245 lex_state_set(parser, PM_LEX_STATE_BEG);
10248 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10253 pm_do_loop_stack_push(parser,
false);
10261 pm_do_loop_stack_pop(parser);
10264 lex_mode_pop(parser);
10265 LEX(PM_TOKEN_EMBEXPR_END);
10269 lex_state_set(parser, PM_LEX_STATE_END);
10270 LEX(PM_TOKEN_BRACE_RIGHT);
10274 if (match(parser,
'*')) {
10275 if (match(parser,
'=')) {
10276 lex_state_set(parser, PM_LEX_STATE_BEG);
10277 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10280 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10282 if (lex_state_spcarg_p(parser, space_seen)) {
10283 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10284 type = PM_TOKEN_USTAR_STAR;
10285 }
else if (lex_state_beg_p(parser)) {
10286 type = PM_TOKEN_USTAR_STAR;
10287 }
else if (ambiguous_operator_p(parser, space_seen)) {
10288 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10291 if (lex_state_operator_p(parser)) {
10292 lex_state_set(parser, PM_LEX_STATE_ARG);
10294 lex_state_set(parser, PM_LEX_STATE_BEG);
10300 if (match(parser,
'=')) {
10301 lex_state_set(parser, PM_LEX_STATE_BEG);
10302 LEX(PM_TOKEN_STAR_EQUAL);
10305 pm_token_type_t
type = PM_TOKEN_STAR;
10307 if (lex_state_spcarg_p(parser, space_seen)) {
10308 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10309 type = PM_TOKEN_USTAR;
10310 }
else if (lex_state_beg_p(parser)) {
10311 type = PM_TOKEN_USTAR;
10312 }
else if (ambiguous_operator_p(parser, space_seen)) {
10313 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10316 if (lex_state_operator_p(parser)) {
10317 lex_state_set(parser, PM_LEX_STATE_ARG);
10319 lex_state_set(parser, PM_LEX_STATE_BEG);
10327 if (lex_state_operator_p(parser)) {
10328 lex_state_set(parser, PM_LEX_STATE_ARG);
10329 if (match(parser,
'@')) {
10330 LEX(PM_TOKEN_BANG);
10333 lex_state_set(parser, PM_LEX_STATE_BEG);
10336 if (match(parser,
'=')) {
10337 LEX(PM_TOKEN_BANG_EQUAL);
10340 if (match(parser,
'~')) {
10341 LEX(PM_TOKEN_BANG_TILDE);
10344 LEX(PM_TOKEN_BANG);
10349 current_token_starts_line(parser) &&
10351 memcmp(parser->
current.end,
"begin", 5) == 0 &&
10352 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10354 pm_token_type_t
type = lex_embdoc(parser);
10355 if (
type == PM_TOKEN_EOF) {
10359 goto lex_next_token;
10362 if (lex_state_operator_p(parser)) {
10363 lex_state_set(parser, PM_LEX_STATE_ARG);
10365 lex_state_set(parser, PM_LEX_STATE_BEG);
10368 if (match(parser,
'>')) {
10369 LEX(PM_TOKEN_EQUAL_GREATER);
10372 if (match(parser,
'~')) {
10373 LEX(PM_TOKEN_EQUAL_TILDE);
10376 if (match(parser,
'=')) {
10377 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10380 LEX(PM_TOKEN_EQUAL);
10384 if (match(parser,
'<')) {
10386 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10387 !lex_state_end_p(parser) &&
10388 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10390 const uint8_t *end = parser->
current.end;
10395 if (match(parser,
'-')) {
10396 indent = PM_HEREDOC_INDENT_DASH;
10398 else if (match(parser,
'~')) {
10399 indent = PM_HEREDOC_INDENT_TILDE;
10402 if (match(parser,
'`')) {
10403 quote = PM_HEREDOC_QUOTE_BACKTICK;
10405 else if (match(parser,
'"')) {
10406 quote = PM_HEREDOC_QUOTE_DOUBLE;
10408 else if (match(parser,
'\'')) {
10409 quote = PM_HEREDOC_QUOTE_SINGLE;
10412 const uint8_t *ident_start = parser->
current.end;
10417 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
10420 if (quote == PM_HEREDOC_QUOTE_NONE) {
10421 parser->
current.end += width;
10423 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
10424 parser->
current.end += width;
10430 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
10435 size_t ident_length = (size_t) (parser->
current.end - ident_start);
10436 bool ident_error =
false;
10438 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10439 pm_parser_err(parser, U32(ident_start - parser->
start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10440 ident_error =
true;
10445 .mode = PM_LEX_HEREDOC,
10448 .ident_start = ident_start,
10449 .ident_length = ident_length,
10453 .next_start = parser->
current.end,
10455 .line_continuation =
false
10460 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10462 if (body_start == NULL) {
10467 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10468 body_start = parser->
end;
10472 pm_line_offset_list_append(&parser->
line_offsets, U32(body_start - parser->
start + 1));
10481 LEX(PM_TOKEN_HEREDOC_START);
10485 if (match(parser,
'=')) {
10486 lex_state_set(parser, PM_LEX_STATE_BEG);
10487 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10490 if (ambiguous_operator_p(parser, space_seen)) {
10491 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10494 if (lex_state_operator_p(parser)) {
10495 lex_state_set(parser, PM_LEX_STATE_ARG);
10497 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10498 lex_state_set(parser, PM_LEX_STATE_BEG);
10501 LEX(PM_TOKEN_LESS_LESS);
10504 if (lex_state_operator_p(parser)) {
10505 lex_state_set(parser, PM_LEX_STATE_ARG);
10507 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10508 lex_state_set(parser, PM_LEX_STATE_BEG);
10511 if (match(parser,
'=')) {
10512 if (match(parser,
'>')) {
10513 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10516 LEX(PM_TOKEN_LESS_EQUAL);
10519 LEX(PM_TOKEN_LESS);
10523 if (match(parser,
'>')) {
10524 if (lex_state_operator_p(parser)) {
10525 lex_state_set(parser, PM_LEX_STATE_ARG);
10527 lex_state_set(parser, PM_LEX_STATE_BEG);
10529 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10532 if (lex_state_operator_p(parser)) {
10533 lex_state_set(parser, PM_LEX_STATE_ARG);
10535 lex_state_set(parser, PM_LEX_STATE_BEG);
10538 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10542 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10543 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10544 LEX(PM_TOKEN_STRING_BEGIN);
10549 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10550 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10551 LEX(PM_TOKEN_BACKTICK);
10554 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10555 if (previous_command_start) {
10556 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10558 lex_state_set(parser, PM_LEX_STATE_ARG);
10561 LEX(PM_TOKEN_BACKTICK);
10564 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10565 LEX(PM_TOKEN_BACKTICK);
10570 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10571 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10572 LEX(PM_TOKEN_STRING_BEGIN);
10577 LEX(lex_question_mark(parser));
10581 if (match(parser,
'&')) {
10582 lex_state_set(parser, PM_LEX_STATE_BEG);
10584 if (match(parser,
'=')) {
10585 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10588 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10591 if (match(parser,
'=')) {
10592 lex_state_set(parser, PM_LEX_STATE_BEG);
10593 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10596 if (match(parser,
'.')) {
10597 lex_state_set(parser, PM_LEX_STATE_DOT);
10598 LEX(PM_TOKEN_AMPERSAND_DOT);
10601 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10602 if (lex_state_spcarg_p(parser, space_seen)) {
10603 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10604 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10606 const uint8_t delim = peek_offset(parser, 1);
10608 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
10609 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10613 type = PM_TOKEN_UAMPERSAND;
10614 }
else if (lex_state_beg_p(parser)) {
10615 type = PM_TOKEN_UAMPERSAND;
10616 }
else if (ambiguous_operator_p(parser, space_seen)) {
10617 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10620 if (lex_state_operator_p(parser)) {
10621 lex_state_set(parser, PM_LEX_STATE_ARG);
10623 lex_state_set(parser, PM_LEX_STATE_BEG);
10631 if (match(parser,
'|')) {
10632 if (match(parser,
'=')) {
10633 lex_state_set(parser, PM_LEX_STATE_BEG);
10634 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10637 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10639 LEX(PM_TOKEN_PIPE);
10642 lex_state_set(parser, PM_LEX_STATE_BEG);
10643 LEX(PM_TOKEN_PIPE_PIPE);
10646 if (match(parser,
'=')) {
10647 lex_state_set(parser, PM_LEX_STATE_BEG);
10648 LEX(PM_TOKEN_PIPE_EQUAL);
10651 if (lex_state_operator_p(parser)) {
10652 lex_state_set(parser, PM_LEX_STATE_ARG);
10654 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10657 LEX(PM_TOKEN_PIPE);
10661 if (lex_state_operator_p(parser)) {
10662 lex_state_set(parser, PM_LEX_STATE_ARG);
10664 if (match(parser,
'@')) {
10665 LEX(PM_TOKEN_UPLUS);
10668 LEX(PM_TOKEN_PLUS);
10671 if (match(parser,
'=')) {
10672 lex_state_set(parser, PM_LEX_STATE_BEG);
10673 LEX(PM_TOKEN_PLUS_EQUAL);
10677 lex_state_beg_p(parser) ||
10678 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
10680 lex_state_set(parser, PM_LEX_STATE_BEG);
10682 if (pm_char_is_decimal_digit(peek(parser))) {
10684 pm_token_type_t
type = lex_numeric(parser);
10685 lex_state_set(parser, PM_LEX_STATE_END);
10689 LEX(PM_TOKEN_UPLUS);
10692 if (ambiguous_operator_p(parser, space_seen)) {
10693 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
10696 lex_state_set(parser, PM_LEX_STATE_BEG);
10697 LEX(PM_TOKEN_PLUS);
10702 if (lex_state_operator_p(parser)) {
10703 lex_state_set(parser, PM_LEX_STATE_ARG);
10705 if (match(parser,
'@')) {
10706 LEX(PM_TOKEN_UMINUS);
10709 LEX(PM_TOKEN_MINUS);
10712 if (match(parser,
'=')) {
10713 lex_state_set(parser, PM_LEX_STATE_BEG);
10714 LEX(PM_TOKEN_MINUS_EQUAL);
10717 if (match(parser,
'>')) {
10718 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10719 LEX(PM_TOKEN_MINUS_GREATER);
10722 bool spcarg = lex_state_spcarg_p(parser, space_seen);
10723 bool is_beg = lex_state_beg_p(parser);
10724 if (!is_beg && spcarg) {
10725 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
10728 if (is_beg || spcarg) {
10729 lex_state_set(parser, PM_LEX_STATE_BEG);
10730 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
10733 if (ambiguous_operator_p(parser, space_seen)) {
10734 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
10737 lex_state_set(parser, PM_LEX_STATE_BEG);
10738 LEX(PM_TOKEN_MINUS);
10743 bool beg_p = lex_state_beg_p(parser);
10745 if (match(parser,
'.')) {
10746 if (match(parser,
'.')) {
10749 if (lex_state_p(parser, PM_LEX_STATE_END)) {
10750 lex_state_set(parser, PM_LEX_STATE_BEG);
10752 lex_state_set(parser, PM_LEX_STATE_ENDARG);
10754 LEX(PM_TOKEN_UDOT_DOT_DOT);
10758 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
10761 lex_state_set(parser, PM_LEX_STATE_BEG);
10762 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
10765 lex_state_set(parser, PM_LEX_STATE_BEG);
10766 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
10769 lex_state_set(parser, PM_LEX_STATE_DOT);
10784 pm_token_type_t
type = lex_numeric(parser);
10785 lex_state_set(parser, PM_LEX_STATE_END);
10791 if (match(parser,
':')) {
10792 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)) {
10793 lex_state_set(parser, PM_LEX_STATE_BEG);
10794 LEX(PM_TOKEN_UCOLON_COLON);
10797 lex_state_set(parser, PM_LEX_STATE_DOT);
10798 LEX(PM_TOKEN_COLON_COLON);
10801 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
10802 lex_state_set(parser, PM_LEX_STATE_BEG);
10803 LEX(PM_TOKEN_COLON);
10806 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
10807 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
10811 lex_state_set(parser, PM_LEX_STATE_FNAME);
10812 LEX(PM_TOKEN_SYMBOL_BEGIN);
10816 if (lex_state_beg_p(parser)) {
10817 lex_mode_push_regexp(parser,
'\0',
'/');
10818 LEX(PM_TOKEN_REGEXP_BEGIN);
10821 if (match(parser,
'=')) {
10822 lex_state_set(parser, PM_LEX_STATE_BEG);
10823 LEX(PM_TOKEN_SLASH_EQUAL);
10826 if (lex_state_spcarg_p(parser, space_seen)) {
10827 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
10828 lex_mode_push_regexp(parser,
'\0',
'/');
10829 LEX(PM_TOKEN_REGEXP_BEGIN);
10832 if (ambiguous_operator_p(parser, space_seen)) {
10833 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
10836 if (lex_state_operator_p(parser)) {
10837 lex_state_set(parser, PM_LEX_STATE_ARG);
10839 lex_state_set(parser, PM_LEX_STATE_BEG);
10842 LEX(PM_TOKEN_SLASH);
10846 if (lex_state_operator_p(parser)) {
10847 lex_state_set(parser, PM_LEX_STATE_ARG);
10849 lex_state_set(parser, PM_LEX_STATE_BEG);
10851 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
10855 if (lex_state_operator_p(parser)) {
10856 (void) match(parser,
'@');
10857 lex_state_set(parser, PM_LEX_STATE_ARG);
10859 lex_state_set(parser, PM_LEX_STATE_BEG);
10862 LEX(PM_TOKEN_TILDE);
10870 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
10871 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
10872 LEX(PM_TOKEN_PERCENT);
10875 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
10876 lex_state_set(parser, PM_LEX_STATE_BEG);
10877 LEX(PM_TOKEN_PERCENT_EQUAL);
10879 lex_state_beg_p(parser) ||
10880 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
10881 lex_state_spcarg_p(parser, space_seen)
10884 if (*parser->
current.end >= 0x80) {
10885 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10888 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10889 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10890 LEX(PM_TOKEN_STRING_BEGIN);
10895 uint8_t delimiter = peek_offset(parser, 1);
10897 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10898 goto lex_next_token;
10901 switch (peek(parser)) {
10906 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10908 lex_mode_push_list_eof(parser);
10911 LEX(PM_TOKEN_PERCENT_LOWER_I);
10917 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10919 lex_mode_push_list_eof(parser);
10922 LEX(PM_TOKEN_PERCENT_UPPER_I);
10928 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10929 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10931 lex_mode_push_regexp(parser,
'\0',
'\0');
10934 LEX(PM_TOKEN_REGEXP_BEGIN);
10940 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10941 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10943 lex_mode_push_string_eof(parser);
10946 LEX(PM_TOKEN_STRING_BEGIN);
10952 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10953 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10955 lex_mode_push_string_eof(parser);
10958 LEX(PM_TOKEN_STRING_BEGIN);
10964 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10965 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10966 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
10968 lex_mode_push_string_eof(parser);
10971 LEX(PM_TOKEN_SYMBOL_BEGIN);
10977 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10979 lex_mode_push_list_eof(parser);
10982 LEX(PM_TOKEN_PERCENT_LOWER_W);
10988 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10990 lex_mode_push_list_eof(parser);
10993 LEX(PM_TOKEN_PERCENT_UPPER_W);
10999 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11000 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11002 lex_mode_push_string_eof(parser);
11005 LEX(PM_TOKEN_PERCENT_LOWER_X);
11012 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11013 goto lex_next_token;
11017 if (ambiguous_operator_p(parser, space_seen)) {
11018 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11021 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11022 LEX(PM_TOKEN_PERCENT);
11027 pm_token_type_t
type = lex_global_variable(parser);
11032 lex_mode_pop(parser);
11035 lex_state_set(parser, PM_LEX_STATE_END);
11041 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11042 LEX(lex_at_variable(parser));
11045 if (*parser->
current.start !=
'_') {
11046 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11053 if (*parser->
current.start >= 0x80) {
11054 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11055 }
else if (*parser->
current.start ==
'\\') {
11056 switch (peek_at(parser, parser->
current.start + 1)) {
11059 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11063 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11067 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11071 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11074 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11076 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11081 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11084 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11085 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11087 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11090 goto lex_next_token;
11096 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11104 current_token_starts_line(parser) &&
11105 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11106 (parser->
current.end == parser->
end || match_eol(parser))
11111 const uint8_t *cursor = parser->
current.end;
11112 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11113 pm_line_offset_list_append(&parser->
line_offsets, U32(++cursor - parser->
start));
11117 parser->
current.type = PM_TOKEN___END__;
11118 parser_lex_callback(parser);
11128 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11129 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11130 if (previous_command_start) {
11131 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11133 lex_state_set(parser, PM_LEX_STATE_ARG);
11135 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11136 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11138 lex_state_set(parser, PM_LEX_STATE_END);
11143 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11144 (
type == PM_TOKEN_IDENTIFIER) &&
11145 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11146 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)))
11148 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11155 case PM_LEX_LIST: {
11169 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11170 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11177 if (whitespace > 0) {
11178 parser->
current.end += whitespace;
11179 if (peek_offset(parser, -1) ==
'\n') {
11181 parser_flush_heredoc_end(parser);
11183 LEX(PM_TOKEN_WORDS_SEP);
11195 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11196 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11202 while (breakpoint != NULL) {
11205 if (pm_char_is_whitespace(*breakpoint)) {
11206 parser->
current.end = breakpoint;
11207 pm_token_buffer_flush(parser, &token_buffer);
11208 LEX(PM_TOKEN_STRING_CONTENT);
11217 parser->
current.end = breakpoint + 1;
11218 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11225 if (breakpoint > parser->
current.start) {
11226 parser->
current.end = breakpoint;
11227 pm_token_buffer_flush(parser, &token_buffer);
11228 LEX(PM_TOKEN_STRING_CONTENT);
11233 parser->
current.end = breakpoint + 1;
11234 lex_mode_pop(parser);
11235 lex_state_set(parser, PM_LEX_STATE_END);
11236 LEX(PM_TOKEN_STRING_END);
11240 if (*breakpoint ==
'\0') {
11241 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11248 if (*breakpoint ==
'\\') {
11249 parser->
current.end = breakpoint + 1;
11258 pm_token_buffer_escape(parser, &token_buffer);
11259 uint8_t peeked = peek(parser);
11267 pm_token_buffer_push_byte(&token_buffer, peeked);
11272 if (peek(parser) !=
'\n') {
11273 pm_token_buffer_push_byte(&token_buffer,
'\r');
11278 pm_token_buffer_push_byte(&token_buffer,
'\n');
11284 parser_flush_heredoc_end(parser);
11285 pm_token_buffer_copy(parser, &token_buffer);
11286 LEX(PM_TOKEN_STRING_CONTENT);
11289 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
11296 pm_token_buffer_push_byte(&token_buffer, peeked);
11299 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11301 pm_token_buffer_push_byte(&token_buffer,
'\\');
11302 pm_token_buffer_push_escaped(&token_buffer, parser);
11309 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11314 if (*breakpoint ==
'#') {
11315 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11322 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11326 if (
type == PM_TOKEN_STRING_CONTENT) {
11327 pm_token_buffer_flush(parser, &token_buffer);
11336 parser->
current.end = breakpoint + 1;
11337 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11343 pm_token_buffer_flush(parser, &token_buffer);
11344 LEX(PM_TOKEN_STRING_CONTENT);
11350 pm_token_buffer_flush(parser, &token_buffer);
11351 LEX(PM_TOKEN_STRING_CONTENT);
11353 case PM_LEX_REGEXP: {
11375 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
11376 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11379 while (breakpoint != NULL) {
11381 bool is_terminator = (*breakpoint == term);
11386 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11387 if (term ==
'\n') {
11388 is_terminator =
true;
11394 if (term ==
'\r') {
11395 is_terminator =
false;
11401 if (is_terminator) {
11403 parser->
current.end = breakpoint + 1;
11404 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11412 if (breakpoint > parser->
current.start) {
11413 parser->
current.end = breakpoint;
11414 pm_regexp_token_buffer_flush(parser, &token_buffer);
11415 LEX(PM_TOKEN_STRING_CONTENT);
11419 size_t eol_length = match_eol_at(parser, breakpoint);
11421 parser->
current.end = breakpoint + eol_length;
11427 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current));
11430 parser->
current.end = breakpoint + 1;
11437 lex_mode_pop(parser);
11438 lex_state_set(parser, PM_LEX_STATE_END);
11439 LEX(PM_TOKEN_REGEXP_END);
11444 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
11445 parser->
current.end = breakpoint + 1;
11446 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11451 switch (*breakpoint) {
11454 parser->
current.end = breakpoint + 1;
11455 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11458 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11459 parser->
current.end = breakpoint + 1;
11460 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11465 parser->
current.end = breakpoint;
11466 pm_regexp_token_buffer_escape(parser, &token_buffer);
11474 pm_line_offset_list_append(&parser->
line_offsets, U32(breakpoint - parser->
start + 1));
11475 parser->
current.end = breakpoint + 1;
11476 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11480 parser->
current.end = breakpoint + 1;
11481 parser_flush_heredoc_end(parser);
11482 pm_regexp_token_buffer_flush(parser, &token_buffer);
11483 LEX(PM_TOKEN_STRING_CONTENT);
11488 parser->
current.end = breakpoint + 1;
11497 pm_regexp_token_buffer_escape(parser, &token_buffer);
11498 uint8_t peeked = peek(parser);
11503 if (peek(parser) !=
'\n') {
11505 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11507 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11508 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11517 parser_flush_heredoc_end(parser);
11518 pm_regexp_token_buffer_copy(parser, &token_buffer);
11519 LEX(PM_TOKEN_STRING_CONTENT);
11522 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
11540 case '$':
case ')':
case '*':
case '+':
11541 case '.':
case '>':
case '?':
case ']':
11542 case '^':
case '|':
case '}':
11543 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11549 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11550 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11555 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11556 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11561 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11567 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11574 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11578 if (
type == PM_TOKEN_STRING_CONTENT) {
11579 pm_regexp_token_buffer_flush(parser, &token_buffer);
11585 assert(
false &&
"unreachable");
11591 pm_regexp_token_buffer_flush(parser, &token_buffer);
11592 LEX(PM_TOKEN_STRING_CONTENT);
11598 pm_regexp_token_buffer_flush(parser, &token_buffer);
11599 LEX(PM_TOKEN_STRING_CONTENT);
11601 case PM_LEX_STRING: {
11620 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
11621 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11627 while (breakpoint != NULL) {
11632 parser->
current.end = breakpoint + 1;
11633 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11638 bool is_terminator = (*breakpoint == term);
11643 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11644 if (term ==
'\n') {
11645 is_terminator =
true;
11651 if (term ==
'\r') {
11652 is_terminator =
false;
11659 if (is_terminator) {
11663 parser->
current.end = breakpoint + 1;
11664 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11671 if (breakpoint > parser->
current.start) {
11672 parser->
current.end = breakpoint;
11673 pm_token_buffer_flush(parser, &token_buffer);
11674 LEX(PM_TOKEN_STRING_CONTENT);
11679 size_t eol_length = match_eol_at(parser, breakpoint);
11681 parser->
current.end = breakpoint + eol_length;
11687 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current));
11690 parser->
current.end = breakpoint + 1;
11693 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
11695 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
11696 lex_mode_pop(parser);
11697 LEX(PM_TOKEN_LABEL_END);
11704 parser_flush_heredoc_end(parser);
11707 lex_state_set(parser, PM_LEX_STATE_END);
11708 lex_mode_pop(parser);
11709 LEX(PM_TOKEN_STRING_END);
11712 switch (*breakpoint) {
11715 parser->
current.end = breakpoint + 1;
11716 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11719 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11720 parser->
current.end = breakpoint + 1;
11721 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11728 parser->
current.end = breakpoint;
11729 pm_token_buffer_escape(parser, &token_buffer);
11730 token_buffer.
cursor = breakpoint;
11739 pm_line_offset_list_append(&parser->
line_offsets, U32(breakpoint - parser->
start + 1));
11740 parser->
current.end = breakpoint + 1;
11741 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11745 parser->
current.end = breakpoint + 1;
11746 parser_flush_heredoc_end(parser);
11747 pm_token_buffer_flush(parser, &token_buffer);
11748 LEX(PM_TOKEN_STRING_CONTENT);
11751 parser->
current.end = breakpoint + 1;
11760 pm_token_buffer_escape(parser, &token_buffer);
11761 uint8_t peeked = peek(parser);
11765 pm_token_buffer_push_byte(&token_buffer,
'\\');
11770 if (peek(parser) !=
'\n') {
11772 pm_token_buffer_push_byte(&token_buffer,
'\\');
11774 pm_token_buffer_push_byte(&token_buffer,
'\r');
11780 pm_token_buffer_push_byte(&token_buffer,
'\\');
11781 pm_token_buffer_push_byte(&token_buffer,
'\n');
11788 parser_flush_heredoc_end(parser);
11789 pm_token_buffer_copy(parser, &token_buffer);
11790 LEX(PM_TOKEN_STRING_CONTENT);
11793 pm_line_offset_list_append(&parser->
line_offsets, PM_TOKEN_END(parser, &parser->
current) + 1);
11800 pm_token_buffer_push_byte(&token_buffer, peeked);
11803 pm_token_buffer_push_byte(&token_buffer, peeked);
11806 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11808 pm_token_buffer_push_byte(&token_buffer,
'\\');
11809 pm_token_buffer_push_escaped(&token_buffer, parser);
11816 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11820 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11827 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11831 if (
type == PM_TOKEN_STRING_CONTENT) {
11832 pm_token_buffer_flush(parser, &token_buffer);
11838 assert(
false &&
"unreachable");
11843 pm_token_buffer_flush(parser, &token_buffer);
11844 LEX(PM_TOKEN_STRING_CONTENT);
11850 pm_token_buffer_flush(parser, &token_buffer);
11851 LEX(PM_TOKEN_STRING_CONTENT);
11853 case PM_LEX_HEREDOC: {
11880 lex_state_set(parser, PM_LEX_STATE_END);
11881 lex_mode_pop(parser);
11882 LEX(PM_TOKEN_HEREDOC_END);
11885 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
11890 if (current_token_starts_line(parser)) {
11891 const uint8_t *start = parser->
current.start;
11893 if (!line_continuation && (start + ident_length <= parser->end)) {
11894 const uint8_t *newline = next_newline(start, parser->
end - start);
11895 const uint8_t *ident_end = newline;
11896 const uint8_t *terminator_end = newline;
11898 if (newline == NULL) {
11899 terminator_end = parser->
end;
11900 ident_end = parser->
end;
11903 if (newline[-1] ==
'\r') {
11908 const uint8_t *terminator_start = ident_end - ident_length;
11909 const uint8_t *cursor = start;
11911 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11912 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11918 (cursor == terminator_start) &&
11919 (memcmp(terminator_start, ident_start, ident_length) == 0)
11921 if (newline != NULL) {
11922 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
11925 parser->
current.end = terminator_end;
11933 lex_state_set(parser, PM_LEX_STATE_END);
11934 lex_mode_pop(parser);
11935 LEX(PM_TOKEN_HEREDOC_END);
11939 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
11941 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
11944 peek_at(parser, start) !=
'\n'
11953 uint8_t breakpoints[] =
"\r\n\\#";
11956 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11957 breakpoints[3] =
'\0';
11960 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11962 bool was_line_continuation =
false;
11964 while (breakpoint != NULL) {
11965 switch (*breakpoint) {
11968 parser->
current.end = breakpoint + 1;
11969 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11972 parser->
current.end = breakpoint + 1;
11974 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11975 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11982 pm_token_buffer_escape(parser, &token_buffer);
11983 token_buffer.
cursor = breakpoint;
11988 parser_flush_heredoc_end(parser);
11989 parser->
current.end = breakpoint + 1;
11990 pm_token_buffer_flush(parser, &token_buffer);
11991 LEX(PM_TOKEN_STRING_CONTENT);
11994 pm_line_offset_list_append(&parser->
line_offsets, U32(breakpoint - parser->
start + 1));
11998 const uint8_t *start = breakpoint + 1;
12000 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12003 const uint8_t *newline = next_newline(start, parser->
end - start);
12005 if (newline == NULL) {
12006 newline = parser->
end;
12007 }
else if (newline[-1] ==
'\r') {
12012 const uint8_t *terminator_start = newline - ident_length;
12016 const uint8_t *cursor = start;
12018 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12019 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12025 cursor == terminator_start &&
12026 (memcmp(terminator_start, ident_start, ident_length) == 0)
12028 parser->
current.end = breakpoint + 1;
12029 pm_token_buffer_flush(parser, &token_buffer);
12030 LEX(PM_TOKEN_STRING_CONTENT);
12034 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12041 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12046 parser->
current.end = breakpoint + 1;
12047 pm_token_buffer_flush(parser, &token_buffer);
12048 LEX(PM_TOKEN_STRING_CONTENT);
12053 parser->
current.end = breakpoint + 1;
12054 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12064 parser->
current.end = breakpoint + 1;
12073 pm_token_buffer_escape(parser, &token_buffer);
12074 uint8_t peeked = peek(parser);
12076 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12080 if (peek(parser) !=
'\n') {
12081 pm_token_buffer_push_byte(&token_buffer,
'\\');
12082 pm_token_buffer_push_byte(&token_buffer,
'\r');
12087 pm_token_buffer_push_byte(&token_buffer,
'\\');
12088 pm_token_buffer_push_byte(&token_buffer,
'\n');
12090 breakpoint = parser->
current.end;
12093 pm_token_buffer_push_byte(&token_buffer,
'\\');
12094 pm_token_buffer_push_escaped(&token_buffer, parser);
12101 if (peek(parser) !=
'\n') {
12102 pm_token_buffer_push_byte(&token_buffer,
'\r');
12110 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12111 const uint8_t *end = parser->
current.end;
12114 pm_line_offset_list_append(&parser->
line_offsets, U32(end - parser->
start + 1));
12119 parser->
current.end = breakpoint;
12120 pm_token_buffer_flush(parser, &token_buffer);
12124 parser->
current.end = end + 1;
12126 LEX(PM_TOKEN_STRING_CONTENT);
12129 was_line_continuation =
true;
12131 breakpoint = parser->
current.end;
12134 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12140 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12144 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12152 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12156 if (
type == PM_TOKEN_STRING_CONTENT) {
12157 pm_token_buffer_flush(parser, &token_buffer);
12163 assert(
false &&
"unreachable");
12166 was_line_continuation =
false;
12171 pm_token_buffer_flush(parser, &token_buffer);
12172 LEX(PM_TOKEN_STRING_CONTENT);
12178 pm_token_buffer_flush(parser, &token_buffer);
12179 LEX(PM_TOKEN_STRING_CONTENT);
12183 assert(
false &&
"unreachable");
12201 PM_BINDING_POWER_UNSET = 0,
12202 PM_BINDING_POWER_STATEMENT = 2,
12203 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12204 PM_BINDING_POWER_MODIFIER = 6,
12205 PM_BINDING_POWER_COMPOSITION = 8,
12206 PM_BINDING_POWER_NOT = 10,
12207 PM_BINDING_POWER_MATCH = 12,
12208 PM_BINDING_POWER_DEFINED = 14,
12209 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12210 PM_BINDING_POWER_ASSIGNMENT = 18,
12211 PM_BINDING_POWER_TERNARY = 20,
12212 PM_BINDING_POWER_RANGE = 22,
12213 PM_BINDING_POWER_LOGICAL_OR = 24,
12214 PM_BINDING_POWER_LOGICAL_AND = 26,
12215 PM_BINDING_POWER_EQUALITY = 28,
12216 PM_BINDING_POWER_COMPARISON = 30,
12217 PM_BINDING_POWER_BITWISE_OR = 32,
12218 PM_BINDING_POWER_BITWISE_AND = 34,
12219 PM_BINDING_POWER_SHIFT = 36,
12220 PM_BINDING_POWER_TERM = 38,
12221 PM_BINDING_POWER_FACTOR = 40,
12222 PM_BINDING_POWER_UMINUS = 42,
12223 PM_BINDING_POWER_EXPONENT = 44,
12224 PM_BINDING_POWER_UNARY = 46,
12225 PM_BINDING_POWER_INDEX = 48,
12226 PM_BINDING_POWER_CALL = 50,
12227 PM_BINDING_POWER_MAX = 52
12228} pm_binding_power_t;
12251#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12252#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12253#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12254#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12255#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12259 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12262 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12263 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12264 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12265 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12268 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12269 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12272 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12273 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12276 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12277 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12278 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12279 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12280 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12281 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12282 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12283 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12284 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12285 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12286 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12287 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12288 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12289 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12292 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12295 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12296 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12297 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12298 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12301 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12304 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12307 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12308 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12309 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12310 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12311 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12312 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12315 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12316 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12317 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12318 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12321 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12322 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12325 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12328 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12329 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12332 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12333 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12336 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12337 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12338 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12339 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12342 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12343 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12346 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12347 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12350 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12351 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12352 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12355 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12358 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12359 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12360 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12363#undef BINDING_POWER_ASSIGNMENT
12364#undef LEFT_ASSOCIATIVE
12365#undef RIGHT_ASSOCIATIVE
12366#undef RIGHT_ASSOCIATIVE_UNARY
12380match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12381 return match1(parser, type1) || match1(parser, type2);
12388match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12389 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12396match4(
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) {
12397 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12404match7(
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) {
12405 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
12412match8(
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) {
12413 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);
12424 if (match1(parser,
type)) {
12425 parser_lex(parser);
12436accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12437 if (match2(parser, type1, type2)) {
12438 parser_lex(parser);
12457 if (accept1(parser,
type))
return;
12460 pm_parser_err(parser, U32(location - parser->
start), 0, diag_id);
12472 if (accept2(parser, type1, type2))
return;
12475 pm_parser_err(parser, U32(location - parser->
start), 0, diag_id);
12486expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12487 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12488 parser_lex(parser);
12490 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12504 if (accept1(parser,
type))
return;
12506 const uint8_t *start = opening->
start;
12507 pm_parser_err(parser, U32(start - parser->
start), U32(opening->
end - start), diag_id);
12514parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth);
12521parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth) {
12522 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
12523 pm_assert_value_expression(parser, node);
12546token_begins_expression_p(pm_token_type_t
type) {
12548 case PM_TOKEN_EQUAL_GREATER:
12549 case PM_TOKEN_KEYWORD_IN:
12553 case PM_TOKEN_BRACE_RIGHT:
12554 case PM_TOKEN_BRACKET_RIGHT:
12555 case PM_TOKEN_COLON:
12556 case PM_TOKEN_COMMA:
12557 case PM_TOKEN_EMBEXPR_END:
12559 case PM_TOKEN_LAMBDA_BEGIN:
12560 case PM_TOKEN_KEYWORD_DO:
12561 case PM_TOKEN_KEYWORD_DO_LOOP:
12562 case PM_TOKEN_KEYWORD_END:
12563 case PM_TOKEN_KEYWORD_ELSE:
12564 case PM_TOKEN_KEYWORD_ELSIF:
12565 case PM_TOKEN_KEYWORD_ENSURE:
12566 case PM_TOKEN_KEYWORD_THEN:
12567 case PM_TOKEN_KEYWORD_RESCUE:
12568 case PM_TOKEN_KEYWORD_WHEN:
12569 case PM_TOKEN_NEWLINE:
12570 case PM_TOKEN_PARENTHESIS_RIGHT:
12571 case PM_TOKEN_SEMICOLON:
12577 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12579 case PM_TOKEN_UAMPERSAND:
12583 case PM_TOKEN_UCOLON_COLON:
12584 case PM_TOKEN_UMINUS:
12585 case PM_TOKEN_UMINUS_NUM:
12586 case PM_TOKEN_UPLUS:
12587 case PM_TOKEN_BANG:
12588 case PM_TOKEN_TILDE:
12589 case PM_TOKEN_UDOT_DOT:
12590 case PM_TOKEN_UDOT_DOT_DOT:
12597 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
12606parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
pm_diagnostic_id_t diag_id, uint16_t depth) {
12607 if (accept1(parser, PM_TOKEN_USTAR)) {
12609 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
12610 return UP(pm_splat_node_create(parser, &
operator, expression));
12613 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
12617pm_node_unreference_each(
const pm_node_t *node,
void *data) {
12618 switch (PM_NODE_TYPE(node)) {
12623 case PM_BREAK_NODE:
12625 case PM_REDO_NODE: {
12629 while (index < parser->current_block_exits->size) {
12632 if (block_exit == node) {
12655 case PM_LOCAL_VARIABLE_READ_NODE:
12656 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12660 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
12661 if (implicit_parameters->
nodes[index] == node) {
12665 if (index != implicit_parameters->
size - 1) {
12666 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
12669 implicit_parameters->
size--;
12688 pm_visit_node(node, pm_node_unreference_each, parser);
12702 size_t length = constant->
length;
12703 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
12704 if (name == NULL)
return;
12706 memcpy(name, constant->
start, length);
12707 name[length] =
'=';
12712 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
12723 switch (PM_NODE_TYPE(target)) {
12724 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12725 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12726 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12727 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12728 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12729 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12730 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
12734 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->
start + PM_NODE_START(target), parser->
start + PM_NODE_END(target));
12737 pm_node_destroy(parser, target);
12751 switch (PM_NODE_TYPE(target)) {
12752 case PM_MISSING_NODE:
12754 case PM_SOURCE_ENCODING_NODE:
12755 case PM_FALSE_NODE:
12756 case PM_SOURCE_FILE_NODE:
12757 case PM_SOURCE_LINE_NODE:
12760 case PM_TRUE_NODE: {
12763 return parse_unwriteable_target(parser, target);
12765 case PM_CLASS_VARIABLE_READ_NODE:
12767 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
12769 case PM_CONSTANT_PATH_NODE:
12770 if (context_def_p(parser)) {
12771 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12775 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
12778 case PM_CONSTANT_READ_NODE:
12779 if (context_def_p(parser)) {
12780 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12784 target->
type = PM_CONSTANT_TARGET_NODE;
12787 case PM_BACK_REFERENCE_READ_NODE:
12788 case PM_NUMBERED_REFERENCE_READ_NODE:
12789 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12791 case PM_GLOBAL_VARIABLE_READ_NODE:
12793 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
12795 case PM_LOCAL_VARIABLE_READ_NODE: {
12796 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
12797 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->
start + PM_NODE_START(target));
12798 pm_node_unreference(parser, target);
12802 uint32_t name = cast->
name;
12803 uint32_t depth = cast->
depth;
12804 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
12807 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
12811 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12813 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
12815 pm_node_unreference(parser, target);
12816 pm_node_destroy(parser, target);
12820 case PM_INSTANCE_VARIABLE_READ_NODE:
12822 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
12824 case PM_MULTI_TARGET_NODE:
12825 if (splat_parent) {
12828 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12832 case PM_SPLAT_NODE: {
12841 case PM_CALL_NODE: {
12853 (call->
block == NULL)
12866 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
12867 pm_node_destroy(parser, target);
12869 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
12873 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
12874 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
12877 parse_write_name(parser, &call->
name);
12878 return UP(pm_call_target_node_create(parser, call));
12885 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12886 return UP(pm_index_target_node_create(parser, call));
12894 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12905 pm_node_t *result = parse_target(parser, target, multiple,
false);
12910 !match1(parser, PM_TOKEN_EQUAL) &&
12912 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
12914 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
12928 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
12929 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
12940 switch (PM_NODE_TYPE(target)) {
12941 case PM_MISSING_NODE:
12942 pm_node_destroy(parser, value);
12944 case PM_CLASS_VARIABLE_READ_NODE: {
12946 pm_node_destroy(parser, target);
12949 case PM_CONSTANT_PATH_NODE: {
12952 if (context_def_p(parser)) {
12953 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12956 return parse_shareable_constant_write(parser, node);
12958 case PM_CONSTANT_READ_NODE: {
12961 if (context_def_p(parser)) {
12962 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12965 pm_node_destroy(parser, target);
12966 return parse_shareable_constant_write(parser, node);
12968 case PM_BACK_REFERENCE_READ_NODE:
12969 case PM_NUMBERED_REFERENCE_READ_NODE:
12970 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12972 case PM_GLOBAL_VARIABLE_READ_NODE: {
12974 pm_node_destroy(parser, target);
12977 case PM_LOCAL_VARIABLE_READ_NODE: {
12982 uint32_t depth = local_read->
depth;
12983 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
12985 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
12986 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
12987 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->
start + PM_NODE_START(target));
12988 pm_node_unreference(parser, target);
12991 pm_locals_unread(&scope->
locals, name);
12992 pm_node_destroy(parser, target);
12994 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
12996 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12998 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
13000 pm_node_unreference(parser, target);
13001 pm_node_destroy(parser, target);
13005 case PM_INSTANCE_VARIABLE_READ_NODE: {
13007 pm_node_destroy(parser, target);
13010 case PM_MULTI_TARGET_NODE:
13012 case PM_SPLAT_NODE: {
13020 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
13022 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
13024 case PM_CALL_NODE: {
13036 (call->
block == NULL)
13050 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
13051 pm_parser_local_add_location(parser, &message_loc, 0);
13052 pm_node_destroy(parser, target);
13054 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));
13055 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
13074 pm_arguments_node_arguments_append(arguments, value);
13075 PM_NODE_LENGTH_SET_NODE(call, arguments);
13076 call->
equal_loc = TOK2LOC(parser,
operator);
13078 parse_write_name(parser, &call->
name);
13079 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13088 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13090 call->
arguments = pm_arguments_node_create(parser);
13093 pm_arguments_node_arguments_append(call->
arguments, value);
13094 PM_NODE_LENGTH_SET_NODE(target, value);
13097 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13098 call->
equal_loc = TOK2LOC(parser,
operator);
13102 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13117 pm_node_unreference(parser, value);
13118 pm_node_destroy(parser, value);
13125 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13138 switch (PM_NODE_TYPE(target)) {
13139 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13140 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13141 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13142 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13143 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13144 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13145 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13152 pm_node_destroy(parser, target);
13167parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13168 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13171 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13173 while (accept1(parser, PM_TOKEN_COMMA)) {
13174 if (accept1(parser, PM_TOKEN_USTAR)) {
13179 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13185 if (token_begins_expression_p(parser->
current.type)) {
13186 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13187 name = parse_target(parser, name,
true,
true);
13190 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13191 pm_multi_target_node_targets_append(parser, result, splat);
13193 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13195 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13196 target = parse_target(parser, target,
true,
false);
13198 pm_multi_target_node_targets_append(parser, result, target);
13199 context_pop(parser);
13200 }
else if (token_begins_expression_p(parser->
current.type)) {
13201 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13202 target = parse_target(parser, target,
true,
false);
13204 pm_multi_target_node_targets_append(parser, result, target);
13205 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13209 pm_multi_target_node_targets_append(parser, result, rest);
13222parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13223 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13224 accept1(parser, PM_TOKEN_NEWLINE);
13227 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13228 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13241 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13244 if (context_terminator(context, &parser->
current))
return NULL;
13250 context_push(parser, context);
13253 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13254 pm_statements_node_body_append(parser, statements, node,
true);
13267 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13270 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13271 if (context_terminator(context, &parser->
current))
break;
13281 if (context_terminator(context, &parser->
current))
break;
13293 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
13294 parser_lex(parser);
13300 if (match1(parser, PM_TOKEN_EOF)) {
13305 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13306 if (context_terminator(context, &parser->
current))
break;
13307 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13317 context_pop(parser);
13318 bool last_value =
true;
13322 last_value =
false;
13327 pm_void_statements_check(parser, statements, last_value);
13340 if (duplicated != NULL) {
13344 pm_diagnostic_list_append_format(
13348 PM_WARN_DUPLICATED_HASH_KEY,
13366 if ((previous = pm_static_literals_add(&parser->
line_offsets, parser->
start, parser->
start_line, literals, node,
false)) != NULL) {
13367 pm_diagnostic_list_append_format(
13369 PM_NODE_START(node),
13370 PM_NODE_LENGTH(node),
13371 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13383 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13384 bool contains_keyword_splat =
false;
13389 switch (parser->
current.type) {
13390 case PM_TOKEN_USTAR_STAR: {
13391 parser_lex(parser);
13395 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
13401 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13402 }
else if (token_begins_expression_p(parser->
current.type)) {
13403 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13405 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13408 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13409 contains_keyword_splat =
true;
13412 case PM_TOKEN_LABEL: {
13414 parser_lex(parser);
13416 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13417 pm_hash_key_static_literals_add(parser, literals, key);
13421 if (token_begins_expression_p(parser->
current.type)) {
13422 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13425 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13426 value = UP(pm_constant_read_node_create(parser, &constant));
13431 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13432 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13434 depth = pm_parser_local_depth(parser, &identifier);
13438 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13440 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13445 value = UP(pm_implicit_node_create(parser, value));
13448 element = UP(pm_assoc_node_create(parser, key, NULL, value));
13452 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
13456 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13457 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13460 pm_hash_key_static_literals_add(parser, literals, key);
13463 if (!pm_symbol_node_label_p(parser, key)) {
13464 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13468 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13469 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
13474 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13481 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13485 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13489 if (token_begins_expression_p(parser->
current.type))
continue;
13495 return contains_keyword_splat;
13500 if (pm_symbol_node_label_p(parser, argument)) {
13504 switch (PM_NODE_TYPE(argument)) {
13505 case PM_CALL_NODE: {
13508 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13511 if (cast->
block != NULL) {
13519 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
13528 arguments->
arguments = pm_arguments_node_create(parser);
13531 pm_arguments_node_arguments_append(arguments->
arguments, argument);
13538parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
13539 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
13544 match2(parser, terminator, PM_TOKEN_EOF) ||
13545 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
13551 bool parsed_first_argument =
false;
13552 bool parsed_bare_hash =
false;
13553 bool parsed_block_argument =
false;
13554 bool parsed_forwarding_arguments =
false;
13556 while (!match1(parser, PM_TOKEN_EOF)) {
13557 if (parsed_forwarding_arguments) {
13558 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
13563 switch (parser->
current.type) {
13564 case PM_TOKEN_USTAR_STAR:
13565 case PM_TOKEN_LABEL: {
13566 if (parsed_bare_hash) {
13567 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
13571 argument = UP(hash);
13574 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
13576 parse_arguments_append(parser, arguments, argument);
13578 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13579 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13580 pm_node_flag_set(UP(arguments->
arguments), flags);
13582 pm_static_literals_free(&hash_keys);
13583 parsed_bare_hash =
true;
13587 case PM_TOKEN_UAMPERSAND: {
13588 parser_lex(parser);
13592 if (token_begins_expression_p(parser->
current.type)) {
13593 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13595 pm_parser_scope_forwarding_block_check(parser, &
operator);
13598 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
13599 if (parsed_block_argument) {
13600 parse_arguments_append(parser, arguments, argument);
13602 arguments->
block = argument;
13605 if (match1(parser, PM_TOKEN_COMMA)) {
13606 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
13609 parsed_block_argument =
true;
13612 case PM_TOKEN_USTAR: {
13613 parser_lex(parser);
13616 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
13617 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
13618 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
13619 if (parsed_bare_hash) {
13620 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13623 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
13625 if (parsed_bare_hash) {
13626 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);
13629 argument = UP(pm_splat_node_create(parser, &
operator, expression));
13632 parse_arguments_append(parser, arguments, argument);
13635 case PM_TOKEN_UDOT_DOT_DOT: {
13636 if (accepts_forwarding) {
13637 parser_lex(parser);
13639 if (token_begins_expression_p(parser->
current.type)) {
13644 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
13649 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
13651 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
13654 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
13656 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
13657 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
13658 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
13661 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->
previous));
13662 parse_arguments_append(parser, arguments, argument);
13663 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
13665 parsed_forwarding_arguments =
true;
13672 if (argument == NULL) {
13673 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13676 bool contains_keywords =
false;
13677 bool contains_keyword_splat =
false;
13679 if (argument_allowed_for_bare_hash(parser, argument)) {
13680 if (parsed_bare_hash) {
13681 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
13685 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
13690 contains_keywords =
true;
13694 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
13697 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13698 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
13700 pm_keyword_hash_node_elements_append(bare_hash, argument);
13701 argument = UP(bare_hash);
13704 if (accept1(parser, PM_TOKEN_COMMA) && (
13705 token_begins_expression_p(parser->
current.type) ||
13706 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
13708 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
13711 pm_static_literals_free(&hash_keys);
13712 parsed_bare_hash =
true;
13715 parse_arguments_append(parser, arguments, argument);
13717 pm_node_flags_t flags = 0;
13718 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13719 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13720 pm_node_flag_set(UP(arguments->
arguments), flags);
13726 parsed_first_argument =
true;
13729 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
13734 bool accepted_newline =
false;
13735 if (terminator != PM_TOKEN_EOF) {
13736 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
13739 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
13743 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
13746 if (accepted_newline) {
13747 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13753 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
13756 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13768 if (match1(parser, terminator))
break;
13783parse_required_destructured_parameter(
pm_parser_t *parser) {
13784 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
13787 pm_multi_target_node_opening_set(parser, node, &parser->
previous);
13796 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
13797 param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13798 pm_multi_target_node_targets_append(parser, node, param);
13799 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13803 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13804 param = UP(parse_required_destructured_parameter(parser));
13805 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
13809 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13811 value = UP(pm_required_parameter_node_create(parser, &name));
13812 if (pm_parser_parameter_name_check(parser, &name)) {
13813 pm_node_flag_set_repeated_parameter(value);
13815 pm_parser_local_add_token(parser, &name, 1);
13818 param = UP(pm_splat_node_create(parser, &star, value));
13820 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
13823 param = UP(pm_required_parameter_node_create(parser, &name));
13824 if (pm_parser_parameter_name_check(parser, &name)) {
13825 pm_node_flag_set_repeated_parameter(param);
13827 pm_parser_local_add_token(parser, &name, 1);
13830 pm_multi_target_node_targets_append(parser, node, param);
13831 }
while (accept1(parser, PM_TOKEN_COMMA));
13833 accept1(parser, PM_TOKEN_NEWLINE);
13834 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
13835 pm_multi_target_node_closing_set(parser, node, &parser->
previous);
13845 PM_PARAMETERS_NO_CHANGE = 0,
13846 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
13847 PM_PARAMETERS_ORDER_KEYWORDS_REST,
13848 PM_PARAMETERS_ORDER_KEYWORDS,
13849 PM_PARAMETERS_ORDER_REST,
13850 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13851 PM_PARAMETERS_ORDER_OPTIONAL,
13852 PM_PARAMETERS_ORDER_NAMED,
13853 PM_PARAMETERS_ORDER_NONE,
13854} pm_parameters_order_t;
13859static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
13860 [0] = PM_PARAMETERS_NO_CHANGE,
13861 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13862 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13863 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13864 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
13865 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
13866 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
13867 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
13868 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13869 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13870 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
13871 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
13883 pm_parameters_order_t state = parameters_ordering[token->type];
13884 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
13888 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13889 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
13891 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13895 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13896 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
13898 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
13899 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
13901 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
13903 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
13907 if (state < *current) *current = state;
13912parse_parameters_handle_trailing_comma(
13915 pm_parameters_order_t order,
13917 bool allows_trailing_comma
13919 if (!allows_trailing_comma) {
13920 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13925 if (order >= PM_PARAMETERS_ORDER_NAMED) {
13927 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13929 if (params->
rest == NULL) {
13930 pm_parameters_node_rest_set(params, param);
13932 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
13933 pm_parameters_node_posts_append(params, UP(param));
13937 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13943 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13954 pm_binding_power_t binding_power,
13955 bool uses_parentheses,
13956 bool allows_trailing_comma,
13957 bool allows_forwarding_parameters,
13958 bool accepts_blocks_in_defaults,
13963 pm_do_loop_stack_push(parser,
false);
13966 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
13969 bool parsing =
true;
13971 switch (parser->
current.type) {
13972 case PM_TOKEN_PARENTHESIS_LEFT: {
13973 update_parameter_state(parser, &parser->
current, &order);
13974 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
13976 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13977 pm_parameters_node_requireds_append(params, param);
13979 pm_parameters_node_posts_append(params, param);
13983 case PM_TOKEN_UAMPERSAND:
13984 case PM_TOKEN_AMPERSAND: {
13985 update_parameter_state(parser, &parser->
current, &order);
13986 parser_lex(parser);
13992 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->
previous);
13996 bool repeated =
false;
13997 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13999 repeated = pm_parser_parameter_name_check(parser, &name);
14000 pm_parser_local_add_token(parser, &name, 1);
14005 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
14007 pm_node_flag_set_repeated_parameter(param);
14011 if (params->
block == NULL) {
14012 pm_parameters_node_block_set(params, param);
14014 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
14015 pm_parameters_node_posts_append(params, param);
14020 case PM_TOKEN_UDOT_DOT_DOT: {
14021 if (!allows_forwarding_parameters) {
14022 pm_parser_err_current(parser, diag_id_forwarding);
14025 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14026 parser_lex(parser);
14035 pm_parameters_node_posts_append(params, keyword_rest);
14036 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14040 pm_parameters_node_keyword_rest_set(params, UP(param));
14043 case PM_TOKEN_CLASS_VARIABLE:
14044 case PM_TOKEN_IDENTIFIER:
14045 case PM_TOKEN_CONSTANT:
14046 case PM_TOKEN_INSTANCE_VARIABLE:
14047 case PM_TOKEN_GLOBAL_VARIABLE:
14048 case PM_TOKEN_METHOD_NAME: {
14049 parser_lex(parser);
14051 case PM_TOKEN_CONSTANT:
14052 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14054 case PM_TOKEN_INSTANCE_VARIABLE:
14055 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14057 case PM_TOKEN_GLOBAL_VARIABLE:
14058 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14060 case PM_TOKEN_CLASS_VARIABLE:
14061 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14063 case PM_TOKEN_METHOD_NAME:
14064 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14069 if (parser->
current.type == PM_TOKEN_EQUAL) {
14070 update_parameter_state(parser, &parser->
current, &order);
14072 update_parameter_state(parser, &parser->
previous, &order);
14076 bool repeated = pm_parser_parameter_name_check(parser, &name);
14077 pm_parser_local_add_token(parser, &name, 1);
14079 if (match1(parser, PM_TOKEN_EQUAL)) {
14082 parser_lex(parser);
14087 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14088 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14089 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14094 pm_node_flag_set_repeated_parameter(UP(param));
14096 pm_parameters_node_optionals_append(params, param);
14102 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
14105 context_pop(parser);
14114 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14117 pm_node_flag_set_repeated_parameter(UP(param));
14119 pm_parameters_node_requireds_append(params, UP(param));
14123 pm_node_flag_set_repeated_parameter(UP(param));
14125 pm_parameters_node_posts_append(params, UP(param));
14130 case PM_TOKEN_LABEL: {
14131 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14132 update_parameter_state(parser, &parser->
current, &order);
14135 parser_lex(parser);
14142 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14143 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14144 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14147 bool repeated = pm_parser_parameter_name_check(parser, &local);
14148 pm_parser_local_add_token(parser, &local, 1);
14150 switch (parser->
current.type) {
14151 case PM_TOKEN_COMMA:
14152 case PM_TOKEN_PARENTHESIS_RIGHT:
14153 case PM_TOKEN_PIPE: {
14154 context_pop(parser);
14156 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14158 pm_node_flag_set_repeated_parameter(param);
14161 pm_parameters_node_keywords_append(params, param);
14164 case PM_TOKEN_SEMICOLON:
14165 case PM_TOKEN_NEWLINE: {
14166 context_pop(parser);
14168 if (uses_parentheses) {
14173 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14175 pm_node_flag_set_repeated_parameter(param);
14178 pm_parameters_node_keywords_append(params, param);
14184 if (token_begins_expression_p(parser->
current.type)) {
14188 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14189 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14190 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14193 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
14196 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14199 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14203 pm_node_flag_set_repeated_parameter(param);
14206 context_pop(parser);
14207 pm_parameters_node_keywords_append(params, param);
14222 case PM_TOKEN_USTAR:
14223 case PM_TOKEN_STAR: {
14224 update_parameter_state(parser, &parser->
current, &order);
14225 parser_lex(parser);
14229 bool repeated =
false;
14231 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14233 repeated = pm_parser_parameter_name_check(parser, &name);
14234 pm_parser_local_add_token(parser, &name, 1);
14239 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14241 pm_node_flag_set_repeated_parameter(param);
14244 if (params->
rest == NULL) {
14245 pm_parameters_node_rest_set(params, param);
14247 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14248 pm_parameters_node_posts_append(params, param);
14253 case PM_TOKEN_STAR_STAR:
14254 case PM_TOKEN_USTAR_STAR: {
14255 pm_parameters_order_t previous_order = order;
14256 update_parameter_state(parser, &parser->
current, &order);
14257 parser_lex(parser);
14262 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14263 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14264 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14267 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
14271 bool repeated =
false;
14272 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14274 repeated = pm_parser_parameter_name_check(parser, &name);
14275 pm_parser_local_add_token(parser, &name, 1);
14280 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14282 pm_node_flag_set_repeated_parameter(param);
14287 pm_parameters_node_keyword_rest_set(params, param);
14289 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14290 pm_parameters_node_posts_append(params, param);
14297 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
14307 if (!parsing)
break;
14309 bool accepted_newline =
false;
14310 if (uses_parentheses) {
14311 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14314 if (accept1(parser, PM_TOKEN_COMMA)) {
14317 if (accepted_newline) {
14318 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14326 pm_do_loop_stack_pop(parser);
14329 if (PM_NODE_START(params) == PM_NODE_END(params)) {
14330 pm_node_destroy(parser, UP(params));
14353 return (
size_t) pm_line_offset_list_line(&parser->
line_offsets, PM_TOKEN_START(parser, &parser->
current), 0);
14362token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14364 const uint8_t *end = token->start;
14368 newline_index == 0 &&
14369 parser->
start[0] == 0xef &&
14370 parser->
start[1] == 0xbb &&
14371 parser->
start[2] == 0xbf
14374 int64_t column = 0;
14375 for (; cursor < end; cursor++) {
14378 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14385 if (break_on_non_space)
return -1;
14398parser_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) {
14403 size_t closing_newline_index = token_newline_index(parser);
14404 if (opening_newline_index == closing_newline_index)
return;
14409 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14410 if (!if_after_else && (opening_column == -1))
return;
14417 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14418 if ((closing_column == -1) || (opening_column == closing_column))
return;
14422 if (allow_indent && (closing_column > opening_column))
return;
14425 PM_PARSER_WARN_FORMAT(
14427 PM_TOKEN_START(parser, closing_token),
14428 PM_TOKEN_LENGTH(closing_token),
14429 PM_WARN_INDENTATION_MISMATCH,
14430 (
int) (closing_token->
end - closing_token->
start),
14431 (
const char *) closing_token->
start,
14432 (
int) (opening_token->
end - opening_token->
start),
14433 (
const char *) opening_token->
start,
14434 ((int32_t) opening_newline_index) + parser->
start_line
14439 PM_RESCUES_BEGIN = 1,
14446} pm_rescues_type_t;
14456 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
14457 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14458 parser_lex(parser);
14462 switch (parser->
current.type) {
14463 case PM_TOKEN_EQUAL_GREATER: {
14467 parser_lex(parser);
14468 pm_rescue_node_operator_set(parser, rescue, &parser->
previous);
14470 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14471 reference = parse_target(parser, reference,
false,
false);
14473 pm_rescue_node_reference_set(rescue, reference);
14476 case PM_TOKEN_NEWLINE:
14477 case PM_TOKEN_SEMICOLON:
14478 case PM_TOKEN_KEYWORD_THEN:
14483 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
14488 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
14489 pm_rescue_node_exceptions_append(rescue, expression);
14493 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
14497 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14498 pm_rescue_node_operator_set(parser, rescue, &parser->
previous);
14500 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14501 reference = parse_target(parser, reference,
false,
false);
14503 pm_rescue_node_reference_set(rescue, reference);
14506 }
while (accept1(parser, PM_TOKEN_COMMA));
14511 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14512 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
14516 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
14520 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
14521 pm_accepts_block_stack_push(parser,
true);
14536 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
14538 pm_accepts_block_stack_pop(parser);
14539 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14542 if (current == NULL) {
14543 pm_begin_node_rescue_clause_set(parent_node, rescue);
14545 pm_rescue_node_subsequent_set(current, rescue);
14554 if (current != NULL) {
14557 while (clause != NULL) {
14558 PM_NODE_LENGTH_SET_NODE(clause, current);
14564 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
14565 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14566 opening_newline_index = token_newline_index(parser);
14568 else_keyword = parser->
current;
14569 opening = &else_keyword;
14571 parser_lex(parser);
14572 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14575 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
14576 pm_accepts_block_stack_push(parser,
true);
14590 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14591 pm_accepts_block_stack_pop(parser);
14593 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14596 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
14597 pm_begin_node_else_clause_set(parent_node, else_clause);
14601 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
14604 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
14605 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14608 parser_lex(parser);
14609 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14612 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14613 pm_accepts_block_stack_push(parser,
true);
14627 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14628 pm_accepts_block_stack_pop(parser);
14630 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14633 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
14634 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
14637 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
14638 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14639 pm_begin_node_end_keyword_set(parser, parent_node, &parser->
current);
14642 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
14652 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
14653 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
14656 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->
current);
14665parse_block_parameters(
14667 bool allows_trailing_comma,
14669 bool is_lambda_literal,
14670 bool accepts_blocks_in_defaults,
14674 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
14675 if (!is_lambda_literal) {
14678 parameters = parse_parameters(
14680 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
14682 allows_trailing_comma,
14684 accepts_blocks_in_defaults,
14686 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
14687 (uint16_t) (depth + 1)
14689 if (!is_lambda_literal) {
14690 context_pop(parser);
14695 if (opening != NULL) {
14696 accept1(parser, PM_TOKEN_NEWLINE);
14698 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
14700 switch (parser->
current.type) {
14701 case PM_TOKEN_CONSTANT:
14702 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14703 parser_lex(parser);
14705 case PM_TOKEN_INSTANCE_VARIABLE:
14706 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14707 parser_lex(parser);
14709 case PM_TOKEN_GLOBAL_VARIABLE:
14710 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14711 parser_lex(parser);
14713 case PM_TOKEN_CLASS_VARIABLE:
14714 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14715 parser_lex(parser);
14718 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
14722 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
14723 pm_parser_local_add_token(parser, &parser->
previous, 1);
14726 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
14728 pm_block_parameters_node_append_local(block_parameters, local);
14729 }
while (accept1(parser, PM_TOKEN_COMMA));
14733 return block_parameters;
14741outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
14743 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
14754static const char *
const pm_numbered_parameter_names[] = {
14755 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
14769 if (parameters != NULL) {
14771 if (implicit_parameters->
size > 0) {
14774 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14775 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
14776 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14777 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
14779 assert(
false &&
"unreachable");
14788 if (implicit_parameters->
size == 0) {
14795 uint8_t numbered_parameter = 0;
14796 bool it_parameter =
false;
14798 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
14801 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14802 if (it_parameter) {
14803 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
14804 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
14805 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
14807 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
14808 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
14809 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->
start[node->
location.
start + 1] -
'0'));
14811 assert(
false &&
"unreachable");
14813 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14814 if (numbered_parameter > 0) {
14815 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
14817 it_parameter =
true;
14822 if (numbered_parameter > 0) {
14826 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
14828 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
14831 if (it_parameter) {
14832 return UP(pm_it_parameters_node_create(parser, opening, closing));
14842parse_block(
pm_parser_t *parser, uint16_t depth) {
14844 accept1(parser, PM_TOKEN_NEWLINE);
14846 pm_accepts_block_stack_push(parser,
true);
14847 pm_parser_scope_push(parser,
false);
14851 if (accept1(parser, PM_TOKEN_PIPE)) {
14853 if (match1(parser, PM_TOKEN_PIPE)) {
14854 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
14856 parser_lex(parser);
14858 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
14859 accept1(parser, PM_TOKEN_NEWLINE);
14861 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
14864 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->
previous);
14867 accept1(parser, PM_TOKEN_NEWLINE);
14870 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
14871 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
14875 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
14877 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14878 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
14879 pm_accepts_block_stack_push(parser,
true);
14881 pm_accepts_block_stack_pop(parser);
14884 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
14885 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
14886 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
14890 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
14894 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
14895 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->
previous);
14897 pm_parser_scope_pop(parser);
14898 pm_accepts_block_stack_pop(parser);
14900 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
14909parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
14910 bool found =
false;
14912 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14916 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14919 pm_accepts_block_stack_push(parser,
true);
14920 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
14922 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14928 pm_accepts_block_stack_pop(parser);
14931 }
else if (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)) {
14933 pm_accepts_block_stack_push(parser,
false);
14938 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
14943 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
14947 pm_accepts_block_stack_pop(parser);
14953 if (accepts_block) {
14956 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
14958 block = parse_block(parser, (uint16_t) (depth + 1));
14959 pm_arguments_validate_block(parser, arguments, block);
14960 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
14962 block = parse_block(parser, (uint16_t) (depth + 1));
14965 if (block != NULL) {
14967 arguments->
block = UP(block);
14969 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
14971 if (arguments->
block != NULL) {
14973 arguments->
arguments = pm_arguments_node_create(parser);
14975 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
14977 arguments->
block = UP(block);
14991 bool in_sclass =
false;
14993 switch (context_node->
context) {
15038 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15061 assert(
false &&
"unreachable");
15066 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15077 switch (context_node->
context) {
15152 assert(
false &&
"unreachable");
15166 return previous_block_exits;
15180 switch (PM_NODE_TYPE(block_exit)) {
15181 case PM_BREAK_NODE:
type =
"break";
break;
15182 case PM_NEXT_NODE:
type =
"next";
break;
15183 case PM_REDO_NODE:
type =
"redo";
break;
15184 default: assert(
false &&
"unreachable");
type =
"";
break;
15187 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15199 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15204 }
else if (previous_block_exits != NULL) {
15216 flush_block_exits(parser, previous_block_exits);
15224 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15227 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15229 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15230 predicate_closed =
true;
15234 if (!predicate_closed) {
15235 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15238 context_pop(parser);
15243parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15245 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15250 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15253 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15254 pm_accepts_block_stack_push(parser,
true);
15255 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15256 pm_accepts_block_stack_pop(parser);
15257 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15264 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15267 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
15270 assert(
false &&
"unreachable");
15279 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15280 if (parser_end_of_line_p(parser)) {
15281 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->
current, PM_WARN_KEYWORD_EOL);
15284 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15286 parser_lex(parser);
15288 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15289 pm_accepts_block_stack_push(parser,
true);
15292 pm_accepts_block_stack_pop(parser);
15293 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15295 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15301 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15302 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15303 opening_newline_index = token_newline_index(parser);
15305 parser_lex(parser);
15308 pm_accepts_block_stack_push(parser,
true);
15310 pm_accepts_block_stack_pop(parser);
15312 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15313 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15314 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
15316 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15320 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
15326 assert(
false &&
"unreachable");
15330 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15331 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
15338 bool recursing =
true;
15340 while (recursing) {
15341 switch (PM_NODE_TYPE(current)) {
15345 recursing = current != NULL;
15363 assert(
false &&
"unreachable");
15367 pop_block_exits(parser, previous_block_exits);
15368 pm_node_list_free(¤t_block_exits);
15377#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15378 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15379 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15380 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15381 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15382 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15383 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15384 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15385 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15386 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15387 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15393#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15394 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15395 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15396 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15397 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15398 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15399 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15400 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15407#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15408 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15409 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15410 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15411 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15412 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15413 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15414 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15415 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15421#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15422 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15423 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15424 case PM_TOKEN_CLASS_VARIABLE
15430#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15431 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15432 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15433 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15437PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15443static inline pm_node_flags_t
15444parse_unescaped_encoding(
const pm_parser_t *parser) {
15449 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15455 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15466parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15467 switch (parser->
current.type) {
15474 case PM_TOKEN_STRING_CONTENT: {
15475 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
15476 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15478 parser_lex(parser);
15487 case PM_TOKEN_EMBEXPR_BEGIN: {
15496 lex_state_set(parser, PM_LEX_STATE_BEG);
15497 parser_lex(parser);
15502 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
15503 pm_accepts_block_stack_push(parser,
true);
15505 pm_accepts_block_stack_pop(parser);
15509 lex_state_set(parser, state);
15510 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15515 if (statements != NULL && statements->
body.
size == 1) {
15516 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15519 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->
previous));
15528 case PM_TOKEN_EMBVAR: {
15533 lex_state_set(parser, PM_LEX_STATE_BEG);
15534 parser_lex(parser);
15539 switch (parser->
current.type) {
15542 case PM_TOKEN_BACK_REFERENCE:
15543 parser_lex(parser);
15544 variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15548 case PM_TOKEN_NUMBERED_REFERENCE:
15549 parser_lex(parser);
15550 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15554 case PM_TOKEN_GLOBAL_VARIABLE:
15555 parser_lex(parser);
15556 variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15560 case PM_TOKEN_INSTANCE_VARIABLE:
15561 parser_lex(parser);
15562 variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
15566 case PM_TOKEN_CLASS_VARIABLE:
15567 parser_lex(parser);
15568 variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
15574 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15575 variable = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
15579 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15582 parser_lex(parser);
15583 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15593static const uint8_t *
15594parse_operator_symbol_name(
const pm_token_t *name) {
15595 switch (name->
type) {
15596 case PM_TOKEN_TILDE:
15597 case PM_TOKEN_BANG:
15598 if (name->
end[-1] ==
'@')
return name->
end - 1;
15608 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
15610 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15611 parser_lex(parser);
15614 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15628 if (lex_mode->
mode != PM_LEX_STRING) {
15629 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15631 switch (parser->
current.type) {
15632 case PM_CASE_OPERATOR:
15633 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15634 case PM_TOKEN_IDENTIFIER:
15635 case PM_TOKEN_CONSTANT:
15636 case PM_TOKEN_INSTANCE_VARIABLE:
15637 case PM_TOKEN_METHOD_NAME:
15638 case PM_TOKEN_CLASS_VARIABLE:
15639 case PM_TOKEN_GLOBAL_VARIABLE:
15640 case PM_TOKEN_NUMBERED_REFERENCE:
15641 case PM_TOKEN_BACK_REFERENCE:
15642 case PM_CASE_KEYWORD:
15643 parser_lex(parser);
15646 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15652 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15659 if (match1(parser, PM_TOKEN_STRING_END)) {
15660 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15661 parser_lex(parser);
15663 .
type = PM_TOKEN_STRING_CONTENT,
15668 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->
previous));
15672 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15676 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15677 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15678 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15684 if (part) pm_interpolated_symbol_node_append(symbol, part);
15686 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15687 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15688 pm_interpolated_symbol_node_append(symbol, part);
15692 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15693 if (match1(parser, PM_TOKEN_EOF)) {
15694 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15696 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15699 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->
previous);
15706 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15709 parser_lex(parser);
15720 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15722 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
15723 pm_interpolated_symbol_node_append(symbol, part);
15725 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->
current, NULL, &parser->
current_string));
15726 pm_interpolated_symbol_node_append(symbol, part);
15728 if (next_state != PM_LEX_STATE_NONE) {
15729 lex_state_set(parser, next_state);
15732 parser_lex(parser);
15733 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15735 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->
previous);
15740 pm_string_shared_init(&unescaped, content.
start, content.
end);
15743 if (next_state != PM_LEX_STATE_NONE) {
15744 lex_state_set(parser, next_state);
15747 if (match1(parser, PM_TOKEN_EOF)) {
15748 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15750 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15753 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
15761parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
15762 switch (parser->
current.type) {
15763 case PM_CASE_OPERATOR:
15764 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
15765 case PM_CASE_KEYWORD:
15766 case PM_TOKEN_CONSTANT:
15767 case PM_TOKEN_IDENTIFIER:
15768 case PM_TOKEN_METHOD_NAME: {
15769 parser_lex(parser);
15773 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15777 case PM_TOKEN_SYMBOL_BEGIN: {
15779 parser_lex(parser);
15781 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15784 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
15785 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
15796parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
15797 switch (parser->
current.type) {
15798 case PM_CASE_OPERATOR:
15799 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
15800 case PM_CASE_KEYWORD:
15801 case PM_TOKEN_CONSTANT:
15802 case PM_TOKEN_IDENTIFIER:
15803 case PM_TOKEN_METHOD_NAME: {
15804 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
15805 parser_lex(parser);
15809 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15813 case PM_TOKEN_SYMBOL_BEGIN: {
15815 parser_lex(parser);
15817 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15819 case PM_TOKEN_BACK_REFERENCE:
15820 parser_lex(parser);
15821 return UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15822 case PM_TOKEN_NUMBERED_REFERENCE:
15823 parser_lex(parser);
15824 return UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15825 case PM_TOKEN_GLOBAL_VARIABLE:
15826 parser_lex(parser);
15827 return UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15829 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
15830 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
15842 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous));
15844 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
15845 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false));
15849 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
15850 if (is_numbered_param) {
15855 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
15856 for (uint8_t number = 1; number <= maximum; number++) {
15857 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
15860 if (!match1(parser, PM_TOKEN_EQUAL)) {
15864 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false));
15869 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->
previous));
15884 pm_node_flags_t flags = 0;
15886 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
15887 pm_node_t *node = parse_variable(parser);
15888 if (node != NULL)
return node;
15889 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
15893 pm_node_flag_set(UP(node), flags);
15904parse_method_definition_name(
pm_parser_t *parser) {
15905 switch (parser->
current.type) {
15906 case PM_CASE_KEYWORD:
15907 case PM_TOKEN_CONSTANT:
15908 case PM_TOKEN_METHOD_NAME:
15909 parser_lex(parser);
15911 case PM_TOKEN_IDENTIFIER:
15912 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current));
15913 parser_lex(parser);
15915 case PM_CASE_OPERATOR:
15916 lex_state_set(parser, PM_LEX_STATE_ENDFN);
15917 parser_lex(parser);
15926parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
15929 pm_string_ensure_owned(
string);
15935 const uint8_t *source_cursor = (uint8_t *) string->
source;
15936 const uint8_t *source_end = source_cursor + dest_length;
15941 size_t trimmed_whitespace = 0;
15947 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
15948 if (*source_cursor ==
'\t') {
15949 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
15950 if (trimmed_whitespace > common_whitespace)
break;
15952 trimmed_whitespace++;
15959 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
15960 string->length = dest_length;
15970 const uint8_t *cursor = parser->
start + PM_LOCATION_START(&string_node->
content_loc);
15983 bool dedent_next =
true;
15987 size_t write_index = 0;
15994 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
15995 nodes->
nodes[write_index++] = node;
15996 dedent_next =
false;
16002 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16005 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16006 pm_node_destroy(parser, node);
16008 nodes->
nodes[write_index++] = node;
16012 dedent_next =
true;
16015 nodes->
size = write_index;
16022parse_strings_empty_content(
const uint8_t *location) {
16023 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16031 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
16032 bool concating =
false;
16034 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16040 assert(lex_mode->
mode == PM_LEX_STRING);
16042 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16045 parser_lex(parser);
16047 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16048 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16057 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16065 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16066 }
else if (!lex_interpolation) {
16072 if (match1(parser, PM_TOKEN_EOF)) {
16077 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16092 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16094 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16095 pm_node_list_append(&parts, part);
16098 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
16099 pm_node_list_append(&parts, part);
16100 parser_lex(parser);
16101 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16103 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16104 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16106 pm_node_list_free(&parts);
16107 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16108 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16109 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16110 }
else if (match1(parser, PM_TOKEN_EOF)) {
16111 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16112 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16113 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16114 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16119 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16121 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16128 parser_lex(parser);
16130 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16131 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16132 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16138 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16140 if (location > parser->
start && location[-1] ==
'\n') location--;
16141 pm_parser_err(parser, U32(location - parser->
start), 0, PM_ERR_STRING_LITERAL_EOF);
16146 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16147 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16148 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16153 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->
previous, NULL, &unescaped));
16154 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16155 pm_node_list_append(&parts, part);
16157 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16158 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16159 pm_node_list_append(&parts, part);
16163 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16164 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16165 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16166 }
else if (match1(parser, PM_TOKEN_EOF)) {
16167 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16168 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16170 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16171 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16174 pm_node_list_free(&parts);
16183 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16184 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16185 pm_node_list_append(&parts, part);
16189 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16190 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16191 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16192 }
else if (match1(parser, PM_TOKEN_EOF)) {
16193 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16194 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16196 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16197 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16200 pm_node_list_free(&parts);
16203 if (current == NULL) {
16207 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16218 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16219 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16225 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16226 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16231 pm_interpolated_string_node_append(container, current);
16232 current = UP(container);
16242#define PM_PARSE_PATTERN_SINGLE 0
16243#define PM_PARSE_PATTERN_TOP 1
16244#define PM_PARSE_PATTERN_MULTI 2
16257 if (peek_at(parser, parser->
start + location->
start) ==
'_')
return;
16259 if (pm_constant_id_list_includes(captures, capture)) {
16260 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16262 pm_constant_id_list_append(captures, capture);
16273 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16275 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16276 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
16282 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16290 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16292 accept1(parser, PM_TOKEN_NEWLINE);
16294 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16295 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16296 accept1(parser, PM_TOKEN_NEWLINE);
16297 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16302 parser_lex(parser);
16304 accept1(parser, PM_TOKEN_NEWLINE);
16306 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16307 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16308 accept1(parser, PM_TOKEN_NEWLINE);
16309 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16318 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16325 switch (PM_NODE_TYPE(inner)) {
16326 case PM_ARRAY_PATTERN_NODE: {
16330 PM_NODE_START_SET_NODE(pattern_node, node);
16331 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16334 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16335 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16337 return UP(pattern_node);
16342 case PM_FIND_PATTERN_NODE: {
16346 PM_NODE_START_SET_NODE(pattern_node, node);
16347 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16350 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16351 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16353 return UP(pattern_node);
16358 case PM_HASH_PATTERN_NODE: {
16362 PM_NODE_START_SET_NODE(pattern_node, node);
16363 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16366 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16367 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16369 return UP(pattern_node);
16381 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16382 pm_array_pattern_node_requireds_append(pattern_node, inner);
16383 return UP(pattern_node);
16398 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16402 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16406 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->
previous));
16407 name = UP(pm_local_variable_target_node_create(
16409 &TOK2LOC(parser, &parser->
previous),
16411 (uint32_t) (depth == -1 ? 0 : depth)
16416 return pm_splat_node_create(parser, &
operator, name);
16424 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
16425 parser_lex(parser);
16430 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16431 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
16434 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16438 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16442 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->
previous));
16443 value = UP(pm_local_variable_target_node_create(
16445 &TOK2LOC(parser, &parser->
previous),
16447 (uint32_t) (depth == -1 ? 0 : depth)
16451 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16459pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16460 ptrdiff_t length = end - start;
16461 if (length == 0)
return false;
16464 size_t width = char_is_identifier_start(parser, start, end - start);
16465 if (width == 0)
return false;
16471 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16476 const uint8_t *cursor = start + width;
16477 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16478 return cursor == end;
16488 const uint8_t *start = parser->
start + PM_LOCATION_START(value_loc);
16489 const uint8_t *end = parser->
start + PM_LOCATION_END(value_loc);
16491 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
16494 if (pm_slice_is_valid_local(parser, start, end)) {
16495 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16497 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
16499 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
16500 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
16505 pm_parser_local_add(parser, constant_id, start, end, 0);
16508 parse_pattern_capture(parser, captures, constant_id, value_loc);
16513 (uint32_t) (depth == -1 ? 0 : depth)
16516 return UP(pm_implicit_node_create(parser, UP(target)));
16526 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16539 switch (PM_NODE_TYPE(first_node)) {
16540 case PM_ASSOC_SPLAT_NODE:
16541 case PM_NO_KEYWORDS_PARAMETER_NODE:
16544 case PM_SYMBOL_NODE: {
16545 if (pm_symbol_node_label_p(parser, first_node)) {
16546 parse_pattern_hash_key(parser, &keys, first_node);
16549 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)) {
16552 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
16556 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16559 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
16560 pm_node_list_append(&assocs, assoc);
16569 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;
16570 pm_parser_err_node(parser, first_node, diag_id);
16572 pm_node_t *value = UP(pm_missing_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
16573 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
16575 pm_node_list_append(&assocs, assoc);
16581 while (accept1(parser, PM_TOKEN_COMMA)) {
16583 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)) {
16585 if (rest != NULL) {
16586 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16592 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16593 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16595 if (rest == NULL) {
16598 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16599 pm_node_list_append(&assocs, assoc);
16604 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16605 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16607 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16608 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16609 }
else if (!pm_symbol_node_label_p(parser, key)) {
16610 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16612 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
16613 key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16615 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16618 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
16621 parse_pattern_hash_key(parser, &keys, key);
16624 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)) {
16625 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16626 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
16628 value = UP(pm_missing_node_create(parser, PM_NODE_END(key), 0));
16631 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16634 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
16636 if (rest != NULL) {
16637 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16640 pm_node_list_append(&assocs, assoc);
16647 pm_static_literals_free(&keys);
16656 switch (parser->
current.type) {
16657 case PM_TOKEN_IDENTIFIER:
16658 case PM_TOKEN_METHOD_NAME: {
16659 parser_lex(parser);
16663 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16667 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->
previous));
16668 return UP(pm_local_variable_target_node_create(
16670 &TOK2LOC(parser, &parser->
previous),
16672 (uint32_t) (depth == -1 ? 0 : depth)
16675 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16677 parser_lex(parser);
16679 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16682 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous));
16687 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16689 accept1(parser, PM_TOKEN_NEWLINE);
16690 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16693 switch (PM_NODE_TYPE(inner)) {
16694 case PM_ARRAY_PATTERN_NODE: {
16697 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
16698 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16700 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16701 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16703 return UP(pattern_node);
16708 case PM_FIND_PATTERN_NODE: {
16711 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
16712 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16714 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16715 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16717 return UP(pattern_node);
16727 pm_array_pattern_node_requireds_append(node, inner);
16730 case PM_TOKEN_BRACE_LEFT: {
16736 parser_lex(parser);
16738 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16741 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
16745 switch (parser->
current.type) {
16746 case PM_TOKEN_LABEL:
16747 parser_lex(parser);
16748 first_node = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16750 case PM_TOKEN_USTAR_STAR:
16751 first_node = parse_pattern_keyword_rest(parser, captures);
16753 case PM_TOKEN_STRING_BEGIN:
16754 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
16758 parser_lex(parser);
16760 first_node = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
16765 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
16767 accept1(parser, PM_TOKEN_NEWLINE);
16768 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
16771 PM_NODE_START_SET_TOKEN(parser, node, &opening);
16772 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
16781 case PM_TOKEN_UDOT_DOT:
16782 case PM_TOKEN_UDOT_DOT_DOT: {
16784 parser_lex(parser);
16788 switch (parser->
current.type) {
16789 case PM_CASE_PRIMITIVE: {
16790 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16791 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16794 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
16795 pm_node_t *right = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
16796 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16800 case PM_CASE_PRIMITIVE: {
16801 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
16804 if (pm_symbol_node_label_p(parser, node))
return node;
16807 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
16808 pm_parser_err_node(parser, node, diag_id);
16809 pm_missing_node_t *missing_node = pm_missing_node_create(parser, PM_NODE_START(node), PM_NODE_LENGTH(node));
16811 pm_node_unreference(parser, node);
16812 pm_node_destroy(parser, node);
16813 return UP(missing_node);
16817 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
16823 switch (parser->
current.type) {
16824 case PM_CASE_PRIMITIVE: {
16825 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16826 return UP(pm_range_node_create(parser, node, &
operator, right));
16829 return UP(pm_range_node_create(parser, node, &
operator, NULL));
16835 case PM_TOKEN_CARET: {
16836 parser_lex(parser);
16841 switch (parser->
current.type) {
16842 case PM_TOKEN_IDENTIFIER: {
16843 parser_lex(parser);
16844 pm_node_t *variable = UP(parse_variable(parser));
16846 if (variable == NULL) {
16847 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
16848 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0));
16851 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16853 case PM_TOKEN_INSTANCE_VARIABLE: {
16854 parser_lex(parser);
16855 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
16857 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16859 case PM_TOKEN_CLASS_VARIABLE: {
16860 parser_lex(parser);
16861 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
16863 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16865 case PM_TOKEN_GLOBAL_VARIABLE: {
16866 parser_lex(parser);
16867 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
16869 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16871 case PM_TOKEN_NUMBERED_REFERENCE: {
16872 parser_lex(parser);
16873 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
16875 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16877 case PM_TOKEN_BACK_REFERENCE: {
16878 parser_lex(parser);
16879 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
16881 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16883 case PM_TOKEN_PARENTHESIS_LEFT: {
16888 parser_lex(parser);
16890 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
16893 accept1(parser, PM_TOKEN_NEWLINE);
16894 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
16895 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous));
16900 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
16901 pm_node_t *variable = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
16902 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16906 case PM_TOKEN_UCOLON_COLON: {
16908 parser_lex(parser);
16910 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16913 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
16915 case PM_TOKEN_CONSTANT: {
16917 parser_lex(parser);
16919 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
16920 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
16923 pm_parser_err_current(parser, diag_id);
16924 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
16929parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
16930 switch (PM_NODE_TYPE(node)) {
16931 case PM_LOCAL_VARIABLE_TARGET_NODE: {
16933 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
16947 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
16957 bool alternation =
false;
16959 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
16960 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
16961 parse_pattern_alternation_error(parser, node);
16964 switch (parser->
current.type) {
16965 case PM_TOKEN_IDENTIFIER:
16966 case PM_TOKEN_BRACKET_LEFT_ARRAY:
16967 case PM_TOKEN_BRACE_LEFT:
16968 case PM_TOKEN_CARET:
16969 case PM_TOKEN_CONSTANT:
16970 case PM_TOKEN_UCOLON_COLON:
16971 case PM_TOKEN_UDOT_DOT:
16972 case PM_TOKEN_UDOT_DOT_DOT:
16973 case PM_CASE_PRIMITIVE: {
16974 if (!alternation) {
16975 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16978 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
16980 if (captures->
size) parse_pattern_alternation_error(parser, right);
16981 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16986 case PM_TOKEN_PARENTHESIS_LEFT:
16987 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
16990 parser_lex(parser);
16992 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16993 accept1(parser, PM_TOKEN_NEWLINE);
16994 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16995 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->
previous, 0));
16997 if (!alternation) {
17000 if (captures->
size) parse_pattern_alternation_error(parser, right);
17001 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17007 pm_parser_err_current(parser, diag_id);
17008 pm_node_t *right = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
17010 if (!alternation) {
17013 if (captures->
size) parse_pattern_alternation_error(parser, right);
17014 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->
previous));
17024 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17026 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17031 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17035 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->
previous));
17038 &TOK2LOC(parser, &parser->
previous),
17040 (uint32_t) (depth == -1 ? 0 : depth)
17043 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17056 bool leading_rest =
false;
17057 bool trailing_rest =
false;
17059 switch (parser->
current.type) {
17060 case PM_TOKEN_LABEL: {
17061 parser_lex(parser);
17063 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17065 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17066 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17071 case PM_TOKEN_USTAR_STAR: {
17072 node = parse_pattern_keyword_rest(parser, captures);
17073 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17075 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17076 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17081 case PM_TOKEN_STRING_BEGIN: {
17084 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17086 if (pm_symbol_node_label_p(parser, node)) {
17087 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17089 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17090 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17096 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17099 case PM_TOKEN_USTAR: {
17100 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17101 parser_lex(parser);
17102 node = UP(parse_pattern_rest(parser, captures));
17103 leading_rest =
true;
17109 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17115 if (pm_symbol_node_label_p(parser, node)) {
17116 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17119 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17124 pm_node_list_append(&nodes, node);
17127 while (accept1(parser, PM_TOKEN_COMMA)) {
17129 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)) {
17130 node = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
17131 pm_node_list_append(&nodes, node);
17132 trailing_rest =
true;
17136 if (accept1(parser, PM_TOKEN_USTAR)) {
17137 node = UP(parse_pattern_rest(parser, captures));
17142 if (trailing_rest) {
17143 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17146 trailing_rest =
true;
17148 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17151 pm_node_list_append(&nodes, node);
17158 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17159 node = UP(pm_find_pattern_node_create(parser, &nodes));
17161 if (nodes.
size == 2) {
17162 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17165 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17167 if (leading_rest && trailing_rest) {
17168 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17173 }
else if (leading_rest) {
17176 node = UP(pm_array_pattern_node_rest_create(parser, node));
17188parse_negative_numeric(
pm_node_t *node) {
17189 switch (PM_NODE_TYPE(node)) {
17190 case PM_INTEGER_NODE: {
17197 case PM_FLOAT_NODE: {
17204 case PM_RATIONAL_NODE: {
17211 case PM_IMAGINARY_NODE:
17217 assert(
false &&
"unreachable");
17230 case PM_ERR_HASH_KEY: {
17234 case PM_ERR_HASH_VALUE:
17235 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17239 case PM_ERR_UNARY_RECEIVER: {
17244 case PM_ERR_UNARY_DISALLOWED:
17245 case PM_ERR_EXPECT_ARGUMENT: {
17250 pm_parser_err_previous(parser, diag_id);
17260#define CONTEXT_NONE 0
17261#define CONTEXT_THROUGH_ENSURE 1
17262#define CONTEXT_THROUGH_ELSE 2
17265 int context = CONTEXT_NONE;
17267 while (context_node != NULL) {
17268 switch (context_node->
context) {
17289 if (context == CONTEXT_NONE) {
17290 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17291 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17292 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17293 }
else if (context == CONTEXT_THROUGH_ELSE) {
17294 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17306 context = CONTEXT_THROUGH_ELSE;
17317 context = CONTEXT_THROUGH_ENSURE;
17321 assert(
false &&
"unreachable");
17352 context_node = context_node->
prev;
17356#undef CONTEXT_ENSURE
17367 while (context_node != NULL) {
17368 switch (context_node->
context) {
17393 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17397 assert(
false &&
"unreachable");
17439 context_node = context_node->
prev;
17471parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17475 if (callback_data->
shared) {
17476 location = (
pm_token_t) { .
type = 0, .start = start, .end = end };
17481 PM_PARSER_ERR_FORMAT(callback_data->
parser, PM_TOKEN_START(callback_data->
parser, &location), PM_TOKEN_LENGTH(&location), PM_ERR_REGEXP_PARSE_ERROR, message);
17492 .
start = parser->
start + PM_NODE_START(node),
17493 .end = parser->
start + PM_NODE_END(node),
17494 .shared = unescaped->
type == PM_STRING_SHARED
17497 pm_regexp_parse(parser,
pm_string_source(unescaped),
pm_string_length(unescaped), PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED), NULL, NULL, parse_regular_expression_error, &error_data);
17504parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth) {
17505 switch (parser->
current.type) {
17506 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17507 parser_lex(parser);
17510 pm_accepts_block_stack_push(parser,
true);
17511 bool parsed_bare_hash =
false;
17513 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
17514 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
17518 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17524 if (accept1(parser, PM_TOKEN_COMMA)) {
17527 if (accepted_newline) {
17528 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
17542 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
17546 if (accept1(parser, PM_TOKEN_USTAR)) {
17550 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
17551 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
17553 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
17556 element = UP(pm_splat_node_create(parser, &
operator, expression));
17557 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
17558 if (parsed_bare_hash) {
17559 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
17562 element = UP(pm_keyword_hash_node_create(parser));
17565 if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) {
17566 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17569 pm_static_literals_free(&hash_keys);
17570 parsed_bare_hash =
true;
17572 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
17574 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17575 if (parsed_bare_hash) {
17576 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
17581 pm_hash_key_static_literals_add(parser, &hash_keys, element);
17584 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
17588 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
17589 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(
operator), value));
17590 pm_keyword_hash_node_elements_append(hash, assoc);
17592 element = UP(hash);
17593 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17594 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17597 pm_static_literals_free(&hash_keys);
17598 parsed_bare_hash =
true;
17602 pm_array_node_elements_append(array, element);
17603 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
17606 accept1(parser, PM_TOKEN_NEWLINE);
17608 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17614 pm_array_node_close_set(parser, array, &parser->
previous);
17615 pm_accepts_block_stack_pop(parser);
17619 case PM_TOKEN_PARENTHESIS_LEFT:
17620 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17622 pm_node_flags_t flags = 0;
17625 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17627 parser_lex(parser);
17629 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17630 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17631 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17638 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
17639 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17641 pop_block_exits(parser, previous_block_exits);
17642 pm_node_list_free(¤t_block_exits);
17644 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags));
17649 pm_accepts_block_stack_push(parser,
true);
17651 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17652 context_pop(parser);
17657 bool terminator_found =
false;
17659 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17660 terminator_found =
true;
17661 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17662 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
17663 terminator_found =
true;
17666 if (terminator_found) {
17668 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17669 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17670 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17679 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17680 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
17681 lex_state_set(parser, PM_LEX_STATE_ENDARG);
17684 parser_lex(parser);
17685 pm_accepts_block_stack_pop(parser);
17687 pop_block_exits(parser, previous_block_exits);
17688 pm_node_list_free(¤t_block_exits);
17690 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17696 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
17699 multi_target = pm_multi_target_node_create(parser);
17700 pm_multi_target_node_targets_append(parser, multi_target, statement);
17703 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
17705 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
17706 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->
previous);
17709 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
17710 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17711 accept1(parser, PM_TOKEN_NEWLINE);
17713 result = UP(multi_target);
17722 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
17725 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17726 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
17730 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17740 pm_statements_node_body_append(parser, statements, statement,
true);
17742 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17749 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17752 pm_statements_node_body_append(parser, statements, statement,
true);
17756 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
17762 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17763 pm_statements_node_body_append(parser, statements, node,
true);
17770 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
17776 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
17780 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17781 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17782 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
17783 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17785 }
else if (!match1(parser, PM_TOKEN_EOF)) {
17792 context_pop(parser);
17793 pm_accepts_block_stack_pop(parser);
17794 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17803 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17805 pm_multi_target_node_targets_append(parser, multi_target, statement);
17807 statement = UP(multi_target);
17811 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
17812 const uint8_t *offset = parser->
start + PM_NODE_END(statement);
17813 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
17814 pm_node_t *value = UP(pm_missing_node_create(parser, PM_NODE_END(statement), 0));
17816 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
17819 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
17823 pop_block_exits(parser, previous_block_exits);
17824 pm_node_list_free(¤t_block_exits);
17826 pm_void_statements_check(parser, statements,
true);
17827 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17829 case PM_TOKEN_BRACE_LEFT: {
17840 pm_accepts_block_stack_push(parser,
true);
17841 parser_lex(parser);
17846 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
17847 if (current_hash_keys != NULL) {
17848 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
17851 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
17852 pm_static_literals_free(&hash_keys);
17855 accept1(parser, PM_TOKEN_NEWLINE);
17858 pm_accepts_block_stack_pop(parser);
17859 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
17860 pm_hash_node_closing_loc_set(parser, node, &parser->
previous);
17864 case PM_TOKEN_CHARACTER_LITERAL: {
17865 pm_node_t *node = UP(pm_string_node_create_current_string(
17868 .type = PM_TOKEN_STRING_BEGIN,
17869 .start = parser->
current.start,
17870 .end = parser->
current.start + 1
17873 .type = PM_TOKEN_STRING_CONTENT,
17874 .start = parser->
current.start + 1,
17880 pm_node_flag_set(node, parse_unescaped_encoding(parser));
17884 parser_lex(parser);
17888 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17889 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
17894 case PM_TOKEN_CLASS_VARIABLE: {
17895 parser_lex(parser);
17896 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
17898 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17899 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17904 case PM_TOKEN_CONSTANT: {
17905 parser_lex(parser);
17911 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
17912 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17913 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17914 match1(parser, PM_TOKEN_BRACE_LEFT)
17917 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17918 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
17923 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17926 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17931 case PM_TOKEN_UCOLON_COLON: {
17932 parser_lex(parser);
17935 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17936 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous));
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_UDOT_DOT:
17945 case PM_TOKEN_UDOT_DOT_DOT: {
17947 parser_lex(parser);
17949 pm_node_t *right = parse_expression(parser, pm_binding_powers[
operator.
type].left,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
17955 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17956 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
17959 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17961 case PM_TOKEN_FLOAT:
17962 parser_lex(parser);
17963 return UP(pm_float_node_create(parser, &parser->
previous));
17964 case PM_TOKEN_FLOAT_IMAGINARY:
17965 parser_lex(parser);
17966 return UP(pm_float_node_imaginary_create(parser, &parser->
previous));
17967 case PM_TOKEN_FLOAT_RATIONAL:
17968 parser_lex(parser);
17969 return UP(pm_float_node_rational_create(parser, &parser->
previous));
17970 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
17971 parser_lex(parser);
17972 return UP(pm_float_node_rational_imaginary_create(parser, &parser->
previous));
17973 case PM_TOKEN_NUMBERED_REFERENCE: {
17974 parser_lex(parser);
17975 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
17977 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17978 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17983 case PM_TOKEN_GLOBAL_VARIABLE: {
17984 parser_lex(parser);
17985 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
17987 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17988 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17993 case PM_TOKEN_BACK_REFERENCE: {
17994 parser_lex(parser);
17995 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
17997 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17998 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18003 case PM_TOKEN_IDENTIFIER:
18004 case PM_TOKEN_METHOD_NAME: {
18005 parser_lex(parser);
18007 pm_node_t *node = parse_variable_call(parser);
18009 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
18017 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18020 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
18029 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
18031 PM_NODE_LENGTH_SET_LOCATION(call, end);
18039 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
18040 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
18041 match1(parser, PM_TOKEN_BRACE_LEFT)
18044 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18045 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18047 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
18051 pm_node_unreference(parser, node);
18057 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
18059 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
18060 pm_node_unreference(parser, node);
18063 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18067 pm_node_destroy(parser, node);
18072 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18073 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18078 case PM_TOKEN_HEREDOC_START: {
18084 size_t common_whitespace = (size_t) -1;
18087 parser_lex(parser);
18093 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18099 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18100 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY));
18105 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
18106 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18113 node = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
18114 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18119 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18126 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18128 cast->
base.
type = PM_X_STRING_NODE;
18131 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18132 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18142 pm_node_list_append(&parts, part);
18144 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18145 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18146 pm_node_list_append(&parts, part);
18152 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18154 cast->
parts = parts;
18157 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->
previous);
18163 pm_node_list_free(&parts);
18166 pm_interpolated_string_node_closing_set(parser, cast, &parser->
previous);
18174 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18176 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18182 parse_heredoc_dedent(parser, nodes, common_whitespace);
18186 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18187 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18192 case PM_TOKEN_INSTANCE_VARIABLE: {
18193 parser_lex(parser);
18194 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
18196 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18197 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18202 case PM_TOKEN_INTEGER: {
18204 parser_lex(parser);
18205 return UP(pm_integer_node_create(parser, base, &parser->
previous));
18207 case PM_TOKEN_INTEGER_IMAGINARY: {
18209 parser_lex(parser);
18210 return UP(pm_integer_node_imaginary_create(parser, base, &parser->
previous));
18212 case PM_TOKEN_INTEGER_RATIONAL: {
18214 parser_lex(parser);
18215 return UP(pm_integer_node_rational_create(parser, base, &parser->
previous));
18217 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18219 parser_lex(parser);
18220 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous));
18222 case PM_TOKEN_KEYWORD___ENCODING__:
18223 parser_lex(parser);
18224 return UP(pm_source_encoding_node_create(parser, &parser->
previous));
18225 case PM_TOKEN_KEYWORD___FILE__:
18226 parser_lex(parser);
18227 return UP(pm_source_file_node_create(parser, &parser->
previous));
18228 case PM_TOKEN_KEYWORD___LINE__:
18229 parser_lex(parser);
18230 return UP(pm_source_line_node_create(parser, &parser->
previous));
18231 case PM_TOKEN_KEYWORD_ALIAS: {
18232 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18233 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18236 parser_lex(parser);
18239 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18240 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18242 switch (PM_NODE_TYPE(new_name)) {
18243 case PM_BACK_REFERENCE_READ_NODE:
18244 case PM_NUMBERED_REFERENCE_READ_NODE:
18245 case PM_GLOBAL_VARIABLE_READ_NODE: {
18246 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)) {
18247 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18248 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18251 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18254 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
18256 case PM_SYMBOL_NODE:
18257 case PM_INTERPOLATED_SYMBOL_NODE: {
18258 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18259 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18264 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
18267 case PM_TOKEN_KEYWORD_CASE: {
18268 size_t opening_newline_index = token_newline_index(parser);
18269 parser_lex(parser);
18275 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18277 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18278 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18280 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18282 }
else if (!token_begins_expression_p(parser->
current.type)) {
18285 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18286 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18289 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18290 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18291 parser_lex(parser);
18293 pop_block_exits(parser, previous_block_exits);
18294 pm_node_list_free(¤t_block_exits);
18296 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18297 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous));
18304 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18305 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
18311 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18312 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18313 parser_lex(parser);
18316 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18319 if (accept1(parser, PM_TOKEN_USTAR)) {
18321 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18323 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18324 pm_when_node_conditions_append(when_node, UP(splat_node));
18326 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18328 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18329 pm_when_node_conditions_append(when_node, condition);
18333 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18337 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18338 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18339 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18340 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18343 pm_when_clause_static_literals_add(parser, &literals, condition);
18345 }
while (accept1(parser, PM_TOKEN_COMMA));
18347 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18348 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18349 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->
previous);
18352 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18353 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->
previous);
18356 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18358 if (statements != NULL) {
18359 pm_when_node_statements_set(when_node, statements);
18363 pm_case_node_condition_append(case_node, UP(when_node));
18369 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18372 pm_static_literals_free(&literals);
18373 node = UP(case_node);
18375 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
18379 if (predicate == NULL) {
18380 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18386 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18387 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18392 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18394 parser_lex(parser);
18399 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));
18402 pm_constant_id_list_free(&captures);
18407 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18409 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18410 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18411 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18413 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18414 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18421 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18422 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18426 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18433 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18441 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
18442 pm_case_match_node_condition_append(case_node, condition);
18448 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18451 node = UP(case_node);
18454 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18455 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18459 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18460 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18462 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18465 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18466 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18472 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18473 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18475 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18481 pop_block_exits(parser, previous_block_exits);
18482 pm_node_list_free(¤t_block_exits);
18486 case PM_TOKEN_KEYWORD_BEGIN: {
18487 size_t opening_newline_index = token_newline_index(parser);
18488 parser_lex(parser);
18491 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18494 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18497 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18498 pm_accepts_block_stack_push(parser,
true);
18499 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18500 pm_accepts_block_stack_pop(parser);
18501 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18504 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18505 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18506 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
18508 PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->
previous);
18509 pm_begin_node_end_keyword_set(parser, begin_node, &parser->
previous);
18511 pop_block_exits(parser, previous_block_exits);
18512 pm_node_list_free(¤t_block_exits);
18514 return UP(begin_node);
18516 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
18518 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18520 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18521 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18524 parser_lex(parser);
18527 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
18531 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
18534 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
18537 flush_block_exits(parser, previous_block_exits);
18538 pm_node_list_free(¤t_block_exits);
18540 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
18542 case PM_TOKEN_KEYWORD_BREAK:
18543 case PM_TOKEN_KEYWORD_NEXT:
18544 case PM_TOKEN_KEYWORD_RETURN: {
18545 parser_lex(parser);
18551 token_begins_expression_p(parser->
current.type) ||
18552 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
18554 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
18556 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
18558 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
18561 if (!accepts_command_call && arguments.
arguments != NULL) {
18562 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(next.
type));
18567 switch (keyword.
type) {
18568 case PM_TOKEN_KEYWORD_BREAK: {
18573 case PM_TOKEN_KEYWORD_NEXT: {
18578 case PM_TOKEN_KEYWORD_RETURN: {
18580 parse_return(parser, node);
18584 assert(
false &&
"unreachable");
18585 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
18588 case PM_TOKEN_KEYWORD_SUPER: {
18589 parser_lex(parser);
18593 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18598 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
18600 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
18603 return UP(pm_super_node_create(parser, &keyword, &arguments));
18605 case PM_TOKEN_KEYWORD_YIELD: {
18606 parser_lex(parser);
18610 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
18616 if (arguments.
block != NULL) {
18617 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
18618 pm_node_unreference(parser, arguments.
block);
18619 pm_node_destroy(parser, arguments.
block);
18620 arguments.
block = NULL;
18628 case PM_TOKEN_KEYWORD_CLASS: {
18629 size_t opening_newline_index = token_newline_index(parser);
18630 parser_lex(parser);
18633 pm_do_loop_stack_push(parser,
false);
18636 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18638 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18640 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, (uint16_t) (depth + 1));
18642 pm_parser_scope_push(parser,
true);
18643 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18648 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18649 pm_accepts_block_stack_push(parser,
true);
18650 statements = UP(parse_statements(parser,
PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18651 pm_accepts_block_stack_pop(parser);
18654 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18655 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18656 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)));
18658 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18661 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18666 pm_parser_scope_pop(parser);
18667 pm_do_loop_stack_pop(parser);
18669 flush_block_exits(parser, previous_block_exits);
18670 pm_node_list_free(¤t_block_exits);
18672 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous));
18675 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
18677 if (name.
type != PM_TOKEN_CONSTANT) {
18678 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18684 if (match1(parser, PM_TOKEN_LESS)) {
18685 inheritance_operator = parser->
current;
18686 lex_state_set(parser, PM_LEX_STATE_BEG);
18689 parser_lex(parser);
18691 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
18696 pm_parser_scope_push(parser,
true);
18698 if (inheritance_operator.
start != NULL) {
18699 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18701 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18705 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18706 pm_accepts_block_stack_push(parser,
true);
18707 statements = UP(parse_statements(parser,
PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18708 pm_accepts_block_stack_pop(parser);
18711 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18712 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18713 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)));
18715 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18718 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18720 if (context_def_p(parser)) {
18721 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18727 pm_parser_scope_pop(parser);
18728 pm_do_loop_stack_pop(parser);
18730 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18731 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18734 pop_block_exits(parser, previous_block_exits);
18735 pm_node_list_free(¤t_block_exits);
18737 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->
previous));
18739 case PM_TOKEN_KEYWORD_DEF: {
18741 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18744 size_t opening_newline_index = token_newline_index(parser);
18754 parser_lex(parser);
18758 bool valid_name =
true;
18760 switch (parser->
current.type) {
18761 case PM_CASE_OPERATOR:
18762 pm_parser_scope_push(parser,
true);
18763 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18764 parser_lex(parser);
18768 case PM_TOKEN_IDENTIFIER: {
18769 parser_lex(parser);
18771 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18772 receiver = parse_variable_call(parser);
18774 pm_parser_scope_push(parser,
true);
18775 lex_state_set(parser, PM_LEX_STATE_FNAME);
18776 parser_lex(parser);
18779 name = parse_method_definition_name(parser);
18781 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous));
18782 pm_parser_scope_push(parser,
true);
18789 case PM_TOKEN_INSTANCE_VARIABLE:
18790 case PM_TOKEN_CLASS_VARIABLE:
18791 case PM_TOKEN_GLOBAL_VARIABLE:
18792 valid_name =
false;
18794 case PM_TOKEN_CONSTANT:
18795 case PM_TOKEN_KEYWORD_NIL:
18796 case PM_TOKEN_KEYWORD_SELF:
18797 case PM_TOKEN_KEYWORD_TRUE:
18798 case PM_TOKEN_KEYWORD_FALSE:
18799 case PM_TOKEN_KEYWORD___FILE__:
18800 case PM_TOKEN_KEYWORD___LINE__:
18801 case PM_TOKEN_KEYWORD___ENCODING__: {
18802 pm_parser_scope_push(parser,
true);
18803 parser_lex(parser);
18807 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18808 lex_state_set(parser, PM_LEX_STATE_FNAME);
18809 parser_lex(parser);
18812 switch (identifier.
type) {
18813 case PM_TOKEN_CONSTANT:
18814 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18816 case PM_TOKEN_INSTANCE_VARIABLE:
18817 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18819 case PM_TOKEN_CLASS_VARIABLE:
18820 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18822 case PM_TOKEN_GLOBAL_VARIABLE:
18823 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18825 case PM_TOKEN_KEYWORD_NIL:
18826 receiver = UP(pm_nil_node_create(parser, &identifier));
18828 case PM_TOKEN_KEYWORD_SELF:
18829 receiver = UP(pm_self_node_create(parser, &identifier));
18831 case PM_TOKEN_KEYWORD_TRUE:
18832 receiver = UP(pm_true_node_create(parser, &identifier));
18834 case PM_TOKEN_KEYWORD_FALSE:
18835 receiver = UP(pm_false_node_create(parser, &identifier));
18837 case PM_TOKEN_KEYWORD___FILE__:
18838 receiver = UP(pm_source_file_node_create(parser, &identifier));
18840 case PM_TOKEN_KEYWORD___LINE__:
18841 receiver = UP(pm_source_line_node_create(parser, &identifier));
18843 case PM_TOKEN_KEYWORD___ENCODING__:
18844 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18850 name = parse_method_definition_name(parser);
18860 case PM_TOKEN_PARENTHESIS_LEFT: {
18865 context_pop(parser);
18866 parser_lex(parser);
18869 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
18871 accept1(parser, PM_TOKEN_NEWLINE);
18872 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18875 lex_state_set(parser, PM_LEX_STATE_FNAME);
18876 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18879 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18883 pm_parser_scope_push(parser,
true);
18885 name = parse_method_definition_name(parser);
18889 pm_parser_scope_push(parser,
true);
18890 name = parse_method_definition_name(parser);
18898 bool accept_endless_def =
true;
18899 switch (parser->
current.type) {
18900 case PM_TOKEN_PARENTHESIS_LEFT: {
18901 parser_lex(parser);
18904 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18909 params = parse_parameters(
18911 PM_BINDING_POWER_DEFINED,
18913 allow_trailing_comma,
18917 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18918 (uint16_t) (depth + 1)
18922 lex_state_set(parser, PM_LEX_STATE_BEG);
18925 context_pop(parser);
18926 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18935 case PM_CASE_PARAMETER: {
18938 if (parser->
current.type == PM_TOKEN_LABEL) {
18939 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
18942 params = parse_parameters(
18944 PM_BINDING_POWER_DEFINED,
18950 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18951 (uint16_t) (depth + 1)
18956 accept_endless_def =
false;
18958 context_pop(parser);
18963 context_pop(parser);
18972 if (accept1(parser, PM_TOKEN_EQUAL)) {
18973 if (token_is_setter_name(&name)) {
18974 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18976 if (!accept_endless_def) {
18977 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18983 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");
18988 pm_do_loop_stack_push(parser,
false);
18989 statements = UP(pm_statements_node_create(parser));
18991 bool allow_command_call;
18993 allow_command_call = accepts_command_call;
18996 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
18999 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
19003 if (PM_NODE_TYPE_P(statement, PM_CALL_NODE)) {
19006 if (call->
arguments != NULL && call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE)) {
19010 pm_parser_err_node(parser, call->
block, PM_ERR_DEF_ENDLESS_DO_BLOCK);
19015 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
19019 pm_node_t *value = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
19020 context_pop(parser);
19022 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
19025 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19026 pm_do_loop_stack_pop(parser);
19027 context_pop(parser);
19029 if (lparen.
start == NULL) {
19030 lex_state_set(parser, PM_LEX_STATE_BEG);
19032 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
19034 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19037 pm_accepts_block_stack_push(parser,
true);
19038 pm_do_loop_stack_push(parser,
false);
19040 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19041 pm_accepts_block_stack_push(parser,
true);
19042 statements = UP(parse_statements(parser,
PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
19043 pm_accepts_block_stack_pop(parser);
19046 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19047 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19048 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)));
19050 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19053 pm_accepts_block_stack_pop(parser);
19054 pm_do_loop_stack_pop(parser);
19056 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
19062 pm_parser_scope_pop(parser);
19069 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
19071 flush_block_exits(parser, previous_block_exits);
19072 pm_node_list_free(¤t_block_exits);
19074 return UP(pm_def_node_create(
19083 NTOK2PTR(
operator),
19087 NTOK2PTR(end_keyword)
19090 case PM_TOKEN_KEYWORD_DEFINED: {
19091 parser_lex(parser);
19099 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19101 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19104 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19105 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19108 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19111 accept1(parser, PM_TOKEN_NEWLINE);
19112 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19117 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19120 context_pop(parser);
19121 return UP(pm_defined_node_create(
19129 case PM_TOKEN_KEYWORD_END_UPCASE: {
19130 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19131 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19134 parser_lex(parser);
19137 if (context_def_p(parser)) {
19138 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19141 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19145 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
19146 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
19148 case PM_TOKEN_KEYWORD_FALSE:
19149 parser_lex(parser);
19150 return UP(pm_false_node_create(parser, &parser->
previous));
19151 case PM_TOKEN_KEYWORD_FOR: {
19152 size_t opening_newline_index = token_newline_index(parser);
19153 parser_lex(parser);
19161 if (accept1(parser, PM_TOKEN_USTAR)) {
19165 if (token_begins_expression_p(parser->
current.type)) {
19166 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19169 index = UP(pm_splat_node_create(parser, &star_operator, name));
19170 }
else if (token_begins_expression_p(parser->
current.type)) {
19171 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19173 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19174 index = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
19178 if (match1(parser, PM_TOKEN_COMMA)) {
19179 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19181 index = parse_target(parser, index,
false,
false);
19184 context_pop(parser);
19185 pm_do_loop_stack_push(parser,
true);
19187 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19190 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19191 pm_do_loop_stack_pop(parser);
19194 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19197 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19203 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19204 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19207 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19208 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19210 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->
previous));
19212 case PM_TOKEN_KEYWORD_IF:
19213 if (parser_end_of_line_p(parser)) {
19214 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->
current, PM_WARN_KEYWORD_EOL);
19217 size_t opening_newline_index = token_newline_index(parser);
19218 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19219 parser_lex(parser);
19221 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19222 case PM_TOKEN_KEYWORD_UNDEF: {
19223 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19224 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19227 parser_lex(parser);
19229 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19231 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19232 pm_node_destroy(parser, name);
19234 pm_undef_node_append(undef, name);
19236 while (match1(parser, PM_TOKEN_COMMA)) {
19237 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19238 parser_lex(parser);
19239 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19241 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19242 pm_node_destroy(parser, name);
19246 pm_undef_node_append(undef, name);
19252 case PM_TOKEN_KEYWORD_NOT: {
19253 parser_lex(parser);
19262 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19263 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19264 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->
previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19266 accept1(parser, PM_TOKEN_NEWLINE);
19267 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19270 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
19273 accept1(parser, PM_TOKEN_NEWLINE);
19275 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19278 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19279 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19281 arguments.
opening_loc = TOK2LOC(parser, &lparen);
19282 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19285 accept1(parser, PM_TOKEN_NEWLINE);
19286 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19291 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19294 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19296 case PM_TOKEN_KEYWORD_UNLESS: {
19297 size_t opening_newline_index = token_newline_index(parser);
19298 parser_lex(parser);
19300 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19302 case PM_TOKEN_KEYWORD_MODULE: {
19304 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19306 size_t opening_newline_index = token_newline_index(parser);
19307 parser_lex(parser);
19310 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19315 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19316 pop_block_exits(parser, previous_block_exits);
19317 pm_node_list_free(¤t_block_exits);
19320 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19323 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19326 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19327 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous));
19334 if (name.
type != PM_TOKEN_CONSTANT) {
19335 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19338 pm_parser_scope_push(parser,
true);
19339 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19342 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19343 pm_accepts_block_stack_push(parser,
true);
19344 statements = UP(parse_statements(parser,
PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19345 pm_accepts_block_stack_pop(parser);
19348 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19349 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19350 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)));
19352 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19358 pm_parser_scope_pop(parser);
19359 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
19361 if (context_def_p(parser)) {
19362 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19365 pop_block_exits(parser, previous_block_exits);
19366 pm_node_list_free(¤t_block_exits);
19368 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous));
19370 case PM_TOKEN_KEYWORD_NIL:
19371 parser_lex(parser);
19372 return UP(pm_nil_node_create(parser, &parser->
previous));
19373 case PM_TOKEN_KEYWORD_REDO: {
19374 parser_lex(parser);
19381 case PM_TOKEN_KEYWORD_RETRY: {
19382 parser_lex(parser);
19385 parse_retry(parser, node);
19389 case PM_TOKEN_KEYWORD_SELF:
19390 parser_lex(parser);
19391 return UP(pm_self_node_create(parser, &parser->
previous));
19392 case PM_TOKEN_KEYWORD_TRUE:
19393 parser_lex(parser);
19394 return UP(pm_true_node_create(parser, &parser->
previous));
19395 case PM_TOKEN_KEYWORD_UNTIL: {
19396 size_t opening_newline_index = token_newline_index(parser);
19399 pm_do_loop_stack_push(parser,
true);
19401 parser_lex(parser);
19403 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19405 pm_do_loop_stack_pop(parser);
19406 context_pop(parser);
19409 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19412 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19416 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19417 pm_accepts_block_stack_push(parser,
true);
19418 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19419 pm_accepts_block_stack_pop(parser);
19420 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19423 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19424 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
19426 return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->
previous, predicate, statements, 0));
19428 case PM_TOKEN_KEYWORD_WHILE: {
19429 size_t opening_newline_index = token_newline_index(parser);
19432 pm_do_loop_stack_push(parser,
true);
19434 parser_lex(parser);
19436 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19438 pm_do_loop_stack_pop(parser);
19439 context_pop(parser);
19442 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19445 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19449 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19450 pm_accepts_block_stack_push(parser,
true);
19451 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19452 pm_accepts_block_stack_pop(parser);
19453 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19456 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19457 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
19459 return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->
previous, predicate, statements, 0));
19461 case PM_TOKEN_PERCENT_LOWER_I: {
19462 parser_lex(parser);
19467 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19468 accept1(parser, PM_TOKEN_WORDS_SEP);
19469 if (match1(parser, PM_TOKEN_STRING_END))
break;
19473 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19475 if (current == NULL) {
19476 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->
current, NULL));
19477 parser_lex(parser);
19478 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19479 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
19480 parser_lex(parser);
19482 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19485 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
19486 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
previous, NULL));
19487 parser_lex(parser);
19490 pm_interpolated_symbol_node_append(interpolated, first_string);
19491 pm_interpolated_symbol_node_append(interpolated, second_string);
19494 current = UP(interpolated);
19496 assert(
false &&
"unreachable");
19501 pm_array_node_elements_append(array, current);
19504 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
19509 if (match1(parser, PM_TOKEN_EOF)) {
19510 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19513 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
19515 pm_array_node_close_set(parser, array, &closing);
19519 case PM_TOKEN_PERCENT_UPPER_I: {
19520 parser_lex(parser);
19528 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19529 switch (parser->
current.type) {
19530 case PM_TOKEN_WORDS_SEP: {
19531 if (current == NULL) {
19537 pm_array_node_elements_append(array, current);
19541 parser_lex(parser);
19544 case PM_TOKEN_STRING_CONTENT: {
19545 if (current == NULL) {
19549 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->
current, NULL));
19550 parser_lex(parser);
19551 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19555 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
19556 parser_lex(parser);
19559 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19565 .
type = PM_TOKEN_STRING_CONTENT,
19570 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
19571 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
previous, NULL));
19572 parser_lex(parser);
19575 pm_interpolated_symbol_node_append(interpolated, first_string);
19576 pm_interpolated_symbol_node_append(interpolated, second_string);
19579 current = UP(interpolated);
19581 assert(
false &&
"unreachable");
19586 case PM_TOKEN_EMBVAR: {
19587 bool start_location_set =
false;
19588 if (current == NULL) {
19592 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19593 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19599 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19600 pm_interpolated_symbol_node_append(interpolated, current);
19601 PM_NODE_START_SET_NODE(interpolated, current);
19602 start_location_set =
true;
19603 current = UP(interpolated);
19609 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19611 if (!start_location_set) {
19612 PM_NODE_START_SET_NODE(current, part);
19616 case PM_TOKEN_EMBEXPR_BEGIN: {
19617 bool start_location_set =
false;
19618 if (current == NULL) {
19622 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19623 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19630 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19631 pm_interpolated_symbol_node_append(interpolated, current);
19632 PM_NODE_START_SET_NODE(interpolated, current);
19633 start_location_set =
true;
19634 current = UP(interpolated);
19635 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19639 assert(
false &&
"unreachable");
19642 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19644 if (!start_location_set) {
19645 PM_NODE_START_SET_NODE(current, part);
19650 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19651 parser_lex(parser);
19658 pm_array_node_elements_append(array, current);
19662 if (match1(parser, PM_TOKEN_EOF)) {
19663 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19666 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19668 pm_array_node_close_set(parser, array, &closing);
19672 case PM_TOKEN_PERCENT_LOWER_W: {
19673 parser_lex(parser);
19678 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19679 accept1(parser, PM_TOKEN_WORDS_SEP);
19680 if (match1(parser, PM_TOKEN_STRING_END))
break;
19684 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19685 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
19688 if (current == NULL) {
19690 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19692 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19694 pm_interpolated_string_node_append(interpolated, current);
19695 pm_interpolated_string_node_append(interpolated,
string);
19696 current = UP(interpolated);
19698 assert(
false &&
"unreachable");
19700 parser_lex(parser);
19704 pm_array_node_elements_append(array, current);
19707 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
19712 if (match1(parser, PM_TOKEN_EOF)) {
19713 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
19716 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
19719 pm_array_node_close_set(parser, array, &closing);
19722 case PM_TOKEN_PERCENT_UPPER_W: {
19723 parser_lex(parser);
19731 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19732 switch (parser->
current.type) {
19733 case PM_TOKEN_WORDS_SEP: {
19738 if (current == NULL) {
19745 pm_array_node_elements_append(array, current);
19749 parser_lex(parser);
19752 case PM_TOKEN_STRING_CONTENT: {
19753 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->
current, NULL));
19754 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
19755 parser_lex(parser);
19757 if (current == NULL) {
19763 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19768 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19774 pm_interpolated_string_node_append(interpolated, current);
19775 pm_interpolated_string_node_append(interpolated,
string);
19776 current = UP(interpolated);
19778 assert(
false &&
"unreachable");
19783 case PM_TOKEN_EMBVAR: {
19784 if (current == NULL) {
19789 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19790 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19796 pm_interpolated_string_node_append(interpolated, current);
19797 current = UP(interpolated);
19804 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19808 case PM_TOKEN_EMBEXPR_BEGIN: {
19809 if (current == NULL) {
19814 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19815 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19821 pm_interpolated_string_node_append(interpolated, current);
19822 current = UP(interpolated);
19823 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19828 assert(
false &&
"unreachable");
19831 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19836 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19837 parser_lex(parser);
19844 pm_array_node_elements_append(array, current);
19848 if (match1(parser, PM_TOKEN_EOF)) {
19849 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19852 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19855 pm_array_node_close_set(parser, array, &closing);
19858 case PM_TOKEN_REGEXP_BEGIN: {
19860 parser_lex(parser);
19862 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19867 .
type = PM_TOKEN_STRING_CONTENT,
19872 parser_lex(parser);
19874 pm_node_t *node = UP(pm_regular_expression_node_create(parser, &opening, &content, &parser->
previous));
19875 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
19882 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19890 parser_lex(parser);
19895 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19902 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19903 parse_regular_expression_errors(parser, node);
19906 pm_node_flag_set(UP(node), parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, FL(node)));
19912 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19914 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->
previous, NULL, &unescaped));
19919 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19922 pm_interpolated_regular_expression_node_append(interpolated, part);
19927 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19933 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19934 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19935 pm_interpolated_regular_expression_node_append(interpolated, part);
19940 if (match1(parser, PM_TOKEN_EOF)) {
19941 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19944 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19947 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19948 return UP(interpolated);
19950 case PM_TOKEN_BACKTICK:
19951 case PM_TOKEN_PERCENT_LOWER_X: {
19952 parser_lex(parser);
19959 if (match1(parser, PM_TOKEN_STRING_END)) {
19964 .
type = PM_TOKEN_STRING_CONTENT,
19969 parser_lex(parser);
19970 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->
previous));
19975 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19982 parser_lex(parser);
19984 if (match1(parser, PM_TOKEN_STRING_END)) {
19985 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
19986 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19987 parser_lex(parser);
19993 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19995 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->
previous, NULL, &unescaped));
19996 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19998 pm_interpolated_xstring_node_append(node, part);
20003 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20007 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20008 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20009 pm_interpolated_xstring_node_append(node, part);
20014 if (match1(parser, PM_TOKEN_EOF)) {
20015 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20018 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20020 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
20024 case PM_TOKEN_USTAR: {
20025 parser_lex(parser);
20030 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20031 pm_parser_err_prefix(parser, diag_id);
20032 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
20038 if (token_begins_expression_p(parser->
current.type)) {
20039 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20042 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
20044 if (match1(parser, PM_TOKEN_COMMA)) {
20045 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20047 return parse_target_validate(parser, splat,
true);
20050 case PM_TOKEN_BANG: {
20051 if (binding_power > PM_BINDING_POWER_UNARY) {
20052 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20055 parser_lex(parser);
20058 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, binding_power < PM_BINDING_POWER_MATCH,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20059 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20061 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20064 case PM_TOKEN_TILDE: {
20065 if (binding_power > PM_BINDING_POWER_UNARY) {
20066 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20068 parser_lex(parser);
20071 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20072 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20076 case PM_TOKEN_UMINUS: {
20077 if (binding_power > PM_BINDING_POWER_UNARY) {
20078 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20080 parser_lex(parser);
20083 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20084 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20088 case PM_TOKEN_UMINUS_NUM: {
20089 parser_lex(parser);
20092 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20094 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20096 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20097 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20098 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20100 switch (PM_NODE_TYPE(node)) {
20101 case PM_INTEGER_NODE:
20102 case PM_FLOAT_NODE:
20103 case PM_RATIONAL_NODE:
20104 case PM_IMAGINARY_NODE:
20105 parse_negative_numeric(node);
20108 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20115 case PM_TOKEN_MINUS_GREATER: {
20119 size_t opening_newline_index = token_newline_index(parser);
20120 pm_accepts_block_stack_push(parser,
true);
20121 parser_lex(parser);
20124 pm_parser_scope_push(parser,
false);
20128 switch (parser->
current.type) {
20129 case PM_TOKEN_PARENTHESIS_LEFT: {
20131 parser_lex(parser);
20133 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20134 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20136 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20139 accept1(parser, PM_TOKEN_NEWLINE);
20140 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20142 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->
previous);
20145 case PM_CASE_PARAMETER: {
20146 pm_accepts_block_stack_push(parser,
false);
20147 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
20148 pm_accepts_block_stack_pop(parser);
20152 block_parameters = NULL;
20161 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20164 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20168 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20169 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20171 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20174 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20175 pm_accepts_block_stack_push(parser,
true);
20177 pm_accepts_block_stack_pop(parser);
20180 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20181 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20182 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)));
20184 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20187 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20191 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20192 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->
previous);
20194 pm_parser_scope_pop(parser);
20195 pm_accepts_block_stack_pop(parser);
20197 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body));
20199 case PM_TOKEN_UPLUS: {
20200 if (binding_power > PM_BINDING_POWER_UNARY) {
20201 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20203 parser_lex(parser);
20206 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20207 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20211 case PM_TOKEN_STRING_BEGIN:
20212 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20213 case PM_TOKEN_SYMBOL_BEGIN: {
20215 parser_lex(parser);
20217 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20228 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20229 pm_parser_err_prefix(parser, diag_id);
20235 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20236 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20242 pm_parser_err_prefix(parser, diag_id);
20245 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
previous), PM_TOKEN_LENGTH(&parser->
previous)));
20260parse_assignment_value(
pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power,
bool accepts_command_call,
pm_diagnostic_id_t diag_id, uint16_t depth) {
20261 pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH, false, diag_id, (uint16_t) (depth + 1));
20265 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20269 parser_lex(parser);
20271 pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20272 context_pop(parser);
20274 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20286 switch (PM_NODE_TYPE(node)) {
20287 case PM_BEGIN_NODE: {
20292 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20294 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20297 case PM_PARENTHESES_NODE: {
20299 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20302 case PM_STATEMENTS_NODE: {
20307 parse_assignment_value_local(parser, statement);
20329parse_assignment_values(
pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power,
bool accepts_command_call,
pm_diagnostic_id_t diag_id, uint16_t depth) {
20330 bool permitted =
true;
20331 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20333 pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MODIFIER, diag_id, (uint16_t) (depth + 1));
20334 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20336 parse_assignment_value_local(parser, value);
20337 bool single_value =
true;
20339 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20340 single_value =
false;
20343 pm_array_node_elements_append(array, value);
20346 while (accept1(parser, PM_TOKEN_COMMA)) {
20347 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20349 pm_array_node_elements_append(array, element);
20350 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20352 parse_assignment_value_local(parser, element);
20358 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20362 parser_lex(parser);
20364 bool accepts_command_call_inner =
false;
20368 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20371 accepts_command_call_inner =
true;
20375 pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, accepts_command_call_inner,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20376 context_pop(parser);
20378 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20394 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20395 pm_node_unreference(parser, UP(call_node->
arguments));
20396 pm_node_destroy(parser, UP(call_node->
arguments));
20400 if (call_node->
block != NULL) {
20401 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20402 pm_node_unreference(parser, UP(call_node->
block));
20403 pm_node_destroy(parser, UP(call_node->
block));
20404 call_node->
block = NULL;
20433static inline const uint8_t *
20434pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20437 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20438 uint8_t value = escape_hexadecimal_digit(*cursor);
20441 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20442 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20446 pm_buffer_append_byte(unescaped, value);
20448 pm_buffer_append_string(unescaped,
"\\x", 2);
20454static inline const uint8_t *
20455pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20456 uint8_t value = (uint8_t) (*cursor -
'0');
20459 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20460 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20463 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20464 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20469 pm_buffer_append_byte(unescaped, value);
20473static inline const uint8_t *
20475 const uint8_t *start = cursor - 1;
20478 if (cursor >= end) {
20479 pm_buffer_append_string(unescaped,
"\\u", 2);
20483 if (*cursor !=
'{') {
20484 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20485 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20487 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20488 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20491 return cursor + length;
20496 while (cursor < end && *cursor ==
' ') cursor++;
20498 if (cursor >= end)
break;
20499 if (*cursor ==
'}') {
20504 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20508 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20510 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20518pm_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) {
20519 const uint8_t *end = source + length;
20520 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20523 if (++cursor >= end) {
20524 pm_buffer_append_byte(unescaped,
'\\');
20530 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20532 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20533 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20536 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
20539 pm_buffer_append_byte(unescaped,
'\\');
20543 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
20544 if (next_cursor == NULL)
break;
20546 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20547 cursor = next_cursor;
20550 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20558parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20579 pm_named_capture_escape(parser, &unescaped, source, length, cursor, callback_data->
shared ? NULL : &call->receiver->location);
20584 const uint8_t *start;
20585 const uint8_t *end;
20590 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20595 if (callback_data->
shared) {
20599 end = source + length;
20600 name = pm_parser_constant_id_raw(parser, start, end);
20607 void *memory =
xmalloc(length);
20608 if (memory == NULL) abort();
20610 memcpy(memory, source, length);
20611 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20616 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20617 pm_constant_id_list_append(names, name);
20620 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20623 if (pm_local_is_keyword((
const char *) source, length)) {
20630 pm_parser_local_add(parser, name, start, end, 0);
20635 if (callback_data->
match == NULL) {
20636 callback_data->
match = pm_match_write_node_create(parser, call);
20641 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));
20642 pm_node_list_append(&callback_data->
match->
targets, target);
20658 .shared = content->
type == PM_STRING_SHARED
20665 .shared = content->
type == PM_STRING_SHARED
20668 pm_regexp_parse(parser,
pm_string_source(content),
pm_string_length(content), extended_mode, parse_regular_expression_named_capture, &callback_data, parse_regular_expression_error, &error_data);
20669 pm_constant_id_list_free(&callback_data.
names);
20671 if (callback_data.
match != NULL) {
20672 return UP(callback_data.
match);
20679parse_expression_infix(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power,
bool accepts_command_call, uint16_t depth) {
20682 switch (token.type) {
20683 case PM_TOKEN_EQUAL: {
20684 switch (PM_NODE_TYPE(node)) {
20685 case PM_CALL_NODE: {
20691 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20692 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
20696 case PM_CASE_WRITABLE: {
20700 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20701 pm_parser_local_add_location(parser, &node->
location, 0);
20704 parser_lex(parser);
20705 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, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20707 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
20708 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20711 return parse_write(parser, node, &token, value);
20713 case PM_SPLAT_NODE: {
20715 pm_multi_target_node_targets_append(parser, multi_target, node);
20717 parser_lex(parser);
20718 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20719 return parse_write(parser, UP(multi_target), &token, value);
20721 case PM_SOURCE_ENCODING_NODE:
20722 case PM_FALSE_NODE:
20723 case PM_SOURCE_FILE_NODE:
20724 case PM_SOURCE_LINE_NODE:
20727 case PM_TRUE_NODE: {
20730 parser_lex(parser);
20731 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20732 return parse_unwriteable_write(parser, node, &token, value);
20738 parser_lex(parser);
20739 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20743 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
20744 switch (PM_NODE_TYPE(node)) {
20745 case PM_BACK_REFERENCE_READ_NODE:
20746 case PM_NUMBERED_REFERENCE_READ_NODE:
20747 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20749 case PM_GLOBAL_VARIABLE_READ_NODE: {
20750 parser_lex(parser);
20752 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20753 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
20755 pm_node_destroy(parser, node);
20758 case PM_CLASS_VARIABLE_READ_NODE: {
20759 parser_lex(parser);
20761 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20764 pm_node_destroy(parser, node);
20767 case PM_CONSTANT_PATH_NODE: {
20768 parser_lex(parser);
20770 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20773 return parse_shareable_constant_write(parser, write);
20775 case PM_CONSTANT_READ_NODE: {
20776 parser_lex(parser);
20778 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20781 pm_node_destroy(parser, node);
20782 return parse_shareable_constant_write(parser, write);
20784 case PM_INSTANCE_VARIABLE_READ_NODE: {
20785 parser_lex(parser);
20787 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20790 pm_node_destroy(parser, node);
20793 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20795 parser_lex(parser);
20797 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20798 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
20800 pm_node_unreference(parser, node);
20801 pm_node_destroy(parser, node);
20804 case PM_LOCAL_VARIABLE_READ_NODE: {
20805 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
20807 pm_node_unreference(parser, node);
20811 parser_lex(parser);
20813 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20814 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20816 pm_node_destroy(parser, node);
20819 case PM_CALL_NODE: {
20825 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20828 parser_lex(parser);
20830 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20831 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20833 pm_node_destroy(parser, UP(cast));
20839 parser_lex(parser);
20844 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20845 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20846 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
20850 if (pm_call_node_writable_p(parser, cast)) {
20851 parse_write_name(parser, &cast->
name);
20853 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20856 parse_call_operator_write(parser, cast, &token);
20857 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20858 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
20860 case PM_MULTI_WRITE_NODE: {
20861 parser_lex(parser);
20862 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
20866 parser_lex(parser);
20871 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
20875 case PM_TOKEN_PIPE_PIPE_EQUAL: {
20876 switch (PM_NODE_TYPE(node)) {
20877 case PM_BACK_REFERENCE_READ_NODE:
20878 case PM_NUMBERED_REFERENCE_READ_NODE:
20879 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20881 case PM_GLOBAL_VARIABLE_READ_NODE: {
20882 parser_lex(parser);
20884 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20885 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
20887 pm_node_destroy(parser, node);
20890 case PM_CLASS_VARIABLE_READ_NODE: {
20891 parser_lex(parser);
20893 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20896 pm_node_destroy(parser, node);
20899 case PM_CONSTANT_PATH_NODE: {
20900 parser_lex(parser);
20902 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20905 return parse_shareable_constant_write(parser, write);
20907 case PM_CONSTANT_READ_NODE: {
20908 parser_lex(parser);
20910 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20913 pm_node_destroy(parser, node);
20914 return parse_shareable_constant_write(parser, write);
20916 case PM_INSTANCE_VARIABLE_READ_NODE: {
20917 parser_lex(parser);
20919 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20922 pm_node_destroy(parser, node);
20925 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20927 parser_lex(parser);
20929 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20930 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
20932 pm_node_unreference(parser, node);
20933 pm_node_destroy(parser, node);
20936 case PM_LOCAL_VARIABLE_READ_NODE: {
20937 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
20938 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->
start + PM_NODE_START(node));
20939 pm_node_unreference(parser, node);
20943 parser_lex(parser);
20945 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20946 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20948 pm_node_destroy(parser, node);
20951 case PM_CALL_NODE: {
20957 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20960 parser_lex(parser);
20962 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20963 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20965 pm_node_destroy(parser, UP(cast));
20971 parser_lex(parser);
20976 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20977 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20978 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
20982 if (pm_call_node_writable_p(parser, cast)) {
20983 parse_write_name(parser, &cast->
name);
20985 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20988 parse_call_operator_write(parser, cast, &token);
20989 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20990 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
20992 case PM_MULTI_WRITE_NODE: {
20993 parser_lex(parser);
20994 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
20998 parser_lex(parser);
21003 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21007 case PM_TOKEN_AMPERSAND_EQUAL:
21008 case PM_TOKEN_CARET_EQUAL:
21009 case PM_TOKEN_GREATER_GREATER_EQUAL:
21010 case PM_TOKEN_LESS_LESS_EQUAL:
21011 case PM_TOKEN_MINUS_EQUAL:
21012 case PM_TOKEN_PERCENT_EQUAL:
21013 case PM_TOKEN_PIPE_EQUAL:
21014 case PM_TOKEN_PLUS_EQUAL:
21015 case PM_TOKEN_SLASH_EQUAL:
21016 case PM_TOKEN_STAR_EQUAL:
21017 case PM_TOKEN_STAR_STAR_EQUAL: {
21018 switch (PM_NODE_TYPE(node)) {
21019 case PM_BACK_REFERENCE_READ_NODE:
21020 case PM_NUMBERED_REFERENCE_READ_NODE:
21021 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21023 case PM_GLOBAL_VARIABLE_READ_NODE: {
21024 parser_lex(parser);
21026 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21027 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
21029 pm_node_destroy(parser, node);
21032 case PM_CLASS_VARIABLE_READ_NODE: {
21033 parser_lex(parser);
21035 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21038 pm_node_destroy(parser, node);
21041 case PM_CONSTANT_PATH_NODE: {
21042 parser_lex(parser);
21044 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21047 return parse_shareable_constant_write(parser, write);
21049 case PM_CONSTANT_READ_NODE: {
21050 parser_lex(parser);
21052 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21055 pm_node_destroy(parser, node);
21056 return parse_shareable_constant_write(parser, write);
21058 case PM_INSTANCE_VARIABLE_READ_NODE: {
21059 parser_lex(parser);
21061 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21064 pm_node_destroy(parser, node);
21067 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21069 parser_lex(parser);
21071 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21072 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21074 pm_node_unreference(parser, node);
21075 pm_node_destroy(parser, node);
21078 case PM_LOCAL_VARIABLE_READ_NODE: {
21079 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21080 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->
start + PM_NODE_START(node));
21081 pm_node_unreference(parser, node);
21085 parser_lex(parser);
21087 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21088 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21090 pm_node_destroy(parser, node);
21093 case PM_CALL_NODE: {
21094 parser_lex(parser);
21100 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21103 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21104 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21106 pm_node_destroy(parser, UP(cast));
21113 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21114 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21115 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21119 if (pm_call_node_writable_p(parser, cast)) {
21120 parse_write_name(parser, &cast->
name);
21122 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21125 parse_call_operator_write(parser, cast, &token);
21126 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21127 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21129 case PM_MULTI_WRITE_NODE: {
21130 parser_lex(parser);
21131 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21135 parser_lex(parser);
21144 case PM_TOKEN_AMPERSAND_AMPERSAND:
21145 case PM_TOKEN_KEYWORD_AND: {
21146 parser_lex(parser);
21148 pm_node_t *right = parse_expression(parser, binding_power, parser->
previous.
type == PM_TOKEN_KEYWORD_AND,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21149 return UP(pm_and_node_create(parser, node, &token, right));
21151 case PM_TOKEN_KEYWORD_OR:
21152 case PM_TOKEN_PIPE_PIPE: {
21153 parser_lex(parser);
21155 pm_node_t *right = parse_expression(parser, binding_power, parser->
previous.
type == PM_TOKEN_KEYWORD_OR,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21156 return UP(pm_or_node_create(parser, node, &token, right));
21158 case PM_TOKEN_EQUAL_TILDE: {
21166 parser_lex(parser);
21167 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21170 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21176 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21183 bool interpolated =
false;
21184 size_t total_length = 0;
21188 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21191 interpolated =
true;
21196 if (!interpolated && total_length > 0) {
21197 void *memory =
xmalloc(total_length);
21198 if (!memory) abort();
21200 uint8_t *cursor = memory;
21210 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21212 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21215 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21219 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21224 case PM_TOKEN_UAMPERSAND:
21225 case PM_TOKEN_USTAR:
21226 case PM_TOKEN_USTAR_STAR:
21229 case PM_TOKEN_BANG_EQUAL:
21230 case PM_TOKEN_BANG_TILDE:
21231 case PM_TOKEN_EQUAL_EQUAL:
21232 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21233 case PM_TOKEN_LESS_EQUAL_GREATER:
21234 case PM_TOKEN_CARET:
21235 case PM_TOKEN_PIPE:
21236 case PM_TOKEN_AMPERSAND:
21237 case PM_TOKEN_GREATER_GREATER:
21238 case PM_TOKEN_LESS_LESS:
21239 case PM_TOKEN_MINUS:
21240 case PM_TOKEN_PLUS:
21241 case PM_TOKEN_PERCENT:
21242 case PM_TOKEN_SLASH:
21243 case PM_TOKEN_STAR:
21244 case PM_TOKEN_STAR_STAR: {
21245 parser_lex(parser);
21247 switch (PM_NODE_TYPE(node)) {
21248 case PM_RESCUE_MODIFIER_NODE: {
21251 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21255 case PM_AND_NODE: {
21257 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21258 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21264 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21265 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21273 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21274 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21276 case PM_TOKEN_GREATER:
21277 case PM_TOKEN_GREATER_EQUAL:
21278 case PM_TOKEN_LESS:
21279 case PM_TOKEN_LESS_EQUAL: {
21280 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21281 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21284 parser_lex(parser);
21285 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21286 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21288 case PM_TOKEN_AMPERSAND_DOT:
21289 case PM_TOKEN_DOT: {
21290 parser_lex(parser);
21295 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21296 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21297 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21300 switch (PM_NODE_TYPE(node)) {
21301 case PM_RESCUE_MODIFIER_NODE: {
21304 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21308 case PM_AND_NODE: {
21310 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21311 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21317 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21318 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21328 switch (parser->
current.type) {
21329 case PM_CASE_OPERATOR:
21330 case PM_CASE_KEYWORD:
21331 case PM_TOKEN_CONSTANT:
21332 case PM_TOKEN_IDENTIFIER:
21333 case PM_TOKEN_METHOD_NAME: {
21334 parser_lex(parser);
21344 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21345 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21348 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21351 match1(parser, PM_TOKEN_COMMA)
21353 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21358 case PM_TOKEN_DOT_DOT:
21359 case PM_TOKEN_DOT_DOT_DOT: {
21360 parser_lex(parser);
21363 if (token_begins_expression_p(parser->
current.type)) {
21364 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21367 return UP(pm_range_node_create(parser, node, &token, right));
21369 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21371 parser_lex(parser);
21373 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21374 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21376 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21378 parser_lex(parser);
21380 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21381 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21383 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21384 parser_lex(parser);
21386 pm_statements_node_body_append(parser, statements, node,
true);
21388 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21389 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));
21391 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21392 parser_lex(parser);
21394 pm_statements_node_body_append(parser, statements, node,
true);
21396 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21397 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));
21399 case PM_TOKEN_QUESTION_MARK: {
21402 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21405 parser_lex(parser);
21407 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21417 pm_node_t *false_expression = UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
21419 context_pop(parser);
21420 pop_block_exits(parser, previous_block_exits);
21421 pm_node_list_free(¤t_block_exits);
21423 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21426 accept1(parser, PM_TOKEN_NEWLINE);
21427 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21430 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21432 context_pop(parser);
21433 pop_block_exits(parser, previous_block_exits);
21434 pm_node_list_free(¤t_block_exits);
21436 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21438 case PM_TOKEN_COLON_COLON: {
21439 parser_lex(parser);
21442 switch (parser->
current.type) {
21443 case PM_TOKEN_CONSTANT: {
21444 parser_lex(parser);
21448 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21449 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21460 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21461 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21464 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21468 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21469 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21474 case PM_CASE_OPERATOR:
21475 case PM_CASE_KEYWORD:
21476 case PM_TOKEN_IDENTIFIER:
21477 case PM_TOKEN_METHOD_NAME: {
21478 parser_lex(parser);
21484 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21485 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21488 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21489 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21494 case PM_TOKEN_PARENTHESIS_LEFT: {
21498 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21500 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21503 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21504 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21508 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21510 parser_lex(parser);
21511 accept1(parser, PM_TOKEN_NEWLINE);
21513 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21514 context_pop(parser);
21516 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21518 case PM_TOKEN_BRACKET_LEFT: {
21519 parser_lex(parser);
21524 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21525 pm_accepts_block_stack_push(parser,
true);
21526 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
21527 pm_accepts_block_stack_pop(parser);
21528 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21535 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21536 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21537 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21544 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21545 block = parse_block(parser, (uint16_t) (depth + 1));
21546 pm_arguments_validate_block(parser, &arguments, block);
21547 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21548 block = parse_block(parser, (uint16_t) (depth + 1));
21551 if (block != NULL) {
21552 if (arguments.
block != NULL) {
21553 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21555 arguments.
arguments = pm_arguments_node_create(parser);
21557 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21560 arguments.
block = UP(block);
21563 return UP(pm_call_node_aref_create(parser, node, &arguments));
21565 case PM_TOKEN_KEYWORD_IN: {
21571 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21572 parser_lex(parser);
21575 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));
21578 pm_constant_id_list_free(&captures);
21580 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21582 case PM_TOKEN_EQUAL_GREATER: {
21588 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21589 parser_lex(parser);
21592 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));
21595 pm_constant_id_list_free(&captures);
21597 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21600 assert(
false &&
"unreachable");
21605#undef PM_PARSE_PATTERN_SINGLE
21606#undef PM_PARSE_PATTERN_TOP
21607#undef PM_PARSE_PATTERN_MULTI
21617 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
21631parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth) {
21633 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21634 return UP(pm_missing_node_create(parser, PM_TOKEN_START(parser, &parser->
current), PM_TOKEN_LENGTH(&parser->
current)));
21637 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21639 switch (PM_NODE_TYPE(node)) {
21640 case PM_MISSING_NODE:
21644 case PM_PRE_EXECUTION_NODE:
21645 case PM_POST_EXECUTION_NODE:
21646 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
21647 case PM_ALIAS_METHOD_NODE:
21648 case PM_MULTI_WRITE_NODE:
21649 case PM_UNDEF_NODE:
21652 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21662 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21666 case PM_SYMBOL_NODE:
21670 if (pm_symbol_node_label_p(parser, node)) {
21681 pm_token_type_t current_token_type;
21684 current_token_type = parser->
current.type,
21685 current_binding_powers = pm_binding_powers[current_token_type],
21686 binding_power <= current_binding_powers.
left &&
21687 current_binding_powers.
binary
21689 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21691 switch (PM_NODE_TYPE(node)) {
21692 case PM_MULTI_WRITE_NODE:
21695 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21699 case PM_CLASS_VARIABLE_WRITE_NODE:
21700 case PM_CONSTANT_PATH_WRITE_NODE:
21701 case PM_CONSTANT_WRITE_NODE:
21702 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21703 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21704 case PM_LOCAL_VARIABLE_WRITE_NODE:
21707 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21715 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21719 case PM_RESCUE_MODIFIER_NODE:
21723 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21727 if (PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE)) {
21738 if (current_binding_powers.
nonassoc) {
21741 if (match1(parser, current_token_type)) {
21753 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
21754 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
21759 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21762 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21767 if (accepts_command_call) {
21776 switch (node->
type) {
21777 case PM_CALL_NODE: {
21791 cast->
block == NULL &&
21801 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
21804 accepts_command_call =
false;
21809 case PM_CONSTANT_PATH_NODE:
21812 accepts_command_call =
false;
21820 !next_binding_powers.
binary ||
21821 binding_power > next_binding_powers.
left ||
21822 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
21838 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21839 if (statements == NULL) {
21840 statements = pm_statements_node_create(parser);
21844 pm_arguments_node_arguments_append(
21846 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
21849 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
21852 pm_parser_constant_id_constant(parser,
"print", 5)
21856 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21857 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21858 if (statements == NULL) {
21859 statements = pm_statements_node_create(parser);
21863 pm_arguments_node_arguments_append(
21865 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
21868 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21869 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
21873 pm_parser_constant_id_constant(parser,
"$F", 2),
21877 pm_statements_node_body_prepend(statements, UP(write));
21881 pm_arguments_node_arguments_append(
21883 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
21886 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21888 pm_keyword_hash_node_elements_append(keywords, UP(pm_assoc_node_create(
21890 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
21892 UP(pm_true_node_synthesized_create(parser))
21895 pm_arguments_node_arguments_append(arguments, UP(keywords));
21896 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
21900 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
21902 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
21906 statements = wrapped_statements;
21921 pm_parser_scope_push(parser,
true);
21925 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21927 parser_lex(parser);
21934 assert(statements->
body.
size > 0);
21935 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
21940 pm_parser_scope_pop(parser);
21945 statements = wrap_statements(parser, statements);
21947 flush_block_exits(parser, previous_block_exits);
21950 pm_node_list_free(¤t_block_exits);
21955 if (statements == NULL) {
21956 statements = pm_statements_node_create(parser);
21960 return UP(pm_program_node_create(parser, &locals, statements));
21977pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
21978 size_t little_length = strlen(little);
21980 for (
const char *max = big + big_length - little_length; big <= max; big++) {
21981 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
21988#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
21996pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
21997 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
21998 pm_parser_warn(parser, U32(start - parser->
start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
22009 const char *switches = pm_strnstr(engine,
" -", length);
22010 if (switches == NULL)
return;
22015 (
const uint8_t *) (switches + 1),
22016 length - ((
size_t) (switches - engine)) - 1,
22020 size_t encoding_length;
22023 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22035 assert(source != NULL);
22039 .lex_state = PM_LEX_STATE_BEG,
22040 .enclosure_nesting = 0,
22041 .lambda_enclosure_nesting = -1,
22042 .brace_nesting = 0,
22043 .do_loop_stack = 0,
22044 .accepts_block_stack = 0,
22047 .stack = {{ .mode = PM_LEX_DEFAULT }},
22051 .end = source + size,
22052 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22053 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22054 .next_start = NULL,
22055 .heredoc_end = NULL,
22057 .comment_list = { 0 },
22058 .magic_comment_list = { 0 },
22059 .warning_list = { 0 },
22060 .error_list = { 0 },
22061 .current_scope = NULL,
22062 .current_context = NULL,
22064 .encoding_changed_callback = NULL,
22065 .encoding_comment_start = source,
22066 .lex_callback = NULL,
22068 .constant_pool = { 0 },
22069 .line_offsets = { 0 },
22073 .explicit_encoding = NULL,
22075 .parsing_eval =
false,
22076 .partial_script =
false,
22077 .command_start =
true,
22078 .recovering =
false,
22079 .encoding_locked =
false,
22080 .encoding_changed =
false,
22081 .pattern_matching_newlines =
false,
22082 .in_keyword_arg =
false,
22083 .current_block_exits = NULL,
22084 .semantic_token_seen =
false,
22086 .current_regular_expression_ascii_only =
false,
22087 .warn_mismatched_indentation =
true
22104 uint32_t constant_size = ((uint32_t) size) / 95;
22105 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22110 size_t newline_size = size / 22;
22111 pm_line_offset_list_init(&parser->
line_offsets, newline_size < 4 ? 4 : newline_size);
22114 if (options != NULL) {
22123 if (encoding_length > 0) {
22125 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22147 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22149 pm_parser_scope_push(parser, scope_index == 0);
22155 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22161 void *allocated =
xmalloc(length);
22162 if (allocated == NULL)
continue;
22164 memcpy(allocated, source, length);
22165 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22176 pm_accepts_block_stack_push(parser,
true);
22179 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22192 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22209 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
22210 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
current.end);
22212 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22213 const char *engine;
22215 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22216 if (newline != NULL) {
22220 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22225 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22228 search_shebang =
false;
22230 search_shebang =
true;
22236 if (search_shebang) {
22239 bool found_shebang =
false;
22243 const uint8_t *cursor = parser->
start;
22247 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22249 while (newline != NULL) {
22250 pm_line_offset_list_append(&parser->
line_offsets, U32(newline - parser->
start + 1));
22252 cursor = newline + 1;
22253 newline = next_newline(cursor, parser->
end - cursor);
22255 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22256 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22257 const char *engine;
22258 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22259 found_shebang =
true;
22261 if (newline != NULL) {
22262 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22267 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22275 if (found_shebang) {
22277 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22279 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
22306 for (node = list->
head; node != NULL; node = next) {
22318pm_magic_comment_list_free(
pm_list_t *list) {
22321 for (node = list->
head; node != NULL; node = next) {
22335 pm_diagnostic_list_free(&parser->
error_list);
22347 pm_parser_scope_pop(parser);
22351 lex_mode_pop(parser);
22360 return parse_program(parser);
22370#define LINE_SIZE 4096
22371 char line[LINE_SIZE];
22373 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22374 size_t length = LINE_SIZE;
22375 while (length > 0 && line[length - 1] ==
'\n') length--;
22377 if (length == LINE_SIZE) {
22382 pm_buffer_append_string(buffer, line, length);
22388 pm_buffer_append_string(buffer, line, length);
22396 if (strncmp(line,
"__END__", 7) == 0)
return false;
22399 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22402 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22408 if (stream_feof(stream)) {
22427 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22433 pm_node_destroy(parser, node);
22434 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22448pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22450 pm_options_read(&options, data);
22456 pm_node_destroy(&parser, node);
22465#undef PM_CASE_KEYWORD
22466#undef PM_CASE_OPERATOR
22467#undef PM_CASE_WRITABLE
22468#undef PM_STRING_EMPTY
22473#ifndef PRISM_EXCLUDE_SERIALIZATION
22477 pm_buffer_append_string(buffer,
"PRISM", 5);
22481 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22489 pm_serialize_header(buffer);
22491 pm_buffer_append_byte(buffer,
'\0');
22499pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22501 pm_options_read(&options, data);
22508 pm_serialize_header(buffer);
22510 pm_buffer_append_byte(buffer,
'\0');
22512 pm_node_destroy(&parser, node);
22525 pm_options_read(&options, data);
22529 pm_serialize_header(buffer);
22531 pm_buffer_append_byte(buffer,
'\0');
22533 pm_node_destroy(&parser, node);
22543pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22545 pm_options_read(&options, data);
22551 pm_serialize_header(buffer);
22553 pm_buffer_append_varsint(buffer, parser.
start_line);
22556 pm_node_destroy(&parser, node);
22570 PM_SLICE_TYPE_ERROR = -1,
22573 PM_SLICE_TYPE_NONE,
22576 PM_SLICE_TYPE_LOCAL,
22579 PM_SLICE_TYPE_CONSTANT,
22582 PM_SLICE_TYPE_METHOD_NAME
22589pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22591 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22592 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22595 if (length == 0)
return PM_SLICE_TYPE_NONE;
22598 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22600 }
else if (*source ==
'_') {
22603 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22607 return PM_SLICE_TYPE_NONE;
22611 const uint8_t *end = source + length;
22612 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22618 while (source < end) {
22619 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22622 }
else if (*source ==
'_') {
22625 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22635 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22637 result = PM_SLICE_TYPE_METHOD_NAME;
22641 return source == end ? result : PM_SLICE_TYPE_NONE;
22648pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22649 switch (pm_slice_type(source, length, encoding_name)) {
22650 case PM_SLICE_TYPE_ERROR:
22652 case PM_SLICE_TYPE_NONE:
22653 case PM_SLICE_TYPE_CONSTANT:
22654 case PM_SLICE_TYPE_METHOD_NAME:
22656 case PM_SLICE_TYPE_LOCAL:
22660 assert(
false &&
"unreachable");
22668pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22669 switch (pm_slice_type(source, length, encoding_name)) {
22670 case PM_SLICE_TYPE_ERROR:
22672 case PM_SLICE_TYPE_NONE:
22673 case PM_SLICE_TYPE_LOCAL:
22674 case PM_SLICE_TYPE_METHOD_NAME:
22676 case PM_SLICE_TYPE_CONSTANT:
22680 assert(
false &&
"unreachable");
22688pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22689#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22690#define C1(c) (*source == c)
22691#define C2(s) (memcmp(source, s, 2) == 0)
22692#define C3(s) (memcmp(source, s, 3) == 0)
22694 switch (pm_slice_type(source, length, encoding_name)) {
22695 case PM_SLICE_TYPE_ERROR:
22697 case PM_SLICE_TYPE_NONE:
22699 case PM_SLICE_TYPE_LOCAL:
22701 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22702 case PM_SLICE_TYPE_CONSTANT:
22704 case PM_SLICE_TYPE_METHOD_NAME:
22711 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22713 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22715 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.
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_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_free(pm_parser_t *parser)
Free any memory associated with the given parser.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(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.
PRISM_EXPORTED_FUNCTION void pm_parser_init(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.
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.
This struct is used to pass information between the regular expression parser and the error callback.
pm_parser_t * parser
The parser that we are parsing the regular expression for.
const uint8_t * start
The start of the regular expression.
bool shared
Whether or not the source of the regular expression is shared.
const uint8_t * end
The end of the regular expression.
This struct is used to pass information between the regular expression parser and the named capture c...
pm_constant_id_list_t names
The list of names that have been parsed.
pm_parser_t * parser
The parser that is parsing the regular expression.
pm_match_write_node_t * match
The match write node that is being created.
pm_call_node_t * call
The call node wrapping the regular expression node.
bool shared
Whether the content of the regular expression is shared.
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.
pm_location_t opening_loc
BlockNode::opening_loc.
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_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.
size_t capacity
The capacity of the list that has been allocated.
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 current_regular_expression_ascii_only
True if the current regular expression being lexed contains only ASCII characters.
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.
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_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...
uint32_t node_id
The next node identifier that will be assigned.
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.
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_string_t unescaped
RegularExpressionNode::unescaped.
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_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.