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))
30 lex_mode_incrementor(
const uint8_t start) {
47 lex_mode_terminator(
const uint8_t start) {
89 lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
90 uint8_t incrementor = lex_mode_incrementor(delimiter);
91 uint8_t terminator = lex_mode_terminator(delimiter);
97 .interpolation = interpolation,
98 .incrementor = incrementor,
99 .terminator = terminator
105 uint8_t *breakpoints = lex_mode.
as.list.breakpoints;
106 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.breakpoints));
111 if (terminator !=
'\0') {
112 breakpoints[index++] = terminator;
118 breakpoints[index++] =
'#';
122 if (incrementor !=
'\0') {
123 breakpoints[index++] = incrementor;
127 return lex_mode_push(parser, lex_mode);
137 return lex_mode_push_list(parser,
false,
'\0');
144 lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
146 .
mode = PM_LEX_REGEXP,
149 .incrementor = incrementor,
150 .terminator = terminator
157 uint8_t *breakpoints = lex_mode.
as.regexp.breakpoints;
158 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.breakpoints));
162 if (terminator !=
'\0') {
163 breakpoints[index++] = terminator;
167 if (incrementor !=
'\0') {
168 breakpoints[index++] = incrementor;
172 return lex_mode_push(parser, lex_mode);
179 lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
181 .
mode = PM_LEX_STRING,
184 .interpolation = interpolation,
185 .label_allowed = label_allowed,
186 .incrementor = incrementor,
187 .terminator = terminator
193 uint8_t *breakpoints = lex_mode.
as.string.breakpoints;
194 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.breakpoints));
199 if (terminator !=
'\0') {
200 breakpoints[index++] = terminator;
206 breakpoints[index++] =
'#';
211 if (incrementor !=
'\0') {
212 breakpoints[index++] = incrementor;
216 return lex_mode_push(parser, lex_mode);
226 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
258 PM_IGNORED_NEWLINE_NONE = 0,
259 PM_IGNORED_NEWLINE_ALL,
260 PM_IGNORED_NEWLINE_PATTERN
261 } pm_ignored_newline_type_t;
263 static inline pm_ignored_newline_type_t
265 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);
268 return PM_IGNORED_NEWLINE_ALL;
269 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
270 return PM_IGNORED_NEWLINE_PATTERN;
272 return PM_IGNORED_NEWLINE_NONE;
278 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));
283 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
287 lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
296 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
304 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
316 #ifndef PM_DEBUG_LOGGING
321 #define PM_DEBUG_LOGGING 0
327 fprintf(stderr,
"STATE: ");
330 if (parser->
lex_state == PM_LEX_STATE_NONE) {
331 fprintf(stderr,
"NONE\n");
335 #define CHECK_STATE(state) \
336 if (parser->lex_state & state) { \
337 if (!first) fprintf(stderr, "|"); \
338 fprintf(stderr, "%s", #state); \
342 CHECK_STATE(PM_LEX_STATE_BEG)
343 CHECK_STATE(PM_LEX_STATE_END)
344 CHECK_STATE(PM_LEX_STATE_ENDARG)
345 CHECK_STATE(PM_LEX_STATE_ENDFN)
346 CHECK_STATE(PM_LEX_STATE_ARG)
347 CHECK_STATE(PM_LEX_STATE_CMDARG)
348 CHECK_STATE(PM_LEX_STATE_MID)
349 CHECK_STATE(PM_LEX_STATE_FNAME)
350 CHECK_STATE(PM_LEX_STATE_DOT)
351 CHECK_STATE(PM_LEX_STATE_CLASS)
352 CHECK_STATE(PM_LEX_STATE_LABEL)
353 CHECK_STATE(PM_LEX_STATE_LABELED)
354 CHECK_STATE(PM_LEX_STATE_FITEM)
358 fprintf(stderr,
"\n");
363 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
365 lex_state_set(parser, state);
366 fprintf(stderr,
"Now: ");
368 fprintf(stderr,
"\n");
371 #define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
379 #define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
382 #define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
385 #define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
388 #define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
391 #define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
394 #define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
397 #define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
414 #define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
415 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
423 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
430 #define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
431 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
446 #define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
447 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
453 #define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
454 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
471 pm_parser_err(parser, token->start, token->end, diag_id);
478 #define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
479 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
485 #define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
486 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
502 pm_parser_warn(parser, token->start, token->end, diag_id);
517 #define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
518 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
524 #define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
525 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
531 #define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
532 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
538 #define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
539 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
547 pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
548 PM_PARSER_ERR_FORMAT(
551 ident_start + ident_length,
554 (
const char *) ident_start
566 pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
568 if (scope == NULL)
return false;
573 .parameters = PM_SCOPE_PARAMETERS_NONE,
574 .implicit_parameters = { 0 },
592 if (scope->
previous == NULL)
return true;
593 if (scope->
closed)
return false;
594 }
while ((scope = scope->
previous) != NULL);
596 assert(
false &&
"unreachable");
604 pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
607 while (depth-- > 0) {
608 assert(scope != NULL);
616 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
617 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
618 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
619 } pm_scope_forwarding_param_check_result_t;
621 static pm_scope_forwarding_param_check_result_t
622 pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
624 bool conflict =
false;
626 while (scope != NULL) {
630 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
632 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
643 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
648 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
649 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
652 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
653 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
655 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
656 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
663 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
664 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
668 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
678 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
679 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
687 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
688 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
695 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
696 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
699 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
700 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
702 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
703 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
712 pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
736 #define PM_LOCALS_HASH_THRESHOLD 9
751 name = ((name >> 16) ^ name) * 0x45d9f3b;
752 name = ((name >> 16) ^ name) * 0x45d9f3b;
753 name = (name >> 16) ^ name;
763 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
764 assert(next_capacity > locals->
capacity);
767 if (next_locals == NULL) abort();
769 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
770 if (locals->
size > 0) {
776 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
777 uint32_t mask = next_capacity - 1;
779 for (uint32_t index = 0; index < locals->
capacity; index++) {
783 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
785 uint32_t hash = local->
hash;
787 next_locals[hash & mask] = *local;
792 pm_locals_free(locals);
793 locals->
locals = next_locals;
815 pm_locals_resize(locals);
818 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
819 for (uint32_t index = 0; index < locals->
capacity; index++) {
825 .location = { .start = start, .end = end },
826 .index = locals->
size++,
831 }
else if (local->
name == name) {
836 uint32_t mask = locals->
capacity - 1;
837 uint32_t hash = pm_locals_hash(name);
838 uint32_t initial_hash = hash;
846 .location = { .start = start, .end = end },
847 .index = locals->
size++,
852 }
else if (local->
name == name) {
857 }
while ((hash & mask) != initial_hash);
860 assert(
false &&
"unreachable");
870 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
871 for (uint32_t index = 0; index < locals->
size; index++) {
873 if (local->
name == name)
return index;
876 uint32_t mask = locals->
capacity - 1;
877 uint32_t hash = pm_locals_hash(name);
878 uint32_t initial_hash = hash & mask;
885 }
else if (local->
name == name) {
890 }
while ((hash & mask) != initial_hash);
902 uint32_t index = pm_locals_find(locals, name);
903 assert(index != UINT32_MAX);
906 assert(local->
reads < UINT32_MAX);
917 uint32_t index = pm_locals_find(locals, name);
918 assert(index != UINT32_MAX);
921 assert(local->
reads > 0);
931 uint32_t index = pm_locals_find(locals, name);
932 assert(index != UINT32_MAX);
952 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
956 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
958 for (uint32_t index = 0; index < capacity; index++) {
967 if (constant->
length >= 1 && *constant->
start !=
'_') {
968 PM_PARSER_WARN_FORMAT(
972 PM_WARN_UNUSED_LOCAL_VARIABLE,
974 (
const char *) constant->
start
990 pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
998 pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1006 pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1015 return pm_parser_constant_id_location(parser, token->start, token->end);
1036 while (node != NULL) {
1044 return void_node != NULL ? void_node : node;
1053 if (vn != NULL)
return vn;
1058 if (vn != NULL)
return vn;
1066 if (vn == NULL)
return NULL;
1067 if (void_node == NULL) void_node = vn;
1070 pm_node_t *vn = pm_check_value_expression(parser, (
pm_node_t *) rescue_clause->statements);
1075 if (void_node == NULL) {
1115 if (void_node == NULL) {
1130 if (void_node == NULL) {
1155 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1170 pm_node_t *void_node = pm_check_value_expression(parser, node);
1171 if (void_node != NULL) {
1172 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1181 const char *
type = NULL;
1191 type =
"a variable";
1199 switch (message->
length) {
1201 switch (message->
start[0]) {
1218 switch (message->
start[1]) {
1220 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1226 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1232 if (message->
start[0] ==
'*') {
1240 if (memcmp(message->
start,
"<=>", 3) == 0) {
1254 type =
"a constant";
1310 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1321 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1322 for (
size_t index = 0; index < size; index++) {
1323 pm_void_statement_check(parser, node->
body.
nodes[index]);
1333 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1334 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1335 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1336 } pm_conditional_predicate_type_t;
1344 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1345 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1347 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1348 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1350 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1360 pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1363 if (
PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1366 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1367 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1373 if (
PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1376 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1381 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1411 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1433 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1434 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1439 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1440 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1464 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1465 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1484 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1485 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1496 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1497 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1502 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1503 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1504 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1507 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1513 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1517 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1524 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1562 #define PM_LOCATION_NULL_VALUE(parser) ((pm_location_t) { .start = (parser)->start, .end = (parser)->start })
1563 #define PM_LOCATION_TOKEN_VALUE(token) ((pm_location_t) { .start = (token)->start, .end = (token)->end })
1564 #define PM_LOCATION_NODE_VALUE(node) ((pm_location_t) { .start = (node)->location.start, .end = (node)->location.end })
1565 #define PM_LOCATION_NODE_BASE_VALUE(node) ((pm_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end })
1566 #define PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((pm_location_t) { .start = NULL, .end = NULL })
1567 #define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : PM_LOCATION_TOKEN_VALUE(token))
1595 static inline const uint8_t *
1597 if (arguments->
block != NULL) {
1638 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1651 static inline size_t
1652 char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b) {
1657 }
else if (*b ==
'_') {
1659 }
else if (*b >= 0x80) {
1664 }
else if (*b < 0x80) {
1675 static inline size_t
1676 char_is_identifier_utf8(
const uint8_t *b,
const uint8_t *end) {
1689 static inline size_t
1690 char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b) {
1695 }
else if (*b ==
'_') {
1697 }
else if (*b >= 0x80) {
1703 return char_is_identifier_utf8(b, parser->
end);
1709 #define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1710 #define PUNCT(idx) ( \
1711 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1712 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1713 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1714 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1715 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1718 const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1724 char_is_global_name_punctuation(const uint8_t b) {
1725 const unsigned int i = (const unsigned int) b;
1726 if (i <= 0x20 || 0x7e < i) return false;
1728 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1732 token_is_setter_name(pm_token_t *token) {
1734 (token->type == PM_TOKEN_IDENTIFIER) &&
1735 (token->end - token->start >= 2) &&
1736 (token->end[-1] == '=')
1744 pm_local_is_keyword(const char *source, size_t length) {
1745 #define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1749 switch (source[0]) {
1750 case 'd': KEYWORD("do"); return false;
1751 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1752 case 'o': KEYWORD("or"); return false;
1753 default: return false;
1756 switch (source[0]) {
1757 case 'a': KEYWORD("and"); return false;
1758 case 'd': KEYWORD("def"); return false;
1759 case 'e': KEYWORD("end"); return false;
1760 case 'f': KEYWORD("for"); return false;
1761 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1762 default: return false;
1765 switch (source[0]) {
1766 case 'c': KEYWORD("case"); return false;
1767 case 'e': KEYWORD("else"); return false;
1768 case 'n': KEYWORD("next"); return false;
1769 case 'r': KEYWORD("redo"); return false;
1770 case 's': KEYWORD("self"); return false;
1771 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1772 case 'w': KEYWORD("when"); return false;
1773 default: return false;
1776 switch (source[0]) {
1777 case 'a': KEYWORD("alias"); return false;
1778 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1779 case 'c': KEYWORD("class"); return false;
1780 case 'e': KEYWORD("elsif"); return false;
1781 case 'f': KEYWORD("false"); return false;
1782 case 'r': KEYWORD("retry"); return false;
1783 case 's': KEYWORD("super"); return false;
1784 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1785 case 'w': KEYWORD("while"); return false;
1786 case 'y': KEYWORD("yield"); return false;
1787 default: return false;
1790 switch (source[0]) {
1791 case 'e': KEYWORD("ensure"); return false;
1792 case 'm': KEYWORD("module"); return false;
1793 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1794 case 'u': KEYWORD("unless"); return false;
1795 default: return false;
1798 KEYWORD("__LINE__");
1799 KEYWORD("__FILE__");
1802 KEYWORD("__ENCODING__");
1811 /******************************************************************************/
1812 /* Node flag handling functions */
1813 /******************************************************************************/
1819 pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1820 node->flags |= flag;
1827 pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1828 node->flags &= (pm_node_flags_t) ~flag;
1835 pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1836 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1837 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1838 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1839 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1840 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1841 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1842 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1843 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1845 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1848 /******************************************************************************/
1849 /* Node creation functions */
1850 /******************************************************************************/
1857 #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)
1862 static inline pm_node_flags_t
1863 pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1864 pm_node_flags_t flags = 0;
1866 if (closing->type == PM_TOKEN_REGEXP_END) {
1867 pm_buffer_t unknown_flags = { 0 };
1869 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1871 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1872 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1873 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1874 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1876 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1877 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1878 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1879 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1881 default: pm_buffer_append_byte(&unknown_flags, *flag);
1885 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1886 if (unknown_flags_length != 0) {
1887 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1888 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1890 pm_buffer_free(&unknown_flags);
1896 #undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1898 static pm_statements_node_t *
1899 pm_statements_node_create(pm_parser_t *parser);
1902 pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1905 pm_statements_node_body_length(pm_statements_node_t *node);
1911 static inline void *
1912 pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1913 void *memory = xcalloc(1, size);
1914 if (memory == NULL) {
1915 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1921 #define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
1922 #define PM_NODE_IDENTIFY(parser) (++parser->node_id)
1927 static pm_missing_node_t *
1928 pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1929 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1931 *node = (pm_missing_node_t) {{
1932 .type = PM_MISSING_NODE,
1933 .node_id = PM_NODE_IDENTIFY(parser),
1934 .location = { .start = start, .end = end }
1943 static pm_alias_global_variable_node_t *
1944 pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1945 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1946 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1948 *node = (pm_alias_global_variable_node_t) {
1950 .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
1951 .node_id = PM_NODE_IDENTIFY(parser),
1953 .start = keyword->start,
1954 .end = old_name->location.end
1957 .new_name = new_name,
1958 .old_name = old_name,
1959 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1968 static pm_alias_method_node_t *
1969 pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1970 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1971 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
1973 *node = (pm_alias_method_node_t) {
1975 .type = PM_ALIAS_METHOD_NODE,
1976 .node_id = PM_NODE_IDENTIFY(parser),
1978 .start = keyword->start,
1979 .end = old_name->location.end
1982 .new_name = new_name,
1983 .old_name = old_name,
1984 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1993 static pm_alternation_pattern_node_t *
1994 pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
1995 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
1997 *node = (pm_alternation_pattern_node_t) {
1999 .type = PM_ALTERNATION_PATTERN_NODE,
2000 .node_id = PM_NODE_IDENTIFY(parser),
2002 .start = left->location.start,
2003 .end = right->location.end
2008 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2017 static pm_and_node_t *
2018 pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2019 pm_assert_value_expression(parser, left);
2021 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2023 *node = (pm_and_node_t) {
2025 .type = PM_AND_NODE,
2026 .node_id = PM_NODE_IDENTIFY(parser),
2028 .start = left->location.start,
2029 .end = right->location.end
2033 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2043 static pm_arguments_node_t *
2044 pm_arguments_node_create(pm_parser_t *parser) {
2045 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2047 *node = (pm_arguments_node_t) {
2049 .type = PM_ARGUMENTS_NODE,
2050 .node_id = PM_NODE_IDENTIFY(parser),
2051 .location = PM_LOCATION_NULL_VALUE(parser)
2063 pm_arguments_node_size(pm_arguments_node_t *node) {
2064 return node->arguments.size;
2071 pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2072 if (pm_arguments_node_size(node) == 0) {
2073 node->base.location.start = argument->location.start;
2076 node->base.location.end = argument->location.end;
2077 pm_node_list_append(&node->arguments, argument);
2079 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2080 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2081 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2083 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2091 static pm_array_node_t *
2092 pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2093 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2095 *node = (pm_array_node_t) {
2097 .type = PM_ARRAY_NODE,
2098 .flags = PM_NODE_FLAG_STATIC_LITERAL,
2099 .node_id = PM_NODE_IDENTIFY(parser),
2100 .location = PM_LOCATION_TOKEN_VALUE(opening)
2102 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2103 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2114 pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2115 if (!node->elements.size && !node->opening_loc.start) {
2116 node->base.location.start = element->location.start;
2119 pm_node_list_append(&node->elements, element);
2120 node->base.location.end = element->location.end;
2122 // If the element is not a static literal, then the array is not a static
2123 // literal. Turn that flag off.
2124 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)) {
2125 pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
2128 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2129 pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2137 pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2138 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2139 node->base.location.end = closing->end;
2140 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2147 static pm_array_pattern_node_t *
2148 pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2149 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2151 *node = (pm_array_pattern_node_t) {
2153 .type = PM_ARRAY_PATTERN_NODE,
2154 .node_id = PM_NODE_IDENTIFY(parser),
2156 .start = nodes->nodes[0]->location.start,
2157 .end = nodes->nodes[nodes->size - 1]->location.end
2164 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2165 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2168 // For now we're going to just copy over each pointer manually. This could be
2169 // much more efficient, as we could instead resize the node list.
2170 bool found_rest = false;
2173 PM_NODE_LIST_FOREACH(nodes, index, child) {
2174 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2177 } else if (found_rest) {
2178 pm_node_list_append(&node->posts, child);
2180 pm_node_list_append(&node->requireds, child);
2190 static pm_array_pattern_node_t *
2191 pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2192 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2194 *node = (pm_array_pattern_node_t) {
2196 .type = PM_ARRAY_PATTERN_NODE,
2197 .node_id = PM_NODE_IDENTIFY(parser),
2198 .location = rest->location,
2204 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2205 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2215 static pm_array_pattern_node_t *
2216 pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2217 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2219 *node = (pm_array_pattern_node_t) {
2221 .type = PM_ARRAY_PATTERN_NODE,
2222 .node_id = PM_NODE_IDENTIFY(parser),
2224 .start = constant->location.start,
2228 .constant = constant,
2230 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2231 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2243 static pm_array_pattern_node_t *
2244 pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2245 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2247 *node = (pm_array_pattern_node_t) {
2249 .type = PM_ARRAY_PATTERN_NODE,
2250 .node_id = PM_NODE_IDENTIFY(parser),
2252 .start = opening->start,
2258 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2259 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2268 pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2269 pm_node_list_append(&node->requireds, inner);
2275 static pm_assoc_node_t *
2276 pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2277 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2280 if (value != NULL && value->location.end > key->location.end) {
2281 end = value->location.end;
2282 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2283 end = operator->end;
2285 end = key->location.end;
2288 // Hash string keys will be frozen, so we can mark them as frozen here so
2289 // that the compiler picks them up and also when we check for static literal
2290 // on the keys it gets factored in.
2291 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2292 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2295 // If the key and value of this assoc node are both static literals, then
2296 // we can mark this node as a static literal.
2297 pm_node_flags_t flags = 0;
2299 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2300 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)
2302 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2305 *node = (pm_assoc_node_t) {
2307 .type = PM_ASSOC_NODE,
2309 .node_id = PM_NODE_IDENTIFY(parser),
2311 .start = key->location.start,
2316 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2326 static pm_assoc_splat_node_t *
2327 pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2328 assert(operator->type == PM_TOKEN_USTAR_STAR);
2329 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2331 *node = (pm_assoc_splat_node_t) {
2333 .type = PM_ASSOC_SPLAT_NODE,
2334 .node_id = PM_NODE_IDENTIFY(parser),
2336 .start = operator->start,
2337 .end = value == NULL ? operator->end : value->location.end
2341 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2350 static pm_back_reference_read_node_t *
2351 pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2352 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2353 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2355 *node = (pm_back_reference_read_node_t) {
2357 .type = PM_BACK_REFERENCE_READ_NODE,
2358 .node_id = PM_NODE_IDENTIFY(parser),
2359 .location = PM_LOCATION_TOKEN_VALUE(name),
2361 .name = pm_parser_constant_id_token(parser, name)
2370 static pm_begin_node_t *
2371 pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2372 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2374 *node = (pm_begin_node_t) {
2376 .type = PM_BEGIN_NODE,
2377 .node_id = PM_NODE_IDENTIFY(parser),
2379 .start = begin_keyword->start,
2380 .end = statements == NULL ? begin_keyword->end : statements->base.location.end
2383 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2384 .statements = statements,
2385 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2395 pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2396 // If the begin keyword doesn't exist, we set the start on the begin_node
2397 if (!node->begin_keyword_loc.start) {
2398 node->base.location.start = rescue_clause->base.location.start;
2400 node->base.location.end = rescue_clause->base.location.end;
2401 node->rescue_clause = rescue_clause;
2408 pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2409 node->base.location.end = else_clause->base.location.end;
2410 node->else_clause = else_clause;
2417 pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2418 node->base.location.end = ensure_clause->base.location.end;
2419 node->ensure_clause = ensure_clause;
2426 pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2427 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2429 node->base.location.end = end_keyword->end;
2430 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2436 static pm_block_argument_node_t *
2437 pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2438 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2440 *node = (pm_block_argument_node_t) {
2442 .type = PM_BLOCK_ARGUMENT_NODE,
2443 .node_id = PM_NODE_IDENTIFY(parser),
2445 .start = operator->start,
2446 .end = expression == NULL ? operator->end : expression->location.end
2449 .expression = expression,
2450 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2459 static pm_block_node_t *
2460 pm_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) {
2461 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2463 *node = (pm_block_node_t) {
2465 .type = PM_BLOCK_NODE,
2466 .node_id = PM_NODE_IDENTIFY(parser),
2467 .location = { .start = opening->start, .end = closing->end },
2470 .parameters = parameters,
2472 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2473 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2482 static pm_block_parameter_node_t *
2483 pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2484 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2485 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2487 *node = (pm_block_parameter_node_t) {
2489 .type = PM_BLOCK_PARAMETER_NODE,
2490 .node_id = PM_NODE_IDENTIFY(parser),
2492 .start = operator->start,
2493 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
2496 .name = pm_parser_optional_constant_id_token(parser, name),
2497 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2498 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2507 static pm_block_parameters_node_t *
2508 pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2509 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2511 const uint8_t *start;
2512 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2513 start = opening->start;
2514 } else if (parameters != NULL) {
2515 start = parameters->base.location.start;
2521 if (parameters != NULL) {
2522 end = parameters->base.location.end;
2523 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2529 *node = (pm_block_parameters_node_t) {
2531 .type = PM_BLOCK_PARAMETERS_NODE,
2532 .node_id = PM_NODE_IDENTIFY(parser),
2538 .parameters = parameters,
2539 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2540 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2551 pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2552 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2554 node->base.location.end = closing->end;
2555 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2561 static pm_block_local_variable_node_t *
2562 pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2563 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2565 *node = (pm_block_local_variable_node_t) {
2567 .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
2568 .node_id = PM_NODE_IDENTIFY(parser),
2569 .location = PM_LOCATION_TOKEN_VALUE(name),
2571 .name = pm_parser_constant_id_token(parser, name)
2581 pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2582 pm_node_list_append(&node->locals, (pm_node_t *) local);
2584 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2585 node->base.location.end = local->base.location.end;
2591 static pm_break_node_t *
2592 pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2593 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2594 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2596 *node = (pm_break_node_t) {
2598 .type = PM_BREAK_NODE,
2599 .node_id = PM_NODE_IDENTIFY(parser),
2601 .start = keyword->start,
2602 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
2605 .arguments = arguments,
2606 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2612 // There are certain flags that we want to use internally but don't want to
2613 // expose because they are not relevant beyond parsing. Therefore we'll define
2614 // them here and not define them in config.yml/a header file.
2615 static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
2616 static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
2617 static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
2618 static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
2625 static pm_call_node_t *
2626 pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2627 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2629 *node = (pm_call_node_t) {
2631 .type = PM_CALL_NODE,
2633 .node_id = PM_NODE_IDENTIFY(parser),
2634 .location = PM_LOCATION_NULL_VALUE(parser),
2637 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2638 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2639 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2641 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2653 static inline pm_node_flags_t
2654 pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2655 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2662 static pm_call_node_t *
2663 pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2664 pm_assert_value_expression(parser, receiver);
2666 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2667 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2668 flags |= PM_CALL_NODE_FLAGS_INDEX;
2671 pm_call_node_t *node = pm_call_node_create(parser, flags);
2673 node->base.location.start = receiver->location.start;
2674 node->base.location.end = pm_arguments_end(arguments);
2676 node->receiver = receiver;
2677 node->message_loc.start = arguments->opening_loc.start;
2678 node->message_loc.end = arguments->closing_loc.end;
2680 node->opening_loc = arguments->opening_loc;
2681 node->arguments = arguments->arguments;
2682 node->closing_loc = arguments->closing_loc;
2683 node->block = arguments->block;
2685 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2692 static pm_call_node_t *
2693 pm_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) {
2694 pm_assert_value_expression(parser, receiver);
2695 pm_assert_value_expression(parser, argument);
2697 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2699 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2700 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2702 node->receiver = receiver;
2703 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2705 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2706 pm_arguments_node_arguments_append(arguments, argument);
2707 node->arguments = arguments;
2709 node->name = pm_parser_constant_id_token(parser, operator);
2716 static pm_call_node_t *
2717 pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2718 pm_assert_value_expression(parser, receiver);
2720 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2722 node->base.location.start = receiver->location.start;
2723 const uint8_t *end = pm_arguments_end(arguments);
2727 node->base.location.end = end;
2729 node->receiver = receiver;
2730 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2731 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2732 node->opening_loc = arguments->opening_loc;
2733 node->arguments = arguments->arguments;
2734 node->closing_loc = arguments->closing_loc;
2735 node->block = arguments->block;
2737 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2738 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2741 node->name = pm_parser_constant_id_token(parser, message);
2748 static pm_call_node_t *
2749 pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2750 pm_call_node_t *node = pm_call_node_create(parser, 0);
2751 node->base.location.start = parser->start;
2752 node->base.location.end = parser->end;
2754 node->receiver = receiver;
2755 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2756 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2757 node->arguments = arguments;
2759 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2767 static pm_call_node_t *
2768 pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2769 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2771 node->base.location.start = message->start;
2772 node->base.location.end = pm_arguments_end(arguments);
2774 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2775 node->opening_loc = arguments->opening_loc;
2776 node->arguments = arguments->arguments;
2777 node->closing_loc = arguments->closing_loc;
2778 node->block = arguments->block;
2780 node->name = pm_parser_constant_id_token(parser, message);
2788 static pm_call_node_t *
2789 pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2790 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2792 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2793 node->arguments = arguments;
2802 static pm_call_node_t *
2803 pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2804 pm_assert_value_expression(parser, receiver);
2805 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2807 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2809 node->base.location.start = message->start;
2810 if (arguments->closing_loc.start != NULL) {
2811 node->base.location.end = arguments->closing_loc.end;
2813 assert(receiver != NULL);
2814 node->base.location.end = receiver->location.end;
2817 node->receiver = receiver;
2818 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2819 node->opening_loc = arguments->opening_loc;
2820 node->arguments = arguments->arguments;
2821 node->closing_loc = arguments->closing_loc;
2823 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2830 static pm_call_node_t *
2831 pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2832 pm_assert_value_expression(parser, receiver);
2834 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2836 node->base.location.start = receiver->location.start;
2837 node->base.location.end = pm_arguments_end(arguments);
2839 node->receiver = receiver;
2840 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2841 node->opening_loc = arguments->opening_loc;
2842 node->arguments = arguments->arguments;
2843 node->closing_loc = arguments->closing_loc;
2844 node->block = arguments->block;
2846 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2847 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2850 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2857 static pm_call_node_t *
2858 pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2859 pm_assert_value_expression(parser, receiver);
2861 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2863 node->base.location.start = operator->start;
2864 node->base.location.end = receiver->location.end;
2866 node->receiver = receiver;
2867 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2869 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2877 static pm_call_node_t *
2878 pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2879 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2881 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2882 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2884 node->name = pm_parser_constant_id_token(parser, message);
2893 pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2895 (node->message_loc.start != NULL) &&
2896 (node->message_loc.end[-1] != '!') &&
2897 (node->message_loc.end[-1] != '?') &&
2898 char_is_identifier_start(parser, node->message_loc.start) &&
2899 (node->opening_loc.start == NULL) &&
2900 (node->arguments == NULL) &&
2901 (node->block == NULL)
2909 pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2910 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2912 if (write_constant->length > 0) {
2913 size_t length = write_constant->length - 1;
2915 void *memory = xmalloc(length);
2916 memcpy(memory, write_constant->start, length);
2918 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2920 // We can get here if the message was missing because of a syntax error.
2921 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2928 static pm_call_and_write_node_t *
2929 pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2930 assert(target->block == NULL);
2931 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2932 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2934 *node = (pm_call_and_write_node_t) {
2936 .type = PM_CALL_AND_WRITE_NODE,
2937 .flags = target->base.flags,
2938 .node_id = PM_NODE_IDENTIFY(parser),
2940 .start = target->base.location.start,
2941 .end = value->location.end
2944 .receiver = target->receiver,
2945 .call_operator_loc = target->call_operator_loc,
2946 .message_loc = target->message_loc,
2948 .write_name = target->name,
2949 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2953 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2955 // Here we're going to free the target, since it is no longer necessary.
2956 // However, we don't want to call `pm_node_destroy` because we want to keep
2957 // around all of its children since we just reused them.
2968 pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2969 if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
2970 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2972 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2973 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2974 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2980 if (block != NULL) {
2981 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2989 static pm_index_and_write_node_t *
2990 pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2991 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2992 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
2994 pm_index_arguments_check(parser, target->arguments, target->block);
2996 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2997 *node = (pm_index_and_write_node_t) {
2999 .type = PM_INDEX_AND_WRITE_NODE,
3000 .flags = target->base.flags,
3001 .node_id = PM_NODE_IDENTIFY(parser),
3003 .start = target->base.location.start,
3004 .end = value->location.end
3007 .receiver = target->receiver,
3008 .call_operator_loc = target->call_operator_loc,
3009 .opening_loc = target->opening_loc,
3010 .arguments = target->arguments,
3011 .closing_loc = target->closing_loc,
3012 .block = (pm_block_argument_node_t *) target->block,
3013 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3017 // Here we're going to free the target, since it is no longer necessary.
3018 // However, we don't want to call `pm_node_destroy` because we want to keep
3019 // around all of its children since we just reused them.
3028 static pm_call_operator_write_node_t *
3029 pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3030 assert(target->block == NULL);
3031 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3033 *node = (pm_call_operator_write_node_t) {
3035 .type = PM_CALL_OPERATOR_WRITE_NODE,
3036 .flags = target->base.flags,
3037 .node_id = PM_NODE_IDENTIFY(parser),
3039 .start = target->base.location.start,
3040 .end = value->location.end
3043 .receiver = target->receiver,
3044 .call_operator_loc = target->call_operator_loc,
3045 .message_loc = target->message_loc,
3047 .write_name = target->name,
3048 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3049 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3053 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3055 // Here we're going to free the target, since it is no longer necessary.
3056 // However, we don't want to call `pm_node_destroy` because we want to keep
3057 // around all of its children since we just reused them.
3066 static pm_index_operator_write_node_t *
3067 pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3068 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3070 pm_index_arguments_check(parser, target->arguments, target->block);
3072 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3073 *node = (pm_index_operator_write_node_t) {
3075 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3076 .flags = target->base.flags,
3077 .node_id = PM_NODE_IDENTIFY(parser),
3079 .start = target->base.location.start,
3080 .end = value->location.end
3083 .receiver = target->receiver,
3084 .call_operator_loc = target->call_operator_loc,
3085 .opening_loc = target->opening_loc,
3086 .arguments = target->arguments,
3087 .closing_loc = target->closing_loc,
3088 .block = (pm_block_argument_node_t *) target->block,
3089 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3090 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3094 // Here we're going to free the target, since it is no longer necessary.
3095 // However, we don't want to call `pm_node_destroy` because we want to keep
3096 // around all of its children since we just reused them.
3105 static pm_call_or_write_node_t *
3106 pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3107 assert(target->block == NULL);
3108 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3109 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3111 *node = (pm_call_or_write_node_t) {
3113 .type = PM_CALL_OR_WRITE_NODE,
3114 .flags = target->base.flags,
3115 .node_id = PM_NODE_IDENTIFY(parser),
3117 .start = target->base.location.start,
3118 .end = value->location.end
3121 .receiver = target->receiver,
3122 .call_operator_loc = target->call_operator_loc,
3123 .message_loc = target->message_loc,
3125 .write_name = target->name,
3126 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3130 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
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.
3143 static pm_index_or_write_node_t *
3144 pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3145 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3146 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3148 pm_index_arguments_check(parser, target->arguments, target->block);
3150 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3151 *node = (pm_index_or_write_node_t) {
3153 .type = PM_INDEX_OR_WRITE_NODE,
3154 .flags = target->base.flags,
3155 .node_id = PM_NODE_IDENTIFY(parser),
3157 .start = target->base.location.start,
3158 .end = value->location.end
3161 .receiver = target->receiver,
3162 .call_operator_loc = target->call_operator_loc,
3163 .opening_loc = target->opening_loc,
3164 .arguments = target->arguments,
3165 .closing_loc = target->closing_loc,
3166 .block = (pm_block_argument_node_t *) target->block,
3167 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3171 // Here we're going to free the target, since it is no longer necessary.
3172 // However, we don't want to call `pm_node_destroy` because we want to keep
3173 // around all of its children since we just reused them.
3183 static pm_call_target_node_t *
3184 pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3185 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3187 *node = (pm_call_target_node_t) {
3189 .type = PM_CALL_TARGET_NODE,
3190 .flags = target->base.flags,
3191 .node_id = PM_NODE_IDENTIFY(parser),
3192 .location = target->base.location
3194 .receiver = target->receiver,
3195 .call_operator_loc = target->call_operator_loc,
3196 .name = target->name,
3197 .message_loc = target->message_loc
3200 // Here we're going to free the target, since it is no longer necessary.
3201 // However, we don't want to call `pm_node_destroy` because we want to keep
3202 // around all of its children since we just reused them.
3212 static pm_index_target_node_t *
3213 pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3214 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3215 pm_node_flags_t flags = target->base.flags;
3217 pm_index_arguments_check(parser, target->arguments, target->block);
3219 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3220 *node = (pm_index_target_node_t) {
3222 .type = PM_INDEX_TARGET_NODE,
3223 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3224 .node_id = PM_NODE_IDENTIFY(parser),
3225 .location = target->base.location
3227 .receiver = target->receiver,
3228 .opening_loc = target->opening_loc,
3229 .arguments = target->arguments,
3230 .closing_loc = target->closing_loc,
3231 .block = (pm_block_argument_node_t *) target->block,
3234 // Here we're going to free the target, since it is no longer necessary.
3235 // However, we don't want to call `pm_node_destroy` because we want to keep
3236 // around all of its children since we just reused them.
3245 static pm_capture_pattern_node_t *
3246 pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3247 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3249 *node = (pm_capture_pattern_node_t) {
3251 .type = PM_CAPTURE_PATTERN_NODE,
3252 .node_id = PM_NODE_IDENTIFY(parser),
3254 .start = value->location.start,
3255 .end = target->base.location.end
3260 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3269 static pm_case_node_t *
3270 pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3271 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3273 *node = (pm_case_node_t) {
3275 .type = PM_CASE_NODE,
3276 .node_id = PM_NODE_IDENTIFY(parser),
3278 .start = case_keyword->start,
3279 .end = end_keyword->end
3282 .predicate = predicate,
3283 .else_clause = NULL,
3284 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3285 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3296 pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3297 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3299 pm_node_list_append(&node->conditions, condition);
3300 node->base.location.end = condition->location.end;
3307 pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3308 node->else_clause = else_clause;
3309 node->base.location.end = else_clause->base.location.end;
3316 pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3317 node->base.location.end = end_keyword->end;
3318 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3324 static pm_case_match_node_t *
3325 pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3326 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3328 *node = (pm_case_match_node_t) {
3330 .type = PM_CASE_MATCH_NODE,
3331 .node_id = PM_NODE_IDENTIFY(parser),
3333 .start = case_keyword->start,
3334 .end = end_keyword->end
3337 .predicate = predicate,
3338 .else_clause = NULL,
3339 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3340 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3351 pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3352 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3354 pm_node_list_append(&node->conditions, condition);
3355 node->base.location.end = condition->location.end;
3362 pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3363 node->else_clause = else_clause;
3364 node->base.location.end = else_clause->base.location.end;
3371 pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3372 node->base.location.end = end_keyword->end;
3373 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3379 static pm_class_node_t *
3380 pm_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) {
3381 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3383 *node = (pm_class_node_t) {
3385 .type = PM_CLASS_NODE,
3386 .node_id = PM_NODE_IDENTIFY(parser),
3387 .location = { .start = class_keyword->start, .end = end_keyword->end },
3390 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3391 .constant_path = constant_path,
3392 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3393 .superclass = superclass,
3395 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3396 .name = pm_parser_constant_id_token(parser, name)
3405 static pm_class_variable_and_write_node_t *
3406 pm_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) {
3407 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3408 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3410 *node = (pm_class_variable_and_write_node_t) {
3412 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3413 .node_id = PM_NODE_IDENTIFY(parser),
3415 .start = target->base.location.start,
3416 .end = value->location.end
3419 .name = target->name,
3420 .name_loc = target->base.location,
3421 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3431 static pm_class_variable_operator_write_node_t *
3432 pm_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) {
3433 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3435 *node = (pm_class_variable_operator_write_node_t) {
3437 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3438 .node_id = PM_NODE_IDENTIFY(parser),
3440 .start = target->base.location.start,
3441 .end = value->location.end
3444 .name = target->name,
3445 .name_loc = target->base.location,
3446 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3448 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3457 static pm_class_variable_or_write_node_t *
3458 pm_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) {
3459 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3460 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3462 *node = (pm_class_variable_or_write_node_t) {
3464 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3465 .node_id = PM_NODE_IDENTIFY(parser),
3467 .start = target->base.location.start,
3468 .end = value->location.end
3471 .name = target->name,
3472 .name_loc = target->base.location,
3473 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3483 static pm_class_variable_read_node_t *
3484 pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3485 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3486 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3488 *node = (pm_class_variable_read_node_t) {
3490 .type = PM_CLASS_VARIABLE_READ_NODE,
3491 .node_id = PM_NODE_IDENTIFY(parser),
3492 .location = PM_LOCATION_TOKEN_VALUE(token)
3494 .name = pm_parser_constant_id_token(parser, token)
3506 static inline pm_node_flags_t
3507 pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3508 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3517 static pm_class_variable_write_node_t *
3518 pm_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) {
3519 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3521 *node = (pm_class_variable_write_node_t) {
3523 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3524 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3525 .node_id = PM_NODE_IDENTIFY(parser),
3527 .start = read_node->base.location.start,
3528 .end = value->location.end
3531 .name = read_node->name,
3532 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3533 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3543 static pm_constant_path_and_write_node_t *
3544 pm_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) {
3545 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3546 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3548 *node = (pm_constant_path_and_write_node_t) {
3550 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3551 .node_id = PM_NODE_IDENTIFY(parser),
3553 .start = target->base.location.start,
3554 .end = value->location.end
3558 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3568 static pm_constant_path_operator_write_node_t *
3569 pm_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) {
3570 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3572 *node = (pm_constant_path_operator_write_node_t) {
3574 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3575 .node_id = PM_NODE_IDENTIFY(parser),
3577 .start = target->base.location.start,
3578 .end = value->location.end
3582 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3584 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3593 static pm_constant_path_or_write_node_t *
3594 pm_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) {
3595 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3596 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3598 *node = (pm_constant_path_or_write_node_t) {
3600 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3601 .node_id = PM_NODE_IDENTIFY(parser),
3603 .start = target->base.location.start,
3604 .end = value->location.end
3608 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3618 static pm_constant_path_node_t *
3619 pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3620 pm_assert_value_expression(parser, parent);
3621 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3623 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3624 if (name_token->type == PM_TOKEN_CONSTANT) {
3625 name = pm_parser_constant_id_token(parser, name_token);
3628 *node = (pm_constant_path_node_t) {
3630 .type = PM_CONSTANT_PATH_NODE,
3631 .node_id = PM_NODE_IDENTIFY(parser),
3633 .start = parent == NULL ? delimiter->start : parent->location.start,
3634 .end = name_token->end
3639 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3640 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3649 static pm_constant_path_write_node_t *
3650 pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3651 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3653 *node = (pm_constant_path_write_node_t) {
3655 .type = PM_CONSTANT_PATH_WRITE_NODE,
3656 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3657 .node_id = PM_NODE_IDENTIFY(parser),
3659 .start = target->base.location.start,
3660 .end = value->location.end
3664 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3674 static pm_constant_and_write_node_t *
3675 pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3676 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3677 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3679 *node = (pm_constant_and_write_node_t) {
3681 .type = PM_CONSTANT_AND_WRITE_NODE,
3682 .node_id = PM_NODE_IDENTIFY(parser),
3684 .start = target->base.location.start,
3685 .end = value->location.end
3688 .name = target->name,
3689 .name_loc = target->base.location,
3690 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3700 static pm_constant_operator_write_node_t *
3701 pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3702 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3704 *node = (pm_constant_operator_write_node_t) {
3706 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3707 .node_id = PM_NODE_IDENTIFY(parser),
3709 .start = target->base.location.start,
3710 .end = value->location.end
3713 .name = target->name,
3714 .name_loc = target->base.location,
3715 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3717 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3726 static pm_constant_or_write_node_t *
3727 pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3728 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3729 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3731 *node = (pm_constant_or_write_node_t) {
3733 .type = PM_CONSTANT_OR_WRITE_NODE,
3734 .node_id = PM_NODE_IDENTIFY(parser),
3736 .start = target->base.location.start,
3737 .end = value->location.end
3740 .name = target->name,
3741 .name_loc = target->base.location,
3742 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3752 static pm_constant_read_node_t *
3753 pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3754 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3755 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3757 *node = (pm_constant_read_node_t) {
3759 .type = PM_CONSTANT_READ_NODE,
3760 .node_id = PM_NODE_IDENTIFY(parser),
3761 .location = PM_LOCATION_TOKEN_VALUE(name)
3763 .name = pm_parser_constant_id_token(parser, name)
3772 static pm_constant_write_node_t *
3773 pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3774 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3776 *node = (pm_constant_write_node_t) {
3778 .type = PM_CONSTANT_WRITE_NODE,
3779 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3780 .node_id = PM_NODE_IDENTIFY(parser),
3782 .start = target->base.location.start,
3783 .end = value->location.end
3786 .name = target->name,
3787 .name_loc = target->base.location,
3788 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3799 pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3800 switch (PM_NODE_TYPE(node)) {
3801 case PM_BEGIN_NODE: {
3802 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3803 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3806 case PM_PARENTHESES_NODE: {
3807 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3808 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3811 case PM_STATEMENTS_NODE: {
3812 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3813 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3818 case PM_IMAGINARY_NODE:
3819 case PM_INTEGER_NODE:
3820 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3821 case PM_INTERPOLATED_STRING_NODE:
3822 case PM_INTERPOLATED_SYMBOL_NODE:
3823 case PM_INTERPOLATED_X_STRING_NODE:
3824 case PM_RATIONAL_NODE:
3825 case PM_REGULAR_EXPRESSION_NODE:
3826 case PM_SOURCE_ENCODING_NODE:
3827 case PM_SOURCE_FILE_NODE:
3828 case PM_SOURCE_LINE_NODE:
3829 case PM_STRING_NODE:
3830 case PM_SYMBOL_NODE:
3831 case PM_X_STRING_NODE:
3832 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3842 static pm_def_node_t *
3844 pm_parser_t *parser,
3845 pm_constant_id_t name,
3846 const pm_token_t *name_loc,
3847 pm_node_t *receiver,
3848 pm_parameters_node_t *parameters,
3850 pm_constant_id_list_t *locals,
3851 const pm_token_t *def_keyword,
3852 const pm_token_t *operator,
3853 const pm_token_t *lparen,
3854 const pm_token_t *rparen,
3855 const pm_token_t *equal,
3856 const pm_token_t *end_keyword
3858 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3861 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3862 end = body->location.end;
3864 end = end_keyword->end;
3867 if ((receiver != NULL) && PM_NODE_TYPE_P(receiver, PM_PARENTHESES_NODE)) {
3868 pm_def_node_receiver_check(parser, receiver);
3871 *node = (pm_def_node_t) {
3873 .type = PM_DEF_NODE,
3874 .node_id = PM_NODE_IDENTIFY(parser),
3875 .location = { .start = def_keyword->start, .end = end },
3878 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3879 .receiver = receiver,
3880 .parameters = parameters,
3883 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3884 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3885 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3886 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3887 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3888 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3897 static pm_defined_node_t *
3898 pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_location_t *keyword_loc) {
3899 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3901 *node = (pm_defined_node_t) {
3903 .type = PM_DEFINED_NODE,
3904 .node_id = PM_NODE_IDENTIFY(parser),
3906 .start = keyword_loc->start,
3907 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3910 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3912 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3913 .keyword_loc = *keyword_loc
3922 static pm_else_node_t *
3923 pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3924 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3925 const uint8_t *end = NULL;
3926 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3927 end = statements->base.location.end;
3929 end = end_keyword->end;
3932 *node = (pm_else_node_t) {
3934 .type = PM_ELSE_NODE,
3935 .node_id = PM_NODE_IDENTIFY(parser),
3937 .start = else_keyword->start,
3941 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3942 .statements = statements,
3943 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3952 static pm_embedded_statements_node_t *
3953 pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3954 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3956 *node = (pm_embedded_statements_node_t) {
3958 .type = PM_EMBEDDED_STATEMENTS_NODE,
3959 .node_id = PM_NODE_IDENTIFY(parser),
3961 .start = opening->start,
3965 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3966 .statements = statements,
3967 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3976 static pm_embedded_variable_node_t *
3977 pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3978 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3980 *node = (pm_embedded_variable_node_t) {
3982 .type = PM_EMBEDDED_VARIABLE_NODE,
3983 .node_id = PM_NODE_IDENTIFY(parser),
3985 .start = operator->start,
3986 .end = variable->location.end
3989 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3990 .variable = variable
3999 static pm_ensure_node_t *
4000 pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4001 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4003 *node = (pm_ensure_node_t) {
4005 .type = PM_ENSURE_NODE,
4006 .node_id = PM_NODE_IDENTIFY(parser),
4008 .start = ensure_keyword->start,
4009 .end = end_keyword->end
4012 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4013 .statements = statements,
4014 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4023 static pm_false_node_t *
4024 pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4025 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4026 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4028 *node = (pm_false_node_t) {{
4029 .type = PM_FALSE_NODE,
4030 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4031 .node_id = PM_NODE_IDENTIFY(parser),
4032 .location = PM_LOCATION_TOKEN_VALUE(token)
4042 static pm_find_pattern_node_t *
4043 pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4044 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4046 pm_node_t *left = nodes->nodes[0];
4047 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4048 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4052 if (nodes->size == 1) {
4053 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4055 right = nodes->nodes[nodes->size - 1];
4056 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4059 #if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4060 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4061 // The resulting AST will anyway be ignored, but this file still needs to compile.
4062 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4064 pm_node_t *right_splat_node = right;
4066 *node = (pm_find_pattern_node_t) {
4068 .type = PM_FIND_PATTERN_NODE,
4069 .node_id = PM_NODE_IDENTIFY(parser),
4071 .start = left->location.start,
4072 .end = right->location.end,
4076 .left = left_splat_node,
4077 .right = right_splat_node,
4079 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4080 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4083 // For now we're going to just copy over each pointer manually. This could be
4084 // much more efficient, as we could instead resize the node list to only point
4086 for (size_t index = 1; index < nodes->size - 1; index++) {
4087 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4098 pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4099 ptrdiff_t diff = token->end - token->start;
4100 if (diff <= 0) return 0.0;
4102 // First, get a buffer of the content.
4103 size_t length = (size_t) diff;
4104 char *buffer = xmalloc(sizeof(char) * (length + 1));
4105 memcpy((void *) buffer, token->start, length);
4107 // Next, determine if we need to replace the decimal point because of
4108 // locale-specific options, and then normalize them if we have to.
4109 char decimal_point = *localeconv()->decimal_point;
4110 if (decimal_point != '.') {
4111 for (size_t index = 0; index < length; index++) {
4112 if (buffer[index] == '.') buffer[index] = decimal_point;
4116 // Next, handle underscores by removing them from the buffer.
4117 for (size_t index = 0; index < length; index++) {
4118 if (buffer[index] == '_') {
4119 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4124 // Null-terminate the buffer so that strtod cannot read off the end.
4125 buffer[length] = '\0';
4127 // Now, call strtod to parse the value. Note that CRuby has their own
4128 // version of strtod which avoids locales. We're okay using the locale-aware
4129 // version because we've already validated through the parser that the token
4130 // is in a valid format.
4133 double value = strtod(buffer, &eptr);
4135 // This should never happen, because we've already checked that the token
4136 // is in a valid format. However it's good to be safe.
4137 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4138 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4139 xfree((void *) buffer);
4143 // If errno is set, then it should only be ERANGE. At this point we need to
4144 // check if it's infinity (it should be).
4154 const char *ellipsis;
4160 warn_width = (int) length;
4164 pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
4165 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4168 // Finally we can free the buffer and return the value.
4169 xfree((void *) buffer);
4176 static pm_float_node_t *
4177 pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4178 assert(token->type == PM_TOKEN_FLOAT);
4179 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4181 *node = (pm_float_node_t) {
4183 .type = PM_FLOAT_NODE,
4184 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4185 .node_id = PM_NODE_IDENTIFY(parser),
4186 .location = PM_LOCATION_TOKEN_VALUE(token)
4188 .value = pm_double_parse(parser, token)
4197 static pm_imaginary_node_t *
4198 pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4199 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4201 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4202 *node = (pm_imaginary_node_t) {
4204 .type = PM_IMAGINARY_NODE,
4205 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4206 .node_id = PM_NODE_IDENTIFY(parser),
4207 .location = PM_LOCATION_TOKEN_VALUE(token)
4209 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4210 .type = PM_TOKEN_FLOAT,
4211 .start = token->start,
4212 .end = token->end - 1
4222 static pm_rational_node_t *
4223 pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4224 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4226 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4227 *node = (pm_rational_node_t) {
4229 .type = PM_RATIONAL_NODE,
4230 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4231 .node_id = PM_NODE_IDENTIFY(parser),
4232 .location = PM_LOCATION_TOKEN_VALUE(token)
4235 .denominator = { 0 }
4238 const uint8_t *start = token->start;
4239 const uint8_t *end = token->end - 1; // r
4241 while (start < end && *start == '0') start++; // 0.1 -> .1
4242 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4244 size_t length = (size_t) (end - start);
4246 node->denominator.value = 1;
4250 const uint8_t *point = memchr(start, '.', length);
4251 assert(point && "should have a decimal point");
4253 uint8_t *digits = malloc(length);
4254 if (digits == NULL) {
4255 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4259 memcpy(digits, start, (unsigned long) (point - start));
4260 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4261 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4264 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4265 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4268 pm_integers_reduce(&node->numerator, &node->denominator);
4276 static pm_imaginary_node_t *
4277 pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4278 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4280 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4281 *node = (pm_imaginary_node_t) {
4283 .type = PM_IMAGINARY_NODE,
4284 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4285 .node_id = PM_NODE_IDENTIFY(parser),
4286 .location = PM_LOCATION_TOKEN_VALUE(token)
4288 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4289 .type = PM_TOKEN_FLOAT_RATIONAL,
4290 .start = token->start,
4291 .end = token->end - 1
4301 static pm_for_node_t *
4303 pm_parser_t *parser,
4305 pm_node_t *collection,
4306 pm_statements_node_t *statements,
4307 const pm_token_t *for_keyword,
4308 const pm_token_t *in_keyword,
4309 const pm_token_t *do_keyword,
4310 const pm_token_t *end_keyword
4312 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4314 *node = (pm_for_node_t) {
4316 .type = PM_FOR_NODE,
4317 .node_id = PM_NODE_IDENTIFY(parser),
4319 .start = for_keyword->start,
4320 .end = end_keyword->end
4324 .collection = collection,
4325 .statements = statements,
4326 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4327 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4328 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4329 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4338 static pm_forwarding_arguments_node_t *
4339 pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4340 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4341 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4343 *node = (pm_forwarding_arguments_node_t) {{
4344 .type = PM_FORWARDING_ARGUMENTS_NODE,
4345 .node_id = PM_NODE_IDENTIFY(parser),
4346 .location = PM_LOCATION_TOKEN_VALUE(token)
4355 static pm_forwarding_parameter_node_t *
4356 pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4357 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4358 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4360 *node = (pm_forwarding_parameter_node_t) {{
4361 .type = PM_FORWARDING_PARAMETER_NODE,
4362 .node_id = PM_NODE_IDENTIFY(parser),
4363 .location = PM_LOCATION_TOKEN_VALUE(token)
4372 static pm_forwarding_super_node_t *
4373 pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4374 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4375 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4376 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4378 pm_block_node_t *block = NULL;
4379 if (arguments->block != NULL) {
4380 block = (pm_block_node_t *) arguments->block;
4383 *node = (pm_forwarding_super_node_t) {
4385 .type = PM_FORWARDING_SUPER_NODE,
4386 .node_id = PM_NODE_IDENTIFY(parser),
4388 .start = token->start,
4389 .end = block != NULL ? block->base.location.end : token->end
4402 static pm_hash_pattern_node_t *
4403 pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4404 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4406 *node = (pm_hash_pattern_node_t) {
4408 .type = PM_HASH_PATTERN_NODE,
4409 .node_id = PM_NODE_IDENTIFY(parser),
4411 .start = opening->start,
4416 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4417 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4428 static pm_hash_pattern_node_t *
4429 pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4430 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4432 const uint8_t *start;
4435 if (elements->size > 0) {
4437 start = elements->nodes[0]->location.start;
4438 end = rest->location.end;
4440 start = elements->nodes[0]->location.start;
4441 end = elements->nodes[elements->size - 1]->location.end;
4444 assert(rest != NULL);
4445 start = rest->location.start;
4446 end = rest->location.end;
4449 *node = (pm_hash_pattern_node_t) {
4451 .type = PM_HASH_PATTERN_NODE,
4452 .node_id = PM_NODE_IDENTIFY(parser),
4461 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4462 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4466 PM_NODE_LIST_FOREACH(elements, index, element) {
4467 pm_node_list_append(&node->elements, element);
4476 static pm_constant_id_t
4477 pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4478 switch (PM_NODE_TYPE(target)) {
4479 case PM_GLOBAL_VARIABLE_READ_NODE:
4480 return ((pm_global_variable_read_node_t *) target)->name;
4481 case PM_BACK_REFERENCE_READ_NODE:
4482 return ((pm_back_reference_read_node_t *) target)->name;
4483 case PM_NUMBERED_REFERENCE_READ_NODE:
4484 // This will only ever happen in the event of a syntax error, but we
4485 // still need to provide something for the node.
4486 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4488 assert(false && "unreachable");
4489 return (pm_constant_id_t) -1;
4496 static pm_global_variable_and_write_node_t *
4497 pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4498 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4499 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4501 *node = (pm_global_variable_and_write_node_t) {
4503 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4504 .node_id = PM_NODE_IDENTIFY(parser),
4506 .start = target->location.start,
4507 .end = value->location.end
4510 .name = pm_global_variable_write_name(parser, target),
4511 .name_loc = target->location,
4512 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4522 static pm_global_variable_operator_write_node_t *
4523 pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4524 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4526 *node = (pm_global_variable_operator_write_node_t) {
4528 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4529 .node_id = PM_NODE_IDENTIFY(parser),
4531 .start = target->location.start,
4532 .end = value->location.end
4535 .name = pm_global_variable_write_name(parser, target),
4536 .name_loc = target->location,
4537 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4539 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4548 static pm_global_variable_or_write_node_t *
4549 pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4550 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4551 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4553 *node = (pm_global_variable_or_write_node_t) {
4555 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4556 .node_id = PM_NODE_IDENTIFY(parser),
4558 .start = target->location.start,
4559 .end = value->location.end
4562 .name = pm_global_variable_write_name(parser, target),
4563 .name_loc = target->location,
4564 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4574 static pm_global_variable_read_node_t *
4575 pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4576 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4578 *node = (pm_global_variable_read_node_t) {
4580 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4581 .node_id = PM_NODE_IDENTIFY(parser),
4582 .location = PM_LOCATION_TOKEN_VALUE(name),
4584 .name = pm_parser_constant_id_token(parser, name)
4593 static pm_global_variable_read_node_t *
4594 pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4595 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4597 *node = (pm_global_variable_read_node_t) {
4599 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4600 .node_id = PM_NODE_IDENTIFY(parser),
4601 .location = PM_LOCATION_NULL_VALUE(parser)
4612 static pm_global_variable_write_node_t *
4613 pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4614 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4616 *node = (pm_global_variable_write_node_t) {
4618 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4619 .node_id = PM_NODE_IDENTIFY(parser),
4620 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4622 .start = target->location.start,
4623 .end = value->location.end
4626 .name = pm_global_variable_write_name(parser, target),
4627 .name_loc = PM_LOCATION_NODE_VALUE(target),
4628 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4638 static pm_global_variable_write_node_t *
4639 pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4640 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4642 *node = (pm_global_variable_write_node_t) {
4644 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4645 .node_id = PM_NODE_IDENTIFY(parser),
4646 .location = PM_LOCATION_NULL_VALUE(parser)
4649 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4650 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4660 static pm_hash_node_t *
4661 pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4662 assert(opening != NULL);
4663 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4665 *node = (pm_hash_node_t) {
4667 .type = PM_HASH_NODE,
4668 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4669 .node_id = PM_NODE_IDENTIFY(parser),
4670 .location = PM_LOCATION_TOKEN_VALUE(opening)
4672 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4673 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4684 pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4685 pm_node_list_append(&hash->elements, element);
4687 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4688 if (static_literal) {
4689 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4690 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);
4691 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4692 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4695 if (!static_literal) {
4696 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4701 pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4702 hash->base.location.end = token->end;
4703 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4709 static pm_if_node_t *
4710 pm_if_node_create(pm_parser_t *parser,
4711 const pm_token_t *if_keyword,
4712 pm_node_t *predicate,
4713 const pm_token_t *then_keyword,
4714 pm_statements_node_t *statements,
4715 pm_node_t *subsequent,
4716 const pm_token_t *end_keyword
4718 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4719 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4722 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4723 end = end_keyword->end;
4724 } else if (subsequent != NULL) {
4725 end = subsequent->location.end;
4726 } else if (pm_statements_node_body_length(statements) != 0) {
4727 end = statements->base.location.end;
4729 end = predicate->location.end;
4732 *node = (pm_if_node_t) {
4735 .flags = PM_NODE_FLAG_NEWLINE,
4736 .node_id = PM_NODE_IDENTIFY(parser),
4738 .start = if_keyword->start,
4742 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4743 .predicate = predicate,
4744 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4745 .statements = statements,
4746 .subsequent = subsequent,
4747 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4756 static pm_if_node_t *
4757 pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4758 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4759 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4761 pm_statements_node_t *statements = pm_statements_node_create(parser);
4762 pm_statements_node_body_append(parser, statements, statement, true);
4764 *node = (pm_if_node_t) {
4767 .flags = PM_NODE_FLAG_NEWLINE,
4768 .node_id = PM_NODE_IDENTIFY(parser),
4770 .start = statement->location.start,
4771 .end = predicate->location.end
4774 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4775 .predicate = predicate,
4776 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4777 .statements = statements,
4779 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4788 static pm_if_node_t *
4789 pm_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) {
4790 pm_assert_value_expression(parser, predicate);
4791 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4793 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4794 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4796 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4797 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4799 pm_token_t end_keyword = not_provided(parser);
4800 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4802 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4804 *node = (pm_if_node_t) {
4807 .flags = PM_NODE_FLAG_NEWLINE,
4808 .node_id = PM_NODE_IDENTIFY(parser),
4810 .start = predicate->location.start,
4811 .end = false_expression->location.end,
4814 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4815 .predicate = predicate,
4816 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4817 .statements = if_statements,
4818 .subsequent = (pm_node_t *) else_node,
4819 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4827 pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4828 node->base.location.end = keyword->end;
4829 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4833 pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4834 node->base.location.end = keyword->end;
4835 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4841 static pm_implicit_node_t *
4842 pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4843 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4845 *node = (pm_implicit_node_t) {
4847 .type = PM_IMPLICIT_NODE,
4848 .node_id = PM_NODE_IDENTIFY(parser),
4849 .location = value->location
4860 static pm_implicit_rest_node_t *
4861 pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4862 assert(token->type == PM_TOKEN_COMMA);
4864 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4866 *node = (pm_implicit_rest_node_t) {
4868 .type = PM_IMPLICIT_REST_NODE,
4869 .node_id = PM_NODE_IDENTIFY(parser),
4870 .location = PM_LOCATION_TOKEN_VALUE(token)
4880 static pm_integer_node_t *
4881 pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4882 assert(token->type == PM_TOKEN_INTEGER);
4883 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4885 *node = (pm_integer_node_t) {
4887 .type = PM_INTEGER_NODE,
4888 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4889 .node_id = PM_NODE_IDENTIFY(parser),
4890 .location = PM_LOCATION_TOKEN_VALUE(token)
4895 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4897 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4898 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4899 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4900 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4901 default: assert(false && "unreachable"); break;
4904 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4912 static pm_imaginary_node_t *
4913 pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4914 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4916 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4917 *node = (pm_imaginary_node_t) {
4919 .type = PM_IMAGINARY_NODE,
4920 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4921 .node_id = PM_NODE_IDENTIFY(parser),
4922 .location = PM_LOCATION_TOKEN_VALUE(token)
4924 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4925 .type = PM_TOKEN_INTEGER,
4926 .start = token->start,
4927 .end = token->end - 1
4938 static pm_rational_node_t *
4939 pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4940 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4942 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4943 *node = (pm_rational_node_t) {
4945 .type = PM_RATIONAL_NODE,
4946 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4947 .node_id = PM_NODE_IDENTIFY(parser),
4948 .location = PM_LOCATION_TOKEN_VALUE(token)
4951 .denominator = { .value = 1, 0 }
4954 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4956 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4957 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4958 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4959 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4960 default: assert(false && "unreachable"); break;
4963 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4972 static pm_imaginary_node_t *
4973 pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4974 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4976 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4977 *node = (pm_imaginary_node_t) {
4979 .type = PM_IMAGINARY_NODE,
4980 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4981 .node_id = PM_NODE_IDENTIFY(parser),
4982 .location = PM_LOCATION_TOKEN_VALUE(token)
4984 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4985 .type = PM_TOKEN_INTEGER_RATIONAL,
4986 .start = token->start,
4987 .end = token->end - 1
4997 static pm_in_node_t *
4998 pm_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) {
4999 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
5002 if (statements != NULL) {
5003 end = statements->base.location.end;
5004 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
5005 end = then_keyword->end;
5007 end = pattern->location.end;
5010 *node = (pm_in_node_t) {
5013 .node_id = PM_NODE_IDENTIFY(parser),
5015 .start = in_keyword->start,
5020 .statements = statements,
5021 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5022 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5031 static pm_instance_variable_and_write_node_t *
5032 pm_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) {
5033 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5034 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5036 *node = (pm_instance_variable_and_write_node_t) {
5038 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5039 .node_id = PM_NODE_IDENTIFY(parser),
5041 .start = target->base.location.start,
5042 .end = value->location.end
5045 .name = target->name,
5046 .name_loc = target->base.location,
5047 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5057 static pm_instance_variable_operator_write_node_t *
5058 pm_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) {
5059 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5061 *node = (pm_instance_variable_operator_write_node_t) {
5063 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5064 .node_id = PM_NODE_IDENTIFY(parser),
5066 .start = target->base.location.start,
5067 .end = value->location.end
5070 .name = target->name,
5071 .name_loc = target->base.location,
5072 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5074 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5083 static pm_instance_variable_or_write_node_t *
5084 pm_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) {
5085 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5086 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5088 *node = (pm_instance_variable_or_write_node_t) {
5090 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5091 .node_id = PM_NODE_IDENTIFY(parser),
5093 .start = target->base.location.start,
5094 .end = value->location.end
5097 .name = target->name,
5098 .name_loc = target->base.location,
5099 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5109 static pm_instance_variable_read_node_t *
5110 pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5111 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5112 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5114 *node = (pm_instance_variable_read_node_t) {
5116 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5117 .node_id = PM_NODE_IDENTIFY(parser),
5118 .location = PM_LOCATION_TOKEN_VALUE(token)
5120 .name = pm_parser_constant_id_token(parser, token)
5130 static pm_instance_variable_write_node_t *
5131 pm_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) {
5132 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5133 *node = (pm_instance_variable_write_node_t) {
5135 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5136 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5137 .node_id = PM_NODE_IDENTIFY(parser),
5139 .start = read_node->base.location.start,
5140 .end = value->location.end
5143 .name = read_node->name,
5144 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5145 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5158 pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5159 switch (PM_NODE_TYPE(part)) {
5160 case PM_STRING_NODE:
5161 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5163 case PM_EMBEDDED_STATEMENTS_NODE: {
5164 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5165 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5167 if (embedded == NULL) {
5168 // If there are no statements or more than one statement, then
5169 // we lose the static literal flag.
5170 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5171 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5172 // If the embedded statement is a string, then we can keep the
5173 // static literal flag and mark the string as frozen.
5174 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5175 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5176 // If the embedded statement is an interpolated string and it's
5177 // a static literal, then we can keep the static literal flag.
5179 // Otherwise we lose the static literal flag.
5180 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5185 case PM_EMBEDDED_VARIABLE_NODE:
5186 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5189 assert(false && "unexpected node type");
5193 pm_node_list_append(parts, part);
5199 static pm_interpolated_regular_expression_node_t *
5200 pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5201 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5203 *node = (pm_interpolated_regular_expression_node_t) {
5205 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5206 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5207 .node_id = PM_NODE_IDENTIFY(parser),
5209 .start = opening->start,
5213 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5214 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5222 pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5223 if (node->base.location.start > part->location.start) {
5224 node->base.location.start = part->location.start;
5226 if (node->base.location.end < part->location.end) {
5227 node->base.location.end = part->location.end;
5230 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5234 pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5235 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5236 node->base.location.end = closing->end;
5237 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5264 pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5265 #define CLEAR_FLAGS(node) \
5266 node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
5268 #define MUTABLE_FLAGS(node) \
5269 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5271 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5272 node->base.location.start = part->location.start;
5275 node->base.location.end = MAX(node->base.location.end, part->location.end);
5277 switch (PM_NODE_TYPE(part)) {
5278 case PM_STRING_NODE:
5279 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5281 case PM_INTERPOLATED_STRING_NODE:
5282 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5283 // If the string that we're concatenating is a static literal,
5284 // then we can keep the static literal flag for this string.
5286 // Otherwise, we lose the static literal flag here and we should
5287 // also clear the mutability flags.
5291 case PM_EMBEDDED_STATEMENTS_NODE: {
5292 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5293 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5295 if (embedded == NULL) {
5296 // If we're embedding multiple statements or no statements, then
5297 // the string is not longer a static literal.
5299 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5300 // If the embedded statement is a string, then we can make that
5301 // string as frozen and static literal, and not touch the static
5302 // literal status of this string.
5303 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5305 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5306 MUTABLE_FLAGS(node);
5308 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5309 // If the embedded statement is an interpolated string, but that
5310 // string is marked as static literal, then we can keep our
5311 // static literal status for this string.
5312 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5313 MUTABLE_FLAGS(node);
5316 // In all other cases, we lose the static literal flag here and
5323 case PM_EMBEDDED_VARIABLE_NODE:
5324 // Embedded variables clear static literal, which means we also
5325 // should clear the mutability flags.
5329 assert(false && "unexpected node type");
5333 pm_node_list_append(&node->parts, part);
5336 #undef MUTABLE_FLAGS
5342 static pm_interpolated_string_node_t *
5343 pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5344 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5345 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5347 switch (parser->frozen_string_literal) {
5348 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5349 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5351 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5352 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5356 *node = (pm_interpolated_string_node_t) {
5358 .type = PM_INTERPOLATED_STRING_NODE,
5360 .node_id = PM_NODE_IDENTIFY(parser),
5362 .start = opening->start,
5363 .end = closing->end,
5366 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5367 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5371 if (parts != NULL) {
5373 PM_NODE_LIST_FOREACH(parts, index, part) {
5374 pm_interpolated_string_node_append(node, part);
5385 pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5386 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5387 node->base.location.end = closing->end;
5391 pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5392 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5393 node->base.location.start = part->location.start;
5396 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5397 node->base.location.end = MAX(node->base.location.end, part->location.end);
5401 pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5402 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5403 node->base.location.end = closing->end;
5409 static pm_interpolated_symbol_node_t *
5410 pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5411 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5413 *node = (pm_interpolated_symbol_node_t) {
5415 .type = PM_INTERPOLATED_SYMBOL_NODE,
5416 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5417 .node_id = PM_NODE_IDENTIFY(parser),
5419 .start = opening->start,
5420 .end = closing->end,
5423 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5424 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5428 if (parts != NULL) {
5430 PM_NODE_LIST_FOREACH(parts, index, part) {
5431 pm_interpolated_symbol_node_append(node, part);
5441 static pm_interpolated_x_string_node_t *
5442 pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5443 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5445 *node = (pm_interpolated_x_string_node_t) {
5447 .type = PM_INTERPOLATED_X_STRING_NODE,
5448 .node_id = PM_NODE_IDENTIFY(parser),
5450 .start = opening->start,
5454 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5455 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5463 pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5464 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5465 node->base.location.end = part->location.end;
5469 pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5470 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5471 node->base.location.end = closing->end;
5477 static pm_it_local_variable_read_node_t *
5478 pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5479 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5481 *node = (pm_it_local_variable_read_node_t) {
5483 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5484 .node_id = PM_NODE_IDENTIFY(parser),
5485 .location = PM_LOCATION_TOKEN_VALUE(name)
5495 static pm_it_parameters_node_t *
5496 pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5497 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5499 *node = (pm_it_parameters_node_t) {
5501 .type = PM_IT_PARAMETERS_NODE,
5502 .node_id = PM_NODE_IDENTIFY(parser),
5504 .start = opening->start,
5516 static pm_keyword_hash_node_t *
5517 pm_keyword_hash_node_create(pm_parser_t *parser) {
5518 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5520 *node = (pm_keyword_hash_node_t) {
5522 .type = PM_KEYWORD_HASH_NODE,
5523 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5524 .node_id = PM_NODE_IDENTIFY(parser),
5525 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5537 pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5538 // If the element being added is not an AssocNode or does not have a symbol
5539 // key, then we want to turn the SYMBOL_KEYS flag off.
5540 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5541 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5544 pm_node_list_append(&hash->elements, element);
5545 if (hash->base.location.start == NULL) {
5546 hash->base.location.start = element->location.start;
5548 hash->base.location.end = element->location.end;
5554 static pm_required_keyword_parameter_node_t *
5555 pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5556 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5558 *node = (pm_required_keyword_parameter_node_t) {
5560 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5561 .node_id = PM_NODE_IDENTIFY(parser),
5563 .start = name->start,
5567 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5568 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5577 static pm_optional_keyword_parameter_node_t *
5578 pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5579 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5581 *node = (pm_optional_keyword_parameter_node_t) {
5583 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5584 .node_id = PM_NODE_IDENTIFY(parser),
5586 .start = name->start,
5587 .end = value->location.end
5590 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5591 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5601 static pm_keyword_rest_parameter_node_t *
5602 pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5603 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5605 *node = (pm_keyword_rest_parameter_node_t) {
5607 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5608 .node_id = PM_NODE_IDENTIFY(parser),
5610 .start = operator->start,
5611 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5614 .name = pm_parser_optional_constant_id_token(parser, name),
5615 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5616 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5625 static pm_lambda_node_t *
5626 pm_lambda_node_create(
5627 pm_parser_t *parser,
5628 pm_constant_id_list_t *locals,
5629 const pm_token_t *operator,
5630 const pm_token_t *opening,
5631 const pm_token_t *closing,
5632 pm_node_t *parameters,
5635 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5637 *node = (pm_lambda_node_t) {
5639 .type = PM_LAMBDA_NODE,
5640 .node_id = PM_NODE_IDENTIFY(parser),
5642 .start = operator->start,
5647 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5648 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5649 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5650 .parameters = parameters,
5660 static pm_local_variable_and_write_node_t *
5661 pm_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) {
5662 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5663 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5664 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5666 *node = (pm_local_variable_and_write_node_t) {
5668 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5669 .node_id = PM_NODE_IDENTIFY(parser),
5671 .start = target->location.start,
5672 .end = value->location.end
5675 .name_loc = target->location,
5676 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5688 static pm_local_variable_operator_write_node_t *
5689 pm_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) {
5690 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5692 *node = (pm_local_variable_operator_write_node_t) {
5694 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5695 .node_id = PM_NODE_IDENTIFY(parser),
5697 .start = target->location.start,
5698 .end = value->location.end
5701 .name_loc = target->location,
5702 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5705 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5715 static pm_local_variable_or_write_node_t *
5716 pm_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) {
5717 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5718 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5719 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5721 *node = (pm_local_variable_or_write_node_t) {
5723 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5724 .node_id = PM_NODE_IDENTIFY(parser),
5726 .start = target->location.start,
5727 .end = value->location.end
5730 .name_loc = target->location,
5731 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5743 static pm_local_variable_read_node_t *
5744 pm_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) {
5745 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5747 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5749 *node = (pm_local_variable_read_node_t) {
5751 .type = PM_LOCAL_VARIABLE_READ_NODE,
5752 .node_id = PM_NODE_IDENTIFY(parser),
5753 .location = PM_LOCATION_TOKEN_VALUE(name)
5765 static pm_local_variable_read_node_t *
5766 pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5767 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5768 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5775 static pm_local_variable_read_node_t *
5776 pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5777 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5778 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5784 static pm_local_variable_write_node_t *
5785 pm_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) {
5786 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5788 *node = (pm_local_variable_write_node_t) {
5790 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5791 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5792 .node_id = PM_NODE_IDENTIFY(parser),
5794 .start = name_loc->start,
5795 .end = value->location.end
5801 .name_loc = *name_loc,
5802 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5812 pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5813 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5821 pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5822 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5830 pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5831 if (pm_token_is_numbered_parameter(start, end)) {
5832 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5840 static pm_local_variable_target_node_t *
5841 pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5842 pm_refute_numbered_parameter(parser, location->start, location->end);
5843 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5845 *node = (pm_local_variable_target_node_t) {
5847 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5848 .node_id = PM_NODE_IDENTIFY(parser),
5849 .location = *location
5861 static pm_match_predicate_node_t *
5862 pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5863 pm_assert_value_expression(parser, value);
5865 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5867 *node = (pm_match_predicate_node_t) {
5869 .type = PM_MATCH_PREDICATE_NODE,
5870 .node_id = PM_NODE_IDENTIFY(parser),
5872 .start = value->location.start,
5873 .end = pattern->location.end
5878 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5887 static pm_match_required_node_t *
5888 pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5889 pm_assert_value_expression(parser, value);
5891 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5893 *node = (pm_match_required_node_t) {
5895 .type = PM_MATCH_REQUIRED_NODE,
5896 .node_id = PM_NODE_IDENTIFY(parser),
5898 .start = value->location.start,
5899 .end = pattern->location.end
5904 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5913 static pm_match_write_node_t *
5914 pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5915 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5917 *node = (pm_match_write_node_t) {
5919 .type = PM_MATCH_WRITE_NODE,
5920 .node_id = PM_NODE_IDENTIFY(parser),
5921 .location = call->base.location
5933 static pm_module_node_t *
5934 pm_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) {
5935 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5937 *node = (pm_module_node_t) {
5939 .type = PM_MODULE_NODE,
5940 .node_id = PM_NODE_IDENTIFY(parser),
5942 .start = module_keyword->start,
5943 .end = end_keyword->end
5946 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5947 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5948 .constant_path = constant_path,
5950 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5951 .name = pm_parser_constant_id_token(parser, name)
5960 static pm_multi_target_node_t *
5961 pm_multi_target_node_create(pm_parser_t *parser) {
5962 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5964 *node = (pm_multi_target_node_t) {
5966 .type = PM_MULTI_TARGET_NODE,
5967 .node_id = PM_NODE_IDENTIFY(parser),
5968 .location = { .start = NULL, .end = NULL }
5973 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5974 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5984 pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5985 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5986 if (node->rest == NULL) {
5987 node->rest = target;
5989 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5990 pm_node_list_append(&node->rights, target);
5992 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5993 if (node->rest == NULL) {
5994 node->rest = target;
5996 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5997 pm_node_list_append(&node->rights, target);
5999 } else if (node->rest == NULL) {
6000 pm_node_list_append(&node->lefts, target);
6002 pm_node_list_append(&node->rights, target);
6005 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
6006 node->base.location.start = target->location.start;
6009 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6010 node->base.location.end = target->location.end;
6018 pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6019 node->base.location.start = lparen->start;
6020 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6027 pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6028 node->base.location.end = rparen->end;
6029 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6035 static pm_multi_write_node_t *
6036 pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6037 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6039 *node = (pm_multi_write_node_t) {
6041 .type = PM_MULTI_WRITE_NODE,
6042 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6043 .node_id = PM_NODE_IDENTIFY(parser),
6045 .start = target->base.location.start,
6046 .end = value->location.end
6049 .lefts = target->lefts,
6050 .rest = target->rest,
6051 .rights = target->rights,
6052 .lparen_loc = target->lparen_loc,
6053 .rparen_loc = target->rparen_loc,
6054 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6058 // Explicitly do not call pm_node_destroy here because we want to keep
6059 // around all of the information within the MultiWriteNode node.
6068 static pm_next_node_t *
6069 pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6070 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6071 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6073 *node = (pm_next_node_t) {
6075 .type = PM_NEXT_NODE,
6076 .node_id = PM_NODE_IDENTIFY(parser),
6078 .start = keyword->start,
6079 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6082 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6083 .arguments = arguments
6092 static pm_nil_node_t *
6093 pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6094 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6095 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6097 *node = (pm_nil_node_t) {{
6098 .type = PM_NIL_NODE,
6099 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6100 .node_id = PM_NODE_IDENTIFY(parser),
6101 .location = PM_LOCATION_TOKEN_VALUE(token)
6110 static pm_no_keywords_parameter_node_t *
6111 pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6112 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6113 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6114 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6116 *node = (pm_no_keywords_parameter_node_t) {
6118 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6119 .node_id = PM_NODE_IDENTIFY(parser),
6121 .start = operator->start,
6125 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6126 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6135 static pm_numbered_parameters_node_t *
6136 pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6137 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6139 *node = (pm_numbered_parameters_node_t) {
6141 .type = PM_NUMBERED_PARAMETERS_NODE,
6142 .node_id = PM_NODE_IDENTIFY(parser),
6143 .location = *location
6155 #define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6164 pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6165 const uint8_t *start = token->start + 1;
6166 const uint8_t *end = token->end;
6168 ptrdiff_t diff = end - start;
6169 assert(diff > 0 && ((unsigned long) diff < SIZE_MAX));
6170 size_t length = (size_t) diff;
6172 char *digits = xcalloc(length + 1, sizeof(char));
6173 memcpy(digits, start, length);
6174 digits[length] = '\0';
6178 unsigned long value = strtoul(digits, &endptr, 10);
6180 if ((digits == endptr) || (*endptr != '\0')) {
6181 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6187 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6188 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6192 return (uint32_t) value;
6200 static pm_numbered_reference_read_node_t *
6201 pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6202 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6203 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6205 *node = (pm_numbered_reference_read_node_t) {
6207 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6208 .node_id = PM_NODE_IDENTIFY(parser),
6209 .location = PM_LOCATION_TOKEN_VALUE(name),
6211 .number = pm_numbered_reference_read_node_number(parser, name)
6220 static pm_optional_parameter_node_t *
6221 pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6222 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6224 *node = (pm_optional_parameter_node_t) {
6226 .type = PM_OPTIONAL_PARAMETER_NODE,
6227 .node_id = PM_NODE_IDENTIFY(parser),
6229 .start = name->start,
6230 .end = value->location.end
6233 .name = pm_parser_constant_id_token(parser, name),
6234 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6235 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6245 static pm_or_node_t *
6246 pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6247 pm_assert_value_expression(parser, left);
6249 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6251 *node = (pm_or_node_t) {
6254 .node_id = PM_NODE_IDENTIFY(parser),
6256 .start = left->location.start,
6257 .end = right->location.end
6262 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6271 static pm_parameters_node_t *
6272 pm_parameters_node_create(pm_parser_t *parser) {
6273 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6275 *node = (pm_parameters_node_t) {
6277 .type = PM_PARAMETERS_NODE,
6278 .node_id = PM_NODE_IDENTIFY(parser),
6279 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6282 .keyword_rest = NULL,
6297 pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6298 if (params->base.location.start == NULL) {
6299 params->base.location.start = param->location.start;
6301 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6304 if (params->base.location.end == NULL) {
6305 params->base.location.end = param->location.end;
6307 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6315 pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6316 pm_parameters_node_location_set(params, param);
6317 pm_node_list_append(¶ms->requireds, param);
6324 pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6325 pm_parameters_node_location_set(params, (pm_node_t *) param);
6326 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6333 pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6334 pm_parameters_node_location_set(params, param);
6335 pm_node_list_append(¶ms->posts, param);
6342 pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6343 pm_parameters_node_location_set(params, param);
6344 params->rest = param;
6351 pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6352 pm_parameters_node_location_set(params, param);
6353 pm_node_list_append(¶ms->keywords, param);
6360 pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6361 assert(params->keyword_rest == NULL);
6362 pm_parameters_node_location_set(params, param);
6363 params->keyword_rest = param;
6370 pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6371 assert(params->block == NULL);
6372 pm_parameters_node_location_set(params, (pm_node_t *) param);
6373 params->block = param;
6379 static pm_program_node_t *
6380 pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6381 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6383 *node = (pm_program_node_t) {
6385 .type = PM_PROGRAM_NODE,
6386 .node_id = PM_NODE_IDENTIFY(parser),
6388 .start = statements == NULL ? parser->start : statements->base.location.start,
6389 .end = statements == NULL ? parser->end : statements->base.location.end
6393 .statements = statements
6402 static pm_parentheses_node_t *
6403 pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
6404 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6406 *node = (pm_parentheses_node_t) {
6408 .type = PM_PARENTHESES_NODE,
6409 .node_id = PM_NODE_IDENTIFY(parser),
6411 .start = opening->start,
6416 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6417 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6426 static pm_pinned_expression_node_t *
6427 pm_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) {
6428 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6430 *node = (pm_pinned_expression_node_t) {
6432 .type = PM_PINNED_EXPRESSION_NODE,
6433 .node_id = PM_NODE_IDENTIFY(parser),
6435 .start = operator->start,
6439 .expression = expression,
6440 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6441 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6442 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6451 static pm_pinned_variable_node_t *
6452 pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6453 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6455 *node = (pm_pinned_variable_node_t) {
6457 .type = PM_PINNED_VARIABLE_NODE,
6458 .node_id = PM_NODE_IDENTIFY(parser),
6460 .start = operator->start,
6461 .end = variable->location.end
6464 .variable = variable,
6465 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6474 static pm_post_execution_node_t *
6475 pm_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) {
6476 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6478 *node = (pm_post_execution_node_t) {
6480 .type = PM_POST_EXECUTION_NODE,
6481 .node_id = PM_NODE_IDENTIFY(parser),
6483 .start = keyword->start,
6487 .statements = statements,
6488 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6489 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6490 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6499 static pm_pre_execution_node_t *
6500 pm_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) {
6501 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6503 *node = (pm_pre_execution_node_t) {
6505 .type = PM_PRE_EXECUTION_NODE,
6506 .node_id = PM_NODE_IDENTIFY(parser),
6508 .start = keyword->start,
6512 .statements = statements,
6513 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6514 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6515 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6524 static pm_range_node_t *
6525 pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6526 pm_assert_value_expression(parser, left);
6527 pm_assert_value_expression(parser, right);
6529 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6530 pm_node_flags_t flags = 0;
6532 // Indicate that this node is an exclusive range if the operator is `...`.
6533 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6534 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6537 // Indicate that this node is a static literal (i.e., can be compiled with
6538 // a putobject in CRuby) if the left and right are implicit nil, explicit
6539 // nil, or integers.
6541 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6542 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6544 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6547 *node = (pm_range_node_t) {
6549 .type = PM_RANGE_NODE,
6551 .node_id = PM_NODE_IDENTIFY(parser),
6553 .start = (left == NULL ? operator->start : left->location.start),
6554 .end = (right == NULL ? operator->end : right->location.end)
6559 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6568 static pm_redo_node_t *
6569 pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6570 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6571 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6573 *node = (pm_redo_node_t) {{
6574 .type = PM_REDO_NODE,
6575 .node_id = PM_NODE_IDENTIFY(parser),
6576 .location = PM_LOCATION_TOKEN_VALUE(token)
6586 static pm_regular_expression_node_t *
6587 pm_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) {
6588 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6590 *node = (pm_regular_expression_node_t) {
6592 .type = PM_REGULAR_EXPRESSION_NODE,
6593 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6594 .node_id = PM_NODE_IDENTIFY(parser),
6596 .start = MIN(opening->start, closing->start),
6597 .end = MAX(opening->end, closing->end)
6600 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6601 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6602 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6603 .unescaped = *unescaped
6612 static inline pm_regular_expression_node_t *
6613 pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6614 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6620 static pm_required_parameter_node_t *
6621 pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6622 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6624 *node = (pm_required_parameter_node_t) {
6626 .type = PM_REQUIRED_PARAMETER_NODE,
6627 .node_id = PM_NODE_IDENTIFY(parser),
6628 .location = PM_LOCATION_TOKEN_VALUE(token)
6630 .name = pm_parser_constant_id_token(parser, token)
6639 static pm_rescue_modifier_node_t *
6640 pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6641 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6643 *node = (pm_rescue_modifier_node_t) {
6645 .type = PM_RESCUE_MODIFIER_NODE,
6646 .node_id = PM_NODE_IDENTIFY(parser),
6648 .start = expression->location.start,
6649 .end = rescue_expression->location.end
6652 .expression = expression,
6653 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6654 .rescue_expression = rescue_expression
6663 static pm_rescue_node_t *
6664 pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6665 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6667 *node = (pm_rescue_node_t) {
6669 .type = PM_RESCUE_NODE,
6670 .node_id = PM_NODE_IDENTIFY(parser),
6671 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6673 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6674 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6685 pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6686 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6693 pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6694 node->reference = reference;
6695 node->base.location.end = reference->location.end;
6702 pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6703 node->statements = statements;
6704 if (pm_statements_node_body_length(statements) > 0) {
6705 node->base.location.end = statements->base.location.end;
6713 pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6714 node->subsequent = subsequent;
6715 node->base.location.end = subsequent->base.location.end;
6722 pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6723 pm_node_list_append(&node->exceptions, exception);
6724 node->base.location.end = exception->location.end;
6730 static pm_rest_parameter_node_t *
6731 pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6732 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6734 *node = (pm_rest_parameter_node_t) {
6736 .type = PM_REST_PARAMETER_NODE,
6737 .node_id = PM_NODE_IDENTIFY(parser),
6739 .start = operator->start,
6740 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6743 .name = pm_parser_optional_constant_id_token(parser, name),
6744 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6745 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6754 static pm_retry_node_t *
6755 pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6756 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6757 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6759 *node = (pm_retry_node_t) {{
6760 .type = PM_RETRY_NODE,
6761 .node_id = PM_NODE_IDENTIFY(parser),
6762 .location = PM_LOCATION_TOKEN_VALUE(token)
6771 static pm_return_node_t *
6772 pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6773 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6775 *node = (pm_return_node_t) {
6777 .type = PM_RETURN_NODE,
6778 .node_id = PM_NODE_IDENTIFY(parser),
6780 .start = keyword->start,
6781 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6784 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6785 .arguments = arguments
6794 static pm_self_node_t *
6795 pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6796 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6797 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6799 *node = (pm_self_node_t) {{
6800 .type = PM_SELF_NODE,
6801 .node_id = PM_NODE_IDENTIFY(parser),
6802 .location = PM_LOCATION_TOKEN_VALUE(token)
6811 static pm_shareable_constant_node_t *
6812 pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6813 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6815 *node = (pm_shareable_constant_node_t) {
6817 .type = PM_SHAREABLE_CONSTANT_NODE,
6818 .flags = (pm_node_flags_t) value,
6819 .node_id = PM_NODE_IDENTIFY(parser),
6820 .location = PM_LOCATION_NODE_VALUE(write)
6831 static pm_singleton_class_node_t *
6832 pm_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) {
6833 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6835 *node = (pm_singleton_class_node_t) {
6837 .type = PM_SINGLETON_CLASS_NODE,
6838 .node_id = PM_NODE_IDENTIFY(parser),
6840 .start = class_keyword->start,
6841 .end = end_keyword->end
6845 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6846 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6847 .expression = expression,
6849 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6858 static pm_source_encoding_node_t *
6859 pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6860 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6861 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6863 *node = (pm_source_encoding_node_t) {{
6864 .type = PM_SOURCE_ENCODING_NODE,
6865 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6866 .node_id = PM_NODE_IDENTIFY(parser),
6867 .location = PM_LOCATION_TOKEN_VALUE(token)
6876 static pm_source_file_node_t*
6877 pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6878 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6879 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6881 pm_node_flags_t flags = 0;
6883 switch (parser->frozen_string_literal) {
6884 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6885 flags |= PM_STRING_FLAGS_MUTABLE;
6887 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6888 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6892 *node = (pm_source_file_node_t) {
6894 .type = PM_SOURCE_FILE_NODE,
6896 .node_id = PM_NODE_IDENTIFY(parser),
6897 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6899 .filepath = parser->filepath
6908 static pm_source_line_node_t *
6909 pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6910 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6911 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6913 *node = (pm_source_line_node_t) {{
6914 .type = PM_SOURCE_LINE_NODE,
6915 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6916 .node_id = PM_NODE_IDENTIFY(parser),
6917 .location = PM_LOCATION_TOKEN_VALUE(token)
6926 static pm_splat_node_t *
6927 pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6928 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6930 *node = (pm_splat_node_t) {
6932 .type = PM_SPLAT_NODE,
6933 .node_id = PM_NODE_IDENTIFY(parser),
6935 .start = operator->start,
6936 .end = (expression == NULL ? operator->end : expression->location.end)
6939 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6940 .expression = expression
6949 static pm_statements_node_t *
6950 pm_statements_node_create(pm_parser_t *parser) {
6951 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6953 *node = (pm_statements_node_t) {
6955 .type = PM_STATEMENTS_NODE,
6956 .node_id = PM_NODE_IDENTIFY(parser),
6957 .location = PM_LOCATION_NULL_VALUE(parser)
6969 pm_statements_node_body_length(pm_statements_node_t *node) {
6970 return node && node->body.size;
6977 pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6978 node->base.location = (pm_location_t) { .start = start, .end = end };
6986 pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6987 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6988 node->base.location.start = statement->location.start;
6991 if (statement->location.end > node->base.location.end) {
6992 node->base.location.end = statement->location.end;
7000 pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
7001 pm_statements_node_body_update(node, statement);
7003 if (node->body.size > 0) {
7004 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
7006 switch (PM_NODE_TYPE(previous)) {
7011 case PM_RETURN_NODE:
7012 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7019 pm_node_list_append(&node->body, statement);
7020 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7027 pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7028 pm_statements_node_body_update(node, statement);
7029 pm_node_list_prepend(&node->body, statement);
7030 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7036 static inline pm_string_node_t *
7037 pm_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) {
7038 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7039 pm_node_flags_t flags = 0;
7041 switch (parser->frozen_string_literal) {
7042 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7043 flags = PM_STRING_FLAGS_MUTABLE;
7045 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7046 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7050 *node = (pm_string_node_t) {
7052 .type = PM_STRING_NODE,
7054 .node_id = PM_NODE_IDENTIFY(parser),
7056 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7057 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7060 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7061 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7062 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7063 .unescaped = *string
7072 static pm_string_node_t *
7073 pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7074 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7081 static pm_string_node_t *
7082 pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7083 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7084 parser->current_string = PM_STRING_EMPTY;
7091 static pm_super_node_t *
7092 pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7093 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7094 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7096 const uint8_t *end = pm_arguments_end(arguments);
7098 assert(false && "unreachable");
7101 *node = (pm_super_node_t) {
7103 .type = PM_SUPER_NODE,
7104 .node_id = PM_NODE_IDENTIFY(parser),
7106 .start = keyword->start,
7110 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7111 .lparen_loc = arguments->opening_loc,
7112 .arguments = arguments->arguments,
7113 .rparen_loc = arguments->closing_loc,
7114 .block = arguments->block
7125 pm_ascii_only_p(const pm_string_t *contents) {
7126 const size_t length = pm_string_length(contents);
7127 const uint8_t *source = pm_string_source(contents);
7129 for (size_t index = 0; index < length; index++) {
7130 if (source[index] & 0x80) return false;
7140 parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7141 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7142 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7145 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7158 parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7159 const pm_encoding_t *encoding = parser->encoding;
7161 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7162 size_t width = encoding->char_width(cursor, end - cursor);
7165 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7182 static inline pm_node_flags_t
7183 parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7184 if (parser->explicit_encoding != NULL) {
7185 // A Symbol may optionally have its encoding explicitly set. This will
7186 // happen if an escape sequence results in a non-ASCII code point.
7187 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7188 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7189 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7190 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7191 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7192 } else if (validate) {
7193 parse_symbol_encoding_validate_other(parser, location, contents);
7195 } else if (pm_ascii_only_p(contents)) {
7196 // Ruby stipulates that all source files must use an ASCII-compatible
7197 // encoding. Thus, all symbols appearing in source are eligible for
7198 // "downgrading" to US-ASCII.
7199 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7200 } else if (validate) {
7201 parse_symbol_encoding_validate_other(parser, location, contents);
7207 static pm_node_flags_t
7208 parse_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) {
7209 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7210 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7211 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7212 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7214 // There's special validation logic used if a string does not contain any character escape sequences.
7215 if (parser->explicit_encoding == NULL) {
7216 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7217 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7218 // the US-ASCII encoding.
7220 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7223 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7225 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7227 } else if (parser->encoding != modifier_encoding) {
7228 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7230 if (modifier == 'n' && !ascii_only) {
7231 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));
7238 // 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.
7239 bool mixed_encoding = false;
7241 if (mixed_encoding) {
7242 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7243 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7244 // 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.
7245 bool valid_string_in_modifier_encoding = true;
7247 if (!valid_string_in_modifier_encoding) {
7248 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7250 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7251 // 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.
7252 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7253 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));
7257 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7267 static pm_node_flags_t
7268 parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7269 // 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.
7270 bool valid_unicode_range = true;
7271 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7272 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));
7276 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7277 // to multi-byte characters are allowed.
7278 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7279 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7280 // following error message appearing twice. We do the same for compatibility.
7281 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7292 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7293 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7296 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7297 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7300 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7301 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7304 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7305 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7308 // At this point no encoding modifiers will be present on the regular expression as they would have already
7309 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7310 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7312 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7315 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7316 // or by specifying a modifier.
7318 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7319 if (parser->explicit_encoding != NULL) {
7320 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7321 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7322 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7323 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7334 static pm_symbol_node_t *
7335 pm_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) {
7336 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7338 *node = (pm_symbol_node_t) {
7340 .type = PM_SYMBOL_NODE,
7341 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7342 .node_id = PM_NODE_IDENTIFY(parser),
7344 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7345 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7348 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7349 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7350 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7351 .unescaped = *unescaped
7360 static inline pm_symbol_node_t *
7361 pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7362 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7368 static pm_symbol_node_t *
7369 pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7370 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));
7371 parser->current_string = PM_STRING_EMPTY;
7378 static pm_symbol_node_t *
7379 pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7380 pm_symbol_node_t *node;
7382 switch (token->type) {
7383 case PM_TOKEN_LABEL: {
7384 pm_token_t opening = not_provided(parser);
7385 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7387 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7388 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7390 assert((label.end - label.start) >= 0);
7391 pm_string_shared_init(&node->unescaped, label.start, label.end);
7392 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7396 case PM_TOKEN_MISSING: {
7397 pm_token_t opening = not_provided(parser);
7398 pm_token_t closing = not_provided(parser);
7400 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7401 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7405 assert(false && "unreachable");
7416 static pm_symbol_node_t *
7417 pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7418 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7420 *node = (pm_symbol_node_t) {
7422 .type = PM_SYMBOL_NODE,
7423 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7424 .node_id = PM_NODE_IDENTIFY(parser),
7425 .location = PM_LOCATION_NULL_VALUE(parser)
7427 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7431 pm_string_constant_init(&node->unescaped, content, strlen(content));
7439 pm_symbol_node_label_p(pm_node_t *node) {
7440 const uint8_t *end = NULL;
7442 switch (PM_NODE_TYPE(node)) {
7443 case PM_SYMBOL_NODE:
7444 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7446 case PM_INTERPOLATED_SYMBOL_NODE:
7447 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7453 return (end != NULL) && (end[-1] == ':');
7459 static pm_symbol_node_t *
7460 pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7461 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7463 *new_node = (pm_symbol_node_t) {
7465 .type = PM_SYMBOL_NODE,
7466 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7467 .node_id = PM_NODE_IDENTIFY(parser),
7469 .start = opening->start,
7473 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7474 .value_loc = node->content_loc,
7475 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7476 .unescaped = node->unescaped
7479 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7480 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7482 // We are explicitly _not_ using pm_node_destroy here because we don't want
7483 // to trash the unescaped string. We could instead copy the string if we
7484 // know that it is owned, but we're taking the fast path for now.
7493 static pm_string_node_t *
7494 pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7495 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7496 pm_node_flags_t flags = 0;
7498 switch (parser->frozen_string_literal) {
7499 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7500 flags = PM_STRING_FLAGS_MUTABLE;
7502 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7503 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7507 *new_node = (pm_string_node_t) {
7509 .type = PM_STRING_NODE,
7511 .node_id = PM_NODE_IDENTIFY(parser),
7512 .location = node->base.location
7514 .opening_loc = node->opening_loc,
7515 .content_loc = node->value_loc,
7516 .closing_loc = node->closing_loc,
7517 .unescaped = node->unescaped
7520 // We are explicitly _not_ using pm_node_destroy here because we don't want
7521 // to trash the unescaped string. We could instead copy the string if we
7522 // know that it is owned, but we're taking the fast path for now.
7531 static pm_true_node_t *
7532 pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7533 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7534 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7536 *node = (pm_true_node_t) {{
7537 .type = PM_TRUE_NODE,
7538 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7539 .node_id = PM_NODE_IDENTIFY(parser),
7540 .location = PM_LOCATION_TOKEN_VALUE(token)
7549 static pm_true_node_t *
7550 pm_true_node_synthesized_create(pm_parser_t *parser) {
7551 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7553 *node = (pm_true_node_t) {{
7554 .type = PM_TRUE_NODE,
7555 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7556 .node_id = PM_NODE_IDENTIFY(parser),
7557 .location = { .start = parser->start, .end = parser->end }
7566 static pm_undef_node_t *
7567 pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7568 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7569 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7571 *node = (pm_undef_node_t) {
7573 .type = PM_UNDEF_NODE,
7574 .node_id = PM_NODE_IDENTIFY(parser),
7575 .location = PM_LOCATION_TOKEN_VALUE(token),
7577 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7588 pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7589 node->base.location.end = name->location.end;
7590 pm_node_list_append(&node->names, name);
7596 static pm_unless_node_t *
7597 pm_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) {
7598 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7599 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7602 if (statements != NULL) {
7603 end = statements->base.location.end;
7605 end = predicate->location.end;
7608 *node = (pm_unless_node_t) {
7610 .type = PM_UNLESS_NODE,
7611 .flags = PM_NODE_FLAG_NEWLINE,
7612 .node_id = PM_NODE_IDENTIFY(parser),
7614 .start = keyword->start,
7618 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7619 .predicate = predicate,
7620 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7621 .statements = statements,
7622 .else_clause = NULL,
7623 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7632 static pm_unless_node_t *
7633 pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7634 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7635 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7637 pm_statements_node_t *statements = pm_statements_node_create(parser);
7638 pm_statements_node_body_append(parser, statements, statement, true);
7640 *node = (pm_unless_node_t) {
7642 .type = PM_UNLESS_NODE,
7643 .flags = PM_NODE_FLAG_NEWLINE,
7644 .node_id = PM_NODE_IDENTIFY(parser),
7646 .start = statement->location.start,
7647 .end = predicate->location.end
7650 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7651 .predicate = predicate,
7652 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7653 .statements = statements,
7654 .else_clause = NULL,
7655 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7662 pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7663 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7664 node->base.location.end = end_keyword->end;
7673 pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7674 assert(parser->current_block_exits != NULL);
7676 // All of the block exits that we want to remove should be within the
7677 // statements, and since we are modifying the statements, we shouldn't have
7678 // to check the end location.
7679 const uint8_t *start = statements->base.location.start;
7681 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7682 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7683 if (block_exit->location.start < start) break;
7685 // Implicitly remove from the list by lowering the size.
7686 parser->current_block_exits->size--;
7693 static pm_until_node_t *
7694 pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
7695 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7696 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7698 *node = (pm_until_node_t) {
7700 .type = PM_UNTIL_NODE,
7702 .node_id = PM_NODE_IDENTIFY(parser),
7704 .start = keyword->start,
7705 .end = closing->end,
7708 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7709 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7710 .predicate = predicate,
7711 .statements = statements
7720 static pm_until_node_t *
7721 pm_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) {
7722 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7723 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7724 pm_loop_modifier_block_exits(parser, statements);
7726 *node = (pm_until_node_t) {
7728 .type = PM_UNTIL_NODE,
7730 .node_id = PM_NODE_IDENTIFY(parser),
7732 .start = statements->base.location.start,
7733 .end = predicate->location.end,
7736 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7737 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7738 .predicate = predicate,
7739 .statements = statements
7748 static pm_when_node_t *
7749 pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7750 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7752 *node = (pm_when_node_t) {
7754 .type = PM_WHEN_NODE,
7755 .node_id = PM_NODE_IDENTIFY(parser),
7757 .start = keyword->start,
7761 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7763 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7774 pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7775 node->base.location.end = condition->location.end;
7776 pm_node_list_append(&node->conditions, condition);
7783 pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7784 node->base.location.end = then_keyword->end;
7785 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7792 pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7793 if (statements->base.location.end > node->base.location.end) {
7794 node->base.location.end = statements->base.location.end;
7797 node->statements = statements;
7803 static pm_while_node_t *
7804 pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
7805 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7806 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7808 *node = (pm_while_node_t) {
7810 .type = PM_WHILE_NODE,
7812 .node_id = PM_NODE_IDENTIFY(parser),
7814 .start = keyword->start,
7818 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7819 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7820 .predicate = predicate,
7821 .statements = statements
7830 static pm_while_node_t *
7831 pm_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) {
7832 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7833 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7834 pm_loop_modifier_block_exits(parser, statements);
7836 *node = (pm_while_node_t) {
7838 .type = PM_WHILE_NODE,
7840 .node_id = PM_NODE_IDENTIFY(parser),
7842 .start = statements->base.location.start,
7843 .end = predicate->location.end
7846 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7847 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7848 .predicate = predicate,
7849 .statements = statements
7858 static pm_while_node_t *
7859 pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7860 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7862 *node = (pm_while_node_t) {
7864 .type = PM_WHILE_NODE,
7865 .node_id = PM_NODE_IDENTIFY(parser),
7866 .location = PM_LOCATION_NULL_VALUE(parser)
7868 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7869 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7870 .predicate = predicate,
7871 .statements = statements
7881 static pm_x_string_node_t *
7882 pm_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) {
7883 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7885 *node = (pm_x_string_node_t) {
7887 .type = PM_X_STRING_NODE,
7888 .flags = PM_STRING_FLAGS_FROZEN,
7889 .node_id = PM_NODE_IDENTIFY(parser),
7891 .start = opening->start,
7895 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7896 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7897 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7898 .unescaped = *unescaped
7907 static inline pm_x_string_node_t *
7908 pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7909 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7915 static pm_yield_node_t *
7916 pm_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) {
7917 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7920 if (rparen_loc->start != NULL) {
7921 end = rparen_loc->end;
7922 } else if (arguments != NULL) {
7923 end = arguments->base.location.end;
7924 } else if (lparen_loc->start != NULL) {
7925 end = lparen_loc->end;
7930 *node = (pm_yield_node_t) {
7932 .type = PM_YIELD_NODE,
7933 .node_id = PM_NODE_IDENTIFY(parser),
7935 .start = keyword->start,
7939 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7940 .lparen_loc = *lparen_loc,
7941 .arguments = arguments,
7942 .rparen_loc = *rparen_loc
7948 #undef PM_NODE_ALLOC
7949 #undef PM_NODE_IDENTIFY
7956 pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7957 pm_scope_t *scope = parser->current_scope;
7960 while (scope != NULL) {
7961 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7962 if (scope->closed) break;
7964 scope = scope->previous;
7977 pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7978 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7985 pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7986 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7992 static pm_constant_id_t
7993 pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7994 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7995 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8002 static inline pm_constant_id_t
8003 pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8004 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8010 static pm_constant_id_t
8011 pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8012 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8013 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8020 static pm_constant_id_t
8021 pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8022 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8023 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8035 pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8036 // We want to check whether the parameter name is a numbered parameter or
8038 pm_refute_numbered_parameter(parser, name->start, name->end);
8040 // Otherwise we'll fetch the constant id for the parameter name and check
8041 // whether it's already in the current scope.
8042 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8044 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8045 // Add an error if the parameter doesn't start with _ and has been seen before
8046 if ((name->start < name->end) && (*name->start != '_')) {
8047 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8058 pm_parser_scope_pop(pm_parser_t *parser) {
8059 pm_scope_t *scope = parser->current_scope;
8060 parser->current_scope = scope->previous;
8061 pm_locals_free(&scope->locals);
8062 pm_node_list_free(&scope->implicit_parameters);
8066 /******************************************************************************/
8068 /******************************************************************************/
8074 pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8075 *stack = (*stack << 1) | (value & 1);
8082 pm_state_stack_pop(pm_state_stack_t *stack) {
8090 pm_state_stack_p(const pm_state_stack_t *stack) {
8095 pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8096 // Use the negation of the value to prevent stack overflow.
8097 pm_state_stack_push(&parser->accepts_block_stack, !value);
8101 pm_accepts_block_stack_pop(pm_parser_t *parser) {
8102 pm_state_stack_pop(&parser->accepts_block_stack);
8106 pm_accepts_block_stack_p(pm_parser_t *parser) {
8107 return !pm_state_stack_p(&parser->accepts_block_stack);
8111 pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8112 pm_state_stack_push(&parser->do_loop_stack, value);
8116 pm_do_loop_stack_pop(pm_parser_t *parser) {
8117 pm_state_stack_pop(&parser->do_loop_stack);
8121 pm_do_loop_stack_p(pm_parser_t *parser) {
8122 return pm_state_stack_p(&parser->do_loop_stack);
8125 /******************************************************************************/
8126 /* Lexer check helpers */
8127 /******************************************************************************/
8133 static inline uint8_t
8134 peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8135 if (cursor < parser->end) {
8147 static inline uint8_t
8148 peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8149 return peek_at(parser, parser->current.end + offset);
8156 static inline uint8_t
8157 peek(const pm_parser_t *parser) {
8158 return peek_at(parser, parser->current.end);
8166 match(pm_parser_t *parser, uint8_t value) {
8167 if (peek(parser) == value) {
8168 parser->current.end++;
8178 static inline size_t
8179 match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8180 if (peek_at(parser, cursor) == '\n') {
8183 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8194 static inline size_t
8195 match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8196 return match_eol_at(parser, parser->current.end + offset);
8204 static inline size_t
8205 match_eol(pm_parser_t *parser) {
8206 return match_eol_at(parser, parser->current.end);
8212 static inline const uint8_t *
8213 next_newline(const uint8_t *cursor, ptrdiff_t length) {
8214 assert(length >= 0);
8216 // Note that it's okay for us to use memchr here to look for \n because none
8217 // of the encodings that we support have \n as a component of a multi-byte
8219 return memchr(cursor, '\n', (size_t) length);
8226 ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8227 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));
8235 parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8236 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8238 if (encoding != NULL) {
8239 if (parser->encoding != encoding) {
8240 parser->encoding = encoding;
8241 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8244 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8256 parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8257 const uint8_t *cursor = parser->current.start + 1;
8258 const uint8_t *end = parser->current.end;
8260 bool separator = false;
8262 if (end - cursor <= 6) return;
8263 switch (cursor[6]) {
8264 case 'C': case 'c': cursor += 6; continue;
8265 case 'O': case 'o': cursor += 5; continue;
8266 case 'D': case 'd': cursor += 4; continue;
8267 case 'I': case 'i': cursor += 3; continue;
8268 case 'N': case 'n': cursor += 2; continue;
8269 case 'G': case 'g': cursor += 1; continue;
8276 if (pm_char_is_whitespace(*cursor)) break;
8279 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8285 if (++cursor >= end) return;
8286 } while (pm_char_is_whitespace(*cursor));
8288 if (separator) break;
8289 if (*cursor != '=' && *cursor != ':') return;
8295 const uint8_t *value_start = cursor;
8296 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8298 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8299 // If we were unable to parse the encoding value, then we've got an
8300 // issue because we didn't understand the encoding that the user was
8301 // trying to use. In this case we'll keep using the default encoding but
8302 // add an error to the parser to indicate an unsuccessful parse.
8303 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8308 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8309 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8310 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8311 } pm_magic_comment_boolean_value_t;
8317 static pm_magic_comment_boolean_value_t
8318 parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8319 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8320 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8321 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8322 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8324 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8329 pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8330 return b == '\'' || b == '"' || b == ':' || b == ';';
8338 static inline const uint8_t *
8339 parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8341 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8360 parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8363 const uint8_t *start = parser->
current.start + 1;
8364 const uint8_t *end = parser->
current.end;
8365 if (end - start <= 7)
return false;
8367 const uint8_t *cursor;
8368 bool indicator =
false;
8370 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8373 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8384 while (cursor < end) {
8385 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) ||
pm_char_is_whitespace(*cursor))) cursor++;
8387 const uint8_t *key_start = cursor;
8388 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !
pm_char_is_whitespace(*cursor))) cursor++;
8390 const uint8_t *key_end = cursor;
8392 if (cursor == end)
break;
8394 if (*cursor ==
':') {
8397 if (!indicator)
return false;
8402 if (cursor == end)
break;
8404 const uint8_t *value_start;
8405 const uint8_t *value_end;
8407 if (*cursor ==
'"') {
8408 value_start = ++cursor;
8409 for (; cursor < end && *cursor !=
'"'; cursor++) {
8410 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8413 if (*cursor ==
'"') cursor++;
8415 value_start = cursor;
8416 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !
pm_char_is_whitespace(*cursor)) cursor++;
8424 if (cursor != end)
return false;
8430 const size_t key_length = (size_t) (key_end - key_start);
8436 uint8_t *buffer =
xmalloc(key_length);
8437 if (buffer == NULL)
break;
8439 memcpy(buffer, key_start, key_length);
8440 buffer[dash - key_start] =
'_';
8443 buffer[dash - key_start] =
'_';
8452 uint32_t value_length = (uint32_t) (value_end - value_start);
8458 (key_length == 8 &&
pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8459 (key_length == 6 &&
pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8461 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8465 if (key_length == 11) {
8466 if (
pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8467 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8468 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8469 PM_PARSER_WARN_TOKEN_FORMAT(
8472 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8474 (
const char *) key_source,
8476 (
const char *) value_start
8479 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8482 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8487 }
else if (key_length == 21) {
8488 if (
pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8491 if (semantic_token_seen) {
8492 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8494 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8495 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8496 PM_PARSER_WARN_TOKEN_FORMAT(
8499 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8501 (
const char *) key_source,
8503 (
const char *) value_start
8506 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8509 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8515 }
else if (key_length == 24) {
8516 if (
pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8517 const uint8_t *cursor = parser->
current.start;
8518 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8520 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8521 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8522 }
else if (value_length == 4 &&
pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8523 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8524 }
else if (value_length == 7 &&
pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8525 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8526 }
else if (value_length == 23 &&
pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8527 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8528 }
else if (value_length == 17 &&
pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8529 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8531 PM_PARSER_WARN_TOKEN_FORMAT(
8534 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8536 (
const char *) key_source,
8538 (
const char *) value_start
8655 while (context_node != NULL) {
8656 if (context_terminator(context_node->
context, token))
return context_node->
context;
8657 context_node = context_node->
prev;
8666 if (context_node == NULL)
return false;
8691 while (context_node != NULL) {
8692 if (context_node->
context == context)
return true;
8693 context_node = context_node->
prev;
8703 while (context_node != NULL) {
8704 switch (context_node->
context) {
8725 context_node = context_node->
prev;
8740 assert(
false &&
"unreachable");
8797 assert(
false &&
"unreachable");
8806 pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8807 if (invalid != NULL) {
8808 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8809 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8814 pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8815 const uint8_t *invalid = NULL;
8817 pm_strspn_number_validate(parser,
string, length, invalid);
8822 pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8823 const uint8_t *invalid = NULL;
8825 pm_strspn_number_validate(parser,
string, length, invalid);
8830 pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8831 const uint8_t *invalid = NULL;
8833 pm_strspn_number_validate(parser,
string, length, invalid);
8838 pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8839 const uint8_t *invalid = NULL;
8841 pm_strspn_number_validate(parser,
string, length, invalid);
8846 lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8851 if (peek(parser) ==
'.') {
8854 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8865 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8866 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8871 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8873 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8877 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8890 lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8894 if (peek_offset(parser, -1) ==
'0') {
8895 switch (*parser->
current.end) {
8901 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8904 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8914 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8917 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8928 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8931 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8947 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8956 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8959 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8967 type = lex_optional_float_suffix(parser, seen_e);
8974 type = lex_optional_float_suffix(parser, seen_e);
8981 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8984 type = lex_optional_float_suffix(parser, seen_e);
8991 const uint8_t *fraction_start = parser->
current.end;
8992 const uint8_t *fraction_end = parser->
current.end + 2;
8994 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9006 bool seen_e =
false;
9007 type = lex_numeric_prefix(parser, &seen_e);
9009 const uint8_t *end = parser->
current.end;
9013 if (match(parser,
'r')) {
9016 if (match(parser,
'i')) {
9019 }
else if (match(parser,
'i')) {
9023 if (!seen_e && match(parser,
'r')) {
9026 if (match(parser,
'i')) {
9029 }
else if (match(parser,
'i')) {
9034 const uint8_t b = peek(parser);
9035 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9048 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9054 bool allow_multiple =
true;
9056 switch (*parser->
current.end) {
9087 if (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0) {
9090 }
while (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0);
9094 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9114 allow_multiple =
false;
9119 if ((width = char_is_identifier(parser, parser->
current.end)) > 0) {
9122 }
while (allow_multiple && parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0);
9126 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9132 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9154 if (memcmp(current_start, value, vlen) == 0) {
9157 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9158 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9160 lex_state_set(parser, state);
9161 if (state == PM_LEX_STATE_BEG) {
9165 if ((modifier_type !=
PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9166 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9167 return modifier_type;
9178 lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9181 const uint8_t *end = parser->
end;
9182 const uint8_t *current_start = parser->
current.start;
9183 const uint8_t *current_end = parser->
current.end;
9186 if (encoding_changed) {
9187 while (current_end < end && (width = char_is_identifier(parser, current_end)) > 0) {
9188 current_end += width;
9191 while (current_end < end && (width = char_is_identifier_utf8(current_end, end)) > 0) {
9192 current_end += width;
9195 parser->
current.end = current_end;
9199 width = (size_t) (current_end - current_start);
9201 if (current_end < end) {
9202 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9208 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9209 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9213 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9214 (void) match(parser,
':');
9218 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9227 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,
'=')) {
9234 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9235 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9239 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9240 (void) match(parser,
':');
9245 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9250 if (pm_do_loop_stack_p(parser)) {
9311 if (encoding_changed) {
9341 lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9344 if (pound + 1 >= parser->
end) {
9345 parser->
current.end = pound + 1;
9355 if (pound + 2 >= parser->
end) {
9356 parser->
current.end = pound + 1;
9362 const uint8_t *variable = pound + 2;
9363 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9365 if (char_is_identifier_start(parser, variable)) {
9369 if (pound > parser->
current.start) {
9376 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9377 parser->
current.end = pound + 1;
9384 parser->
current.end = pound + 1;
9390 if (pound + 2 >= parser->
end) {
9391 parser->
current.end = pound + 1;
9398 const uint8_t *check = pound + 2;
9400 if (pound[2] ==
'-') {
9401 if (pound + 3 >= parser->
end) {
9402 parser->
current.end = pound + 2;
9414 char_is_identifier_start(parser, check) ||
9420 if (pound > parser->
current.start) {
9427 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9428 parser->
current.end = pound + 1;
9434 parser->
current.end = pound + 1;
9440 if (pound > parser->
current.start) {
9449 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9450 parser->
current.end = pound + 2;
9452 pm_do_loop_stack_push(parser,
false);
9458 parser->
current.end = pound + 1;
9463 static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9464 static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9465 static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9466 static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9467 static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9472 static const bool ascii_printable_chars[] = {
9473 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9474 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9475 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9476 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9477 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9479 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9480 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9484 char_is_ascii_printable(
const uint8_t b) {
9485 return (b < 0x80) && ascii_printable_chars[b];
9492 static inline uint8_t
9493 escape_hexadecimal_digit(
const uint8_t value) {
9494 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9502 static inline uint32_t
9503 escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9505 for (
size_t index = 0; index < length; index++) {
9506 if (index != 0) value <<= 4;
9507 value |= escape_hexadecimal_digit(
string[index]);
9512 if (value >= 0xD800 && value <= 0xDFFF) {
9513 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9523 static inline uint8_t
9524 escape_byte(uint8_t value,
const uint8_t flags) {
9525 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9526 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9534 escape_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) {
9538 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9546 if (value <= 0x7F) {
9548 }
else if (value <= 0x7FF) {
9551 }
else if (value <= 0xFFFF) {
9555 }
else if (value <= 0x10FFFF) {
9561 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9576 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9599 width = (width == 0) ? 1 : width;
9601 for (
size_t index = 0; index < width; index++) {
9602 escape_write_byte_encoded(parser, buffer, *parser->
current.end);
9624 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9628 escape_write_byte_encoded(parser, buffer,
byte);
9637 escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9638 #define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9640 PM_PARSER_WARN_TOKEN_FORMAT(
9643 PM_WARN_INVALID_CHARACTER,
9657 switch (peek(parser)) {
9660 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9665 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9670 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9675 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9680 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9685 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9690 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9695 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9700 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9705 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9710 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9713 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9714 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9718 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9722 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9727 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9731 const uint8_t *start = parser->
current.end - 1;
9734 uint8_t
byte = peek(parser);
9737 uint8_t value = escape_hexadecimal_digit(
byte);
9740 byte = peek(parser);
9742 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9746 value = escape_byte(value, flags);
9747 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9748 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9755 escape_write_byte_encoded(parser, buffer, value);
9757 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9763 const uint8_t *start = parser->
current.end - 1;
9767 const uint8_t *start = parser->
current.end - 2;
9768 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9769 }
else if (peek(parser) ==
'{') {
9770 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9776 parser->
current.end += whitespace;
9777 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9788 const uint8_t *extra_codepoints_start = NULL;
9789 int codepoints_count = 0;
9792 const uint8_t *unicode_start = parser->
current.end;
9795 if (hexadecimal_length > 6) {
9797 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9798 }
else if (hexadecimal_length == 0) {
9801 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9807 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9808 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9814 parser->
current.end += hexadecimal_length;
9816 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9817 extra_codepoints_start = unicode_start;
9820 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9821 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9828 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9829 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9833 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9834 }
else if (peek(parser) ==
'}') {
9837 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9843 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9847 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9854 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9857 const uint8_t *start = parser->
current.end - 2;
9858 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9860 }
else if (length == 4) {
9861 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9863 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9867 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9870 parser->
current.end += length;
9872 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9878 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9887 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9888 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9892 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9896 uint8_t peeked = peek(parser);
9900 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9906 if (match(parser,
'u') || match(parser,
'U')) {
9907 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9911 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9915 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9916 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9920 escape_read_warn(parser, flags, 0,
"\\t");
9921 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9924 if (!char_is_ascii_printable(peeked)) {
9925 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9930 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9937 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9938 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9941 if (peek(parser) !=
'-') {
9943 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9949 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9953 uint8_t peeked = peek(parser);
9957 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9963 if (match(parser,
'u') || match(parser,
'U')) {
9964 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9968 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9972 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9973 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9977 escape_read_warn(parser, flags, 0,
"\\t");
9978 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9981 if (!char_is_ascii_printable(peeked)) {
9983 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9988 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9995 if (flags & PM_ESCAPE_FLAG_META) {
9996 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9999 if (peek(parser) !=
'-') {
10001 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10007 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10011 uint8_t peeked = peek(parser);
10016 if (match(parser,
'u') || match(parser,
'U')) {
10017 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10021 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10025 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10026 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10030 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10031 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10034 if (!char_is_ascii_printable(peeked)) {
10036 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10041 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10046 if (peek_offset(parser, 1) ==
'\n') {
10048 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10055 escape_write_escape_encoded(parser, buffer);
10057 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10091 if (lex_state_end_p(parser)) {
10092 lex_state_set(parser, PM_LEX_STATE_BEG);
10097 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10103 lex_state_set(parser, PM_LEX_STATE_BEG);
10107 lex_state_set(parser, PM_LEX_STATE_BEG);
10109 if (match(parser,
'\\')) {
10110 lex_state_set(parser, PM_LEX_STATE_END);
10115 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10127 (parser->
current.end + encoding_width >= parser->
end) ||
10128 !char_is_identifier(parser, parser->
current.end + encoding_width)
10131 lex_state_set(parser, PM_LEX_STATE_END);
10132 parser->
current.end += encoding_width;
10150 if (parser->
current.end < parser->
end && (width = char_is_identifier_start(parser, parser->
current.end)) > 0) {
10151 parser->
current.end += width;
10153 while (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0) {
10154 parser->
current.end += width;
10163 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10166 pm_parser_err_token(parser, &parser->
current, diag_id);
10172 lex_mode_pop(parser);
10194 if (comment == NULL)
return NULL;
10212 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10214 if (newline == NULL) {
10218 parser->
current.end = newline + 1;
10222 parser_lex_callback(parser);
10225 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10230 while (parser->
current.end + 4 <= parser->
end) {
10236 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10240 (parser->
current.end[4] ==
'\0') ||
10241 (parser->
current.end[4] ==
'\004') ||
10242 (parser->
current.end[4] ==
'\032')
10245 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10247 if (newline == NULL) {
10251 parser->
current.end = newline + 1;
10255 parser_lex_callback(parser);
10265 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10267 if (newline == NULL) {
10271 parser->
current.end = newline + 1;
10275 parser_lex_callback(parser);
10278 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10292 parser_lex_ignored_newline(
pm_parser_t *parser) {
10294 parser_lex_callback(parser);
10317 parser_end_of_line_p(
const pm_parser_t *parser) {
10318 const uint8_t *cursor = parser->
current.end;
10320 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10395 static inline size_t
10406 return (width == 0 ? 1 : width);
10414 size_t width = parser_char_width(parser);
10416 parser->
current.end += width;
10421 size_t width = parser_char_width(parser);
10424 parser->
current.end += width;
10428 pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10429 for (
size_t index = 0; index < length; index++) {
10430 if (value[index] & 0x80)
return false;
10465 if (token_buffer->
cursor == NULL) {
10469 pm_token_buffer_copy(parser, token_buffer);
10481 pm_regexp_token_buffer_copy(parser, token_buffer);
10485 #define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10497 const uint8_t *start;
10498 if (token_buffer->
cursor == NULL) {
10500 start = parser->
current.start;
10502 start = token_buffer->
cursor;
10505 const uint8_t *end = parser->
current.end - 1;
10508 token_buffer->
cursor = end;
10513 const uint8_t *start;
10517 start = parser->
current.start;
10522 const uint8_t *end = parser->
current.end - 1;
10529 #undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10535 static inline size_t
10537 size_t whitespace = 0;
10540 case PM_HEREDOC_INDENT_NONE:
10545 case PM_HEREDOC_INDENT_DASH:
10549 case PM_HEREDOC_INDENT_TILDE:
10553 if (**cursor ==
'\t') {
10554 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10573 size_t eol_length = match_eol(parser);
10580 parser_flush_heredoc_end(parser);
10586 const uint8_t delimiter = *parser->
current.end;
10587 parser->
current.end += eol_length;
10592 return *parser->
current.end++;
10599 #define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10618 bool lexed_comment =
false;
10626 case PM_LEX_DEFAULT:
10627 case PM_LEX_EMBEXPR:
10628 case PM_LEX_EMBVAR:
10644 bool space_seen =
false;
10648 bool chomping =
true;
10649 while (parser->
current.end < parser->
end && chomping) {
10650 switch (*parser->
current.end) {
10659 if (match_eol_offset(parser, 1)) {
10662 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10668 size_t eol_length = match_eol_offset(parser, 1);
10674 parser->
current.end += eol_length + 1;
10711 switch (*parser->
current.end++) {
10719 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10720 parser->
current.end = ending == NULL ? parser->
end : ending;
10725 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10728 if (ending) parser->
current.end++;
10730 parser_lex_callback(parser);
10742 parser_lex_magic_comment_encoding(parser);
10746 lexed_comment =
true;
10752 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10764 if (!lexed_comment) {
10765 parser->
current.end += eol_length - 1;
10774 parser_flush_heredoc_end(parser);
10779 switch (lex_state_ignored_p(parser)) {
10780 case PM_IGNORED_NEWLINE_NONE:
10782 case PM_IGNORED_NEWLINE_PATTERN:
10784 if (!lexed_comment) parser_lex_ignored_newline(parser);
10785 lex_state_set(parser, PM_LEX_STATE_BEG);
10791 case PM_IGNORED_NEWLINE_ALL:
10792 if (!lexed_comment) parser_lex_ignored_newline(parser);
10793 lexed_comment =
false;
10794 goto lex_next_token;
10804 if (next_content < parser->end) {
10810 if (next_content[0] ==
'#') {
10812 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10814 while (following && (following + 1 < parser->
end)) {
10820 if (peek_at(parser, following) !=
'#')
break;
10824 following = next_newline(following, parser->
end - following);
10830 lex_state_ignored_p(parser) ||
10832 (peek_at(parser, following) ==
'.') ||
10833 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10836 if (!lexed_comment) parser_lex_ignored_newline(parser);
10837 lexed_comment =
false;
10838 goto lex_next_token;
10844 if (next_content[0] ==
'.') {
10848 if (peek_at(parser, next_content + 1) ==
'.') {
10849 if (!lexed_comment) parser_lex_ignored_newline(parser);
10850 lex_state_set(parser, PM_LEX_STATE_BEG);
10856 if (!lexed_comment) parser_lex_ignored_newline(parser);
10857 lex_state_set(parser, PM_LEX_STATE_DOT);
10858 parser->
current.start = next_content;
10859 parser->
current.end = next_content + 1;
10866 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10867 if (!lexed_comment) parser_lex_ignored_newline(parser);
10868 lex_state_set(parser, PM_LEX_STATE_DOT);
10869 parser->
current.start = next_content;
10870 parser->
current.end = next_content + 2;
10878 lex_state_set(parser, PM_LEX_STATE_BEG);
10881 if (!lexed_comment) parser_lex_callback(parser);
10891 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10898 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10903 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10904 pm_do_loop_stack_push(parser,
false);
10911 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10912 pm_do_loop_stack_pop(parser);
10917 lex_state_set(parser, PM_LEX_STATE_BEG);
10926 if (lex_state_operator_p(parser)) {
10927 if (match(parser,
']')) {
10929 lex_state_set(parser, PM_LEX_STATE_ARG);
10933 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10937 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10941 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10942 pm_do_loop_stack_push(parser,
false);
10948 lex_state_set(parser, PM_LEX_STATE_END);
10949 pm_do_loop_stack_pop(parser);
10959 lex_state_set(parser, PM_LEX_STATE_BEG);
10961 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10963 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10964 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10967 lex_state_set(parser, PM_LEX_STATE_BEG);
10968 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10971 lex_state_set(parser, PM_LEX_STATE_BEG);
10974 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10979 pm_do_loop_stack_push(parser,
false);
10987 pm_do_loop_stack_pop(parser);
10990 lex_mode_pop(parser);
10995 lex_state_set(parser, PM_LEX_STATE_END);
11000 if (match(parser,
'*')) {
11001 if (match(parser,
'=')) {
11002 lex_state_set(parser, PM_LEX_STATE_BEG);
11008 if (lex_state_spcarg_p(parser, space_seen)) {
11009 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11011 }
else if (lex_state_beg_p(parser)) {
11013 }
else if (ambiguous_operator_p(parser, space_seen)) {
11014 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11017 if (lex_state_operator_p(parser)) {
11018 lex_state_set(parser, PM_LEX_STATE_ARG);
11020 lex_state_set(parser, PM_LEX_STATE_BEG);
11026 if (match(parser,
'=')) {
11027 lex_state_set(parser, PM_LEX_STATE_BEG);
11033 if (lex_state_spcarg_p(parser, space_seen)) {
11034 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11036 }
else if (lex_state_beg_p(parser)) {
11038 }
else if (ambiguous_operator_p(parser, space_seen)) {
11039 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11042 if (lex_state_operator_p(parser)) {
11043 lex_state_set(parser, PM_LEX_STATE_ARG);
11045 lex_state_set(parser, PM_LEX_STATE_BEG);
11053 if (lex_state_operator_p(parser)) {
11054 lex_state_set(parser, PM_LEX_STATE_ARG);
11055 if (match(parser,
'@')) {
11059 lex_state_set(parser, PM_LEX_STATE_BEG);
11062 if (match(parser,
'=')) {
11066 if (match(parser,
'~')) {
11075 current_token_starts_line(parser) &&
11077 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11085 goto lex_next_token;
11088 if (lex_state_operator_p(parser)) {
11089 lex_state_set(parser, PM_LEX_STATE_ARG);
11091 lex_state_set(parser, PM_LEX_STATE_BEG);
11094 if (match(parser,
'>')) {
11098 if (match(parser,
'~')) {
11102 if (match(parser,
'=')) {
11110 if (match(parser,
'<')) {
11112 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11113 !lex_state_end_p(parser) &&
11114 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11116 const uint8_t *end = parser->
current.end;
11121 if (match(parser,
'-')) {
11122 indent = PM_HEREDOC_INDENT_DASH;
11124 else if (match(parser,
'~')) {
11125 indent = PM_HEREDOC_INDENT_TILDE;
11128 if (match(parser,
'`')) {
11129 quote = PM_HEREDOC_QUOTE_BACKTICK;
11131 else if (match(parser,
'"')) {
11132 quote = PM_HEREDOC_QUOTE_DOUBLE;
11134 else if (match(parser,
'\'')) {
11135 quote = PM_HEREDOC_QUOTE_SINGLE;
11138 const uint8_t *ident_start = parser->
current.end;
11143 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end)) == 0) {
11146 if (quote == PM_HEREDOC_QUOTE_NONE) {
11147 parser->
current.end += width;
11149 while ((parser->
current.end < parser->
end) && (width = char_is_identifier(parser, parser->
current.end))) {
11150 parser->
current.end += width;
11156 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11161 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11162 bool ident_error =
false;
11164 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11165 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11166 ident_error =
true;
11171 .mode = PM_LEX_HEREDOC,
11174 .ident_start = ident_start,
11175 .ident_length = ident_length,
11179 .next_start = parser->
current.end,
11181 .line_continuation =
false
11186 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11188 if (body_start == NULL) {
11193 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11194 body_start = parser->
end;
11211 if (match(parser,
'=')) {
11212 lex_state_set(parser, PM_LEX_STATE_BEG);
11216 if (ambiguous_operator_p(parser, space_seen)) {
11217 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11220 if (lex_state_operator_p(parser)) {
11221 lex_state_set(parser, PM_LEX_STATE_ARG);
11223 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11224 lex_state_set(parser, PM_LEX_STATE_BEG);
11230 if (lex_state_operator_p(parser)) {
11231 lex_state_set(parser, PM_LEX_STATE_ARG);
11233 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11234 lex_state_set(parser, PM_LEX_STATE_BEG);
11237 if (match(parser,
'=')) {
11238 if (match(parser,
'>')) {
11249 if (match(parser,
'>')) {
11250 if (lex_state_operator_p(parser)) {
11251 lex_state_set(parser, PM_LEX_STATE_ARG);
11253 lex_state_set(parser, PM_LEX_STATE_BEG);
11258 if (lex_state_operator_p(parser)) {
11259 lex_state_set(parser, PM_LEX_STATE_ARG);
11261 lex_state_set(parser, PM_LEX_STATE_BEG);
11268 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11269 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11275 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11276 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11280 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11281 if (previous_command_start) {
11282 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11284 lex_state_set(parser, PM_LEX_STATE_ARG);
11290 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11296 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11297 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11303 LEX(lex_question_mark(parser));
11307 if (match(parser,
'&')) {
11308 lex_state_set(parser, PM_LEX_STATE_BEG);
11310 if (match(parser,
'=')) {
11317 if (match(parser,
'=')) {
11318 lex_state_set(parser, PM_LEX_STATE_BEG);
11322 if (match(parser,
'.')) {
11323 lex_state_set(parser, PM_LEX_STATE_DOT);
11328 if (lex_state_spcarg_p(parser, space_seen)) {
11329 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11330 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11332 const uint8_t delim = peek_offset(parser, 1);
11334 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1)) {
11335 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11340 }
else if (lex_state_beg_p(parser)) {
11342 }
else if (ambiguous_operator_p(parser, space_seen)) {
11343 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11346 if (lex_state_operator_p(parser)) {
11347 lex_state_set(parser, PM_LEX_STATE_ARG);
11349 lex_state_set(parser, PM_LEX_STATE_BEG);
11357 if (match(parser,
'|')) {
11358 if (match(parser,
'=')) {
11359 lex_state_set(parser, PM_LEX_STATE_BEG);
11363 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11368 lex_state_set(parser, PM_LEX_STATE_BEG);
11372 if (match(parser,
'=')) {
11373 lex_state_set(parser, PM_LEX_STATE_BEG);
11377 if (lex_state_operator_p(parser)) {
11378 lex_state_set(parser, PM_LEX_STATE_ARG);
11380 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11387 if (lex_state_operator_p(parser)) {
11388 lex_state_set(parser, PM_LEX_STATE_ARG);
11390 if (match(parser,
'@')) {
11397 if (match(parser,
'=')) {
11398 lex_state_set(parser, PM_LEX_STATE_BEG);
11403 lex_state_beg_p(parser) ||
11404 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) :
false)
11406 lex_state_set(parser, PM_LEX_STATE_BEG);
11411 lex_state_set(parser, PM_LEX_STATE_END);
11418 if (ambiguous_operator_p(parser, space_seen)) {
11419 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11422 lex_state_set(parser, PM_LEX_STATE_BEG);
11428 if (lex_state_operator_p(parser)) {
11429 lex_state_set(parser, PM_LEX_STATE_ARG);
11431 if (match(parser,
'@')) {
11438 if (match(parser,
'=')) {
11439 lex_state_set(parser, PM_LEX_STATE_BEG);
11443 if (match(parser,
'>')) {
11444 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11448 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11449 bool is_beg = lex_state_beg_p(parser);
11450 if (!is_beg && spcarg) {
11451 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11454 if (is_beg || spcarg) {
11455 lex_state_set(parser, PM_LEX_STATE_BEG);
11459 if (ambiguous_operator_p(parser, space_seen)) {
11460 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11463 lex_state_set(parser, PM_LEX_STATE_BEG);
11469 bool beg_p = lex_state_beg_p(parser);
11471 if (match(parser,
'.')) {
11472 if (match(parser,
'.')) {
11475 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11476 lex_state_set(parser, PM_LEX_STATE_BEG);
11478 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11484 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11487 lex_state_set(parser, PM_LEX_STATE_BEG);
11491 lex_state_set(parser, PM_LEX_STATE_BEG);
11495 lex_state_set(parser, PM_LEX_STATE_DOT);
11511 lex_state_set(parser, PM_LEX_STATE_END);
11517 if (match(parser,
':')) {
11518 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)) {
11519 lex_state_set(parser, PM_LEX_STATE_BEG);
11523 lex_state_set(parser, PM_LEX_STATE_DOT);
11528 lex_state_set(parser, PM_LEX_STATE_BEG);
11532 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11533 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11537 lex_state_set(parser, PM_LEX_STATE_FNAME);
11542 if (lex_state_beg_p(parser)) {
11543 lex_mode_push_regexp(parser,
'\0',
'/');
11547 if (match(parser,
'=')) {
11548 lex_state_set(parser, PM_LEX_STATE_BEG);
11552 if (lex_state_spcarg_p(parser, space_seen)) {
11553 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11554 lex_mode_push_regexp(parser,
'\0',
'/');
11558 if (ambiguous_operator_p(parser, space_seen)) {
11559 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11562 if (lex_state_operator_p(parser)) {
11563 lex_state_set(parser, PM_LEX_STATE_ARG);
11565 lex_state_set(parser, PM_LEX_STATE_BEG);
11572 if (lex_state_operator_p(parser)) {
11573 lex_state_set(parser, PM_LEX_STATE_ARG);
11575 lex_state_set(parser, PM_LEX_STATE_BEG);
11581 if (lex_state_operator_p(parser)) {
11582 (void) match(parser,
'@');
11583 lex_state_set(parser, PM_LEX_STATE_ARG);
11585 lex_state_set(parser, PM_LEX_STATE_BEG);
11596 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11597 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11601 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11602 lex_state_set(parser, PM_LEX_STATE_BEG);
11605 lex_state_beg_p(parser) ||
11606 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11607 lex_state_spcarg_p(parser, space_seen)
11610 if (*parser->
current.end >= 0x80) {
11611 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11614 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11615 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11621 uint8_t delimiter = peek_offset(parser, 1);
11623 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11624 goto lex_next_token;
11627 switch (peek(parser)) {
11632 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11634 lex_mode_push_list_eof(parser);
11643 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11645 lex_mode_push_list_eof(parser);
11654 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11655 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11657 lex_mode_push_regexp(parser,
'\0',
'\0');
11666 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11667 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11669 lex_mode_push_string_eof(parser);
11678 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11679 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11681 lex_mode_push_string_eof(parser);
11690 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11691 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11692 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11694 lex_mode_push_string_eof(parser);
11703 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11705 lex_mode_push_list_eof(parser);
11714 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11716 lex_mode_push_list_eof(parser);
11725 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11726 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11728 lex_mode_push_string_eof(parser);
11738 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11739 goto lex_next_token;
11743 if (ambiguous_operator_p(parser, space_seen)) {
11744 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11747 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11758 lex_mode_pop(parser);
11761 lex_state_set(parser, PM_LEX_STATE_END);
11767 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11768 LEX(lex_at_variable(parser));
11771 if (*parser->
current.start !=
'_') {
11772 size_t width = char_is_identifier_start(parser, parser->
current.start);
11779 if (*parser->
current.start >= 0x80) {
11780 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11781 }
else if (*parser->
current.start ==
'\\') {
11782 switch (peek_at(parser, parser->
current.start + 1)) {
11785 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11789 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11793 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11797 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11800 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11802 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11807 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11810 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11811 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11813 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11816 goto lex_next_token;
11830 current_token_starts_line(parser) &&
11831 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11832 (parser->
current.end == parser->
end || match_eol(parser))
11837 const uint8_t *cursor = parser->
current.end;
11838 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11844 parser_lex_callback(parser);
11855 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11856 if (previous_command_start) {
11857 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11859 lex_state_set(parser, PM_LEX_STATE_ARG);
11861 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11862 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11864 lex_state_set(parser, PM_LEX_STATE_END);
11869 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11871 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11872 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11874 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11881 case PM_LEX_LIST: {
11896 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11903 if (whitespace > 0) {
11904 parser->
current.end += whitespace;
11905 if (peek_offset(parser, -1) ==
'\n') {
11907 parser_flush_heredoc_end(parser);
11921 const uint8_t *breakpoints = lex_mode->
as.list.breakpoints;
11928 while (breakpoint != NULL) {
11932 parser->
current.end = breakpoint;
11933 pm_token_buffer_flush(parser, &token_buffer);
11939 if (*breakpoint == lex_mode->
as.list.terminator) {
11942 if (lex_mode->
as.list.nesting > 0) {
11943 parser->
current.end = breakpoint + 1;
11945 lex_mode->
as.list.nesting--;
11951 if (breakpoint > parser->
current.start) {
11952 parser->
current.end = breakpoint;
11953 pm_token_buffer_flush(parser, &token_buffer);
11959 parser->
current.end = breakpoint + 1;
11960 lex_mode_pop(parser);
11961 lex_state_set(parser, PM_LEX_STATE_END);
11966 if (*breakpoint ==
'\0') {
11967 breakpoint =
pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11974 if (*breakpoint ==
'\\') {
11975 parser->
current.end = breakpoint + 1;
11984 pm_token_buffer_escape(parser, &token_buffer);
11985 uint8_t peeked = peek(parser);
11993 pm_token_buffer_push_byte(&token_buffer, peeked);
11998 if (peek(parser) !=
'\n') {
11999 pm_token_buffer_push_byte(&token_buffer,
'\r');
12004 pm_token_buffer_push_byte(&token_buffer,
'\n');
12010 parser_flush_heredoc_end(parser);
12011 pm_token_buffer_copy(parser, &token_buffer);
12021 if (peeked == lex_mode->
as.list.incrementor || peeked == lex_mode->
as.list.terminator) {
12022 pm_token_buffer_push_byte(&token_buffer, peeked);
12024 }
else if (lex_mode->
as.list.interpolation) {
12025 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12027 pm_token_buffer_push_byte(&token_buffer,
'\\');
12028 pm_token_buffer_push_escaped(&token_buffer, parser);
12040 if (*breakpoint ==
'#') {
12053 pm_token_buffer_flush(parser, &token_buffer);
12061 assert(*breakpoint == lex_mode->
as.list.incrementor);
12062 parser->
current.end = breakpoint + 1;
12064 lex_mode->
as.list.nesting++;
12069 pm_token_buffer_flush(parser, &token_buffer);
12076 pm_token_buffer_flush(parser, &token_buffer);
12079 case PM_LEX_REGEXP: {
12101 const uint8_t *breakpoints = lex_mode->
as.regexp.breakpoints;
12105 while (breakpoint != NULL) {
12108 if (*breakpoint == lex_mode->
as.regexp.terminator) {
12109 if (lex_mode->
as.regexp.nesting > 0) {
12110 parser->
current.end = breakpoint + 1;
12112 lex_mode->
as.regexp.nesting--;
12119 if (breakpoint > parser->
current.start) {
12120 parser->
current.end = breakpoint;
12121 pm_regexp_token_buffer_flush(parser, &token_buffer);
12126 size_t eol_length = match_eol_at(parser, breakpoint);
12128 parser->
current.end = breakpoint + eol_length;
12131 parser->
current.end = breakpoint + 1;
12138 lex_mode_pop(parser);
12139 lex_state_set(parser, PM_LEX_STATE_END);
12145 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.incrementor) {
12146 parser->
current.end = breakpoint + 1;
12148 lex_mode->
as.regexp.nesting++;
12152 switch (*breakpoint) {
12155 parser->
current.end = breakpoint + 1;
12159 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12160 parser->
current.end = breakpoint + 1;
12166 parser->
current.end = breakpoint;
12167 pm_regexp_token_buffer_escape(parser, &token_buffer);
12176 parser->
current.end = breakpoint + 1;
12181 parser->
current.end = breakpoint + 1;
12182 parser_flush_heredoc_end(parser);
12183 pm_regexp_token_buffer_flush(parser, &token_buffer);
12189 parser->
current.end = breakpoint + 1;
12198 pm_regexp_token_buffer_escape(parser, &token_buffer);
12199 uint8_t peeked = peek(parser);
12204 if (peek(parser) !=
'\n') {
12205 if (lex_mode->
as.regexp.terminator !=
'\r') {
12206 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12208 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12209 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12218 parser_flush_heredoc_end(parser);
12219 pm_regexp_token_buffer_copy(parser, &token_buffer);
12236 if (lex_mode->
as.regexp.terminator == peeked) {
12241 case '$':
case ')':
case '*':
case '+':
12242 case '.':
case '>':
case '?':
case ']':
12243 case '^':
case '|':
case '}':
12244 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12250 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12251 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12256 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12257 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12280 pm_regexp_token_buffer_flush(parser, &token_buffer);
12286 assert(
false &&
"unreachable");
12292 pm_regexp_token_buffer_flush(parser, &token_buffer);
12299 pm_regexp_token_buffer_flush(parser, &token_buffer);
12302 case PM_LEX_STRING: {
12321 const uint8_t *breakpoints = lex_mode->
as.string.breakpoints;
12328 while (breakpoint != NULL) {
12331 if (lex_mode->
as.string.incrementor !=
'\0' && *breakpoint == lex_mode->
as.string.incrementor) {
12332 lex_mode->
as.string.nesting++;
12333 parser->
current.end = breakpoint + 1;
12341 if (*breakpoint == lex_mode->
as.string.terminator) {
12344 if (lex_mode->
as.string.nesting > 0) {
12345 parser->
current.end = breakpoint + 1;
12347 lex_mode->
as.string.nesting--;
12353 if (breakpoint > parser->
current.start) {
12354 parser->
current.end = breakpoint;
12355 pm_token_buffer_flush(parser, &token_buffer);
12361 size_t eol_length = match_eol_at(parser, breakpoint);
12363 parser->
current.end = breakpoint + eol_length;
12366 parser->
current.end = breakpoint + 1;
12369 if (lex_mode->
as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12371 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12372 lex_mode_pop(parser);
12376 lex_state_set(parser, PM_LEX_STATE_END);
12377 lex_mode_pop(parser);
12381 switch (*breakpoint) {
12384 parser->
current.end = breakpoint + 1;
12388 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12389 parser->
current.end = breakpoint + 1;
12397 parser->
current.end = breakpoint;
12398 pm_token_buffer_escape(parser, &token_buffer);
12399 token_buffer.
cursor = breakpoint;
12409 parser->
current.end = breakpoint + 1;
12414 parser->
current.end = breakpoint + 1;
12415 parser_flush_heredoc_end(parser);
12416 pm_token_buffer_flush(parser, &token_buffer);
12420 parser->
current.end = breakpoint + 1;
12429 pm_token_buffer_escape(parser, &token_buffer);
12430 uint8_t peeked = peek(parser);
12434 pm_token_buffer_push_byte(&token_buffer,
'\\');
12439 if (peek(parser) !=
'\n') {
12440 if (!lex_mode->
as.string.interpolation) {
12441 pm_token_buffer_push_byte(&token_buffer,
'\\');
12443 pm_token_buffer_push_byte(&token_buffer,
'\r');
12448 if (!lex_mode->
as.string.interpolation) {
12449 pm_token_buffer_push_byte(&token_buffer,
'\\');
12450 pm_token_buffer_push_byte(&token_buffer,
'\n');
12457 parser_flush_heredoc_end(parser);
12458 pm_token_buffer_copy(parser, &token_buffer);
12468 if (lex_mode->
as.string.incrementor !=
'\0' && peeked == lex_mode->
as.string.incrementor) {
12469 pm_token_buffer_push_byte(&token_buffer, peeked);
12471 }
else if (lex_mode->
as.string.terminator !=
'\0' && peeked == lex_mode->
as.string.terminator) {
12472 pm_token_buffer_push_byte(&token_buffer, peeked);
12474 }
else if (lex_mode->
as.string.interpolation) {
12475 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12477 pm_token_buffer_push_byte(&token_buffer,
'\\');
12478 pm_token_buffer_push_escaped(&token_buffer, parser);
12501 pm_token_buffer_flush(parser, &token_buffer);
12507 assert(
false &&
"unreachable");
12512 pm_token_buffer_flush(parser, &token_buffer);
12519 pm_token_buffer_flush(parser, &token_buffer);
12522 case PM_LEX_HEREDOC: {
12538 bool line_continuation = lex_mode->
as.heredoc.line_continuation;
12539 lex_mode->
as.heredoc.line_continuation =
false;
12549 lex_state_set(parser, PM_LEX_STATE_END);
12550 lex_mode_pop(parser);
12554 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12559 if (current_token_starts_line(parser)) {
12560 const uint8_t *start = parser->
current.start;
12562 if (!line_continuation && (start + ident_length <= parser->end)) {
12563 const uint8_t *newline = next_newline(start, parser->
end - start);
12564 const uint8_t *ident_end = newline;
12565 const uint8_t *terminator_end = newline;
12567 if (newline == NULL) {
12568 terminator_end = parser->
end;
12569 ident_end = parser->
end;
12572 if (newline[-1] ==
'\r') {
12577 const uint8_t *terminator_start = ident_end - ident_length;
12578 const uint8_t *cursor = start;
12580 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12587 (cursor == terminator_start) &&
12588 (memcmp(terminator_start, ident_start, ident_length) == 0)
12590 if (newline != NULL) {
12594 parser->
current.end = terminator_end;
12595 if (*lex_mode->
as.heredoc.next_start ==
'\\') {
12602 lex_state_set(parser, PM_LEX_STATE_END);
12603 lex_mode_pop(parser);
12608 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12610 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12611 lex_mode->
as.heredoc.common_whitespace != NULL &&
12612 (*lex_mode->
as.heredoc.common_whitespace > whitespace) &&
12613 peek_at(parser, start) !=
'\n'
12615 *lex_mode->
as.heredoc.common_whitespace = whitespace;
12622 uint8_t breakpoints[] =
"\r\n\\#";
12625 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12626 breakpoints[3] =
'\0';
12631 bool was_line_continuation =
false;
12633 while (breakpoint != NULL) {
12634 switch (*breakpoint) {
12637 parser->
current.end = breakpoint + 1;
12641 parser->
current.end = breakpoint + 1;
12643 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12651 pm_token_buffer_escape(parser, &token_buffer);
12652 token_buffer.
cursor = breakpoint;
12657 parser_flush_heredoc_end(parser);
12658 parser->
current.end = breakpoint + 1;
12659 pm_token_buffer_flush(parser, &token_buffer);
12667 const uint8_t *start = breakpoint + 1;
12669 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12672 const uint8_t *newline = next_newline(start, parser->
end - start);
12674 if (newline == NULL) {
12675 newline = parser->
end;
12676 }
else if (newline[-1] ==
'\r') {
12681 const uint8_t *terminator_start = newline - ident_length;
12685 const uint8_t *cursor = start;
12687 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12694 cursor == terminator_start &&
12695 (memcmp(terminator_start, ident_start, ident_length) == 0)
12697 parser->
current.end = breakpoint + 1;
12698 pm_token_buffer_flush(parser, &token_buffer);
12703 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.base.indent);
12710 if (lex_mode->
as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12711 if ((lex_mode->
as.heredoc.common_whitespace != NULL) && (*lex_mode->
as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12712 *lex_mode->
as.heredoc.common_whitespace = whitespace;
12715 parser->
current.end = breakpoint + 1;
12716 pm_token_buffer_flush(parser, &token_buffer);
12722 parser->
current.end = breakpoint + 1;
12733 parser->
current.end = breakpoint + 1;
12742 pm_token_buffer_escape(parser, &token_buffer);
12743 uint8_t peeked = peek(parser);
12745 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12749 if (peek(parser) !=
'\n') {
12750 pm_token_buffer_push_byte(&token_buffer,
'\\');
12751 pm_token_buffer_push_byte(&token_buffer,
'\r');
12756 pm_token_buffer_push_byte(&token_buffer,
'\\');
12757 pm_token_buffer_push_byte(&token_buffer,
'\n');
12759 breakpoint = parser->
current.end;
12762 pm_token_buffer_push_byte(&token_buffer,
'\\');
12763 pm_token_buffer_push_escaped(&token_buffer, parser);
12770 if (peek(parser) !=
'\n') {
12771 pm_token_buffer_push_byte(&token_buffer,
'\r');
12779 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12780 const uint8_t *end = parser->
current.end;
12785 parser->
current.end = breakpoint;
12786 pm_token_buffer_flush(parser, &token_buffer);
12790 parser->
current.end = end + 1;
12791 lex_mode->
as.heredoc.line_continuation =
true;
12795 was_line_continuation =
true;
12797 breakpoint = parser->
current.end;
12800 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12823 pm_token_buffer_flush(parser, &token_buffer);
12829 assert(
false &&
"unreachable");
12832 was_line_continuation =
false;
12837 pm_token_buffer_flush(parser, &token_buffer);
12844 pm_token_buffer_flush(parser, &token_buffer);
12849 assert(
false &&
"unreachable");
12867 PM_BINDING_POWER_UNSET = 0,
12868 PM_BINDING_POWER_STATEMENT = 2,
12869 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12870 PM_BINDING_POWER_MODIFIER = 6,
12871 PM_BINDING_POWER_COMPOSITION = 8,
12872 PM_BINDING_POWER_NOT = 10,
12873 PM_BINDING_POWER_MATCH = 12,
12874 PM_BINDING_POWER_DEFINED = 14,
12875 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12876 PM_BINDING_POWER_ASSIGNMENT = 18,
12877 PM_BINDING_POWER_TERNARY = 20,
12878 PM_BINDING_POWER_RANGE = 22,
12879 PM_BINDING_POWER_LOGICAL_OR = 24,
12880 PM_BINDING_POWER_LOGICAL_AND = 26,
12881 PM_BINDING_POWER_EQUALITY = 28,
12882 PM_BINDING_POWER_COMPARISON = 30,
12883 PM_BINDING_POWER_BITWISE_OR = 32,
12884 PM_BINDING_POWER_BITWISE_AND = 34,
12885 PM_BINDING_POWER_SHIFT = 36,
12886 PM_BINDING_POWER_TERM = 38,
12887 PM_BINDING_POWER_FACTOR = 40,
12888 PM_BINDING_POWER_UMINUS = 42,
12889 PM_BINDING_POWER_EXPONENT = 44,
12890 PM_BINDING_POWER_UNARY = 46,
12891 PM_BINDING_POWER_INDEX = 48,
12892 PM_BINDING_POWER_CALL = 50,
12893 PM_BINDING_POWER_MAX = 52
12894 } pm_binding_power_t;
12917 #define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12918 #define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12919 #define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12920 #define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12921 #define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12983 [
PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12987 [
PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12988 [
PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13004 [
PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13005 [
PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13008 [
PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13016 [
PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13017 [
PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13018 [
PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13025 [
PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13029 #undef BINDING_POWER_ASSIGNMENT
13030 #undef LEFT_ASSOCIATIVE
13031 #undef RIGHT_ASSOCIATIVE
13032 #undef RIGHT_ASSOCIATIVE_UNARY
13047 return match1(parser, type1) || match1(parser, type2);
13055 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13063 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13071 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
13079 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13087 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);
13098 if (match1(parser,
type)) {
13099 parser_lex(parser);
13111 if (match2(parser, type1, type2)) {
13112 parser_lex(parser);
13124 if (match3(parser, type1, type2, type3)) {
13125 parser_lex(parser);
13144 if (accept1(parser,
type))
return;
13147 pm_parser_err(parser, location, location, diag_id);
13159 if (accept2(parser, type1, type2))
return;
13162 pm_parser_err(parser, location, location, diag_id);
13173 if (accept3(parser, type1, type2, type3))
return;
13176 pm_parser_err(parser, location, location, diag_id);
13187 expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13189 parser_lex(parser);
13191 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13198 parse_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);
13205 parse_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) {
13206 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13207 pm_assert_value_expression(parser, node);
13261 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13281 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13290 parse_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) {
13293 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13294 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13297 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13311 size_t length = constant->
length;
13312 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13313 if (name == NULL)
return;
13315 memcpy(name, constant->
start, length);
13316 name[length] =
'=';
13333 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13334 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13335 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13336 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13337 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13338 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13339 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13359 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13360 if (implicit_parameters->
nodes[index] == node) {
13364 if (index != implicit_parameters->
size - 1) {
13365 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13368 implicit_parameters->
size--;
13396 return parse_unwriteable_target(parser, target);
13403 if (context_def_p(parser)) {
13404 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13412 if (context_def_p(parser)) {
13413 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13422 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13431 parse_target_implicit_parameter(parser, target);
13435 uint32_t name = cast->
name;
13436 uint32_t depth = cast->
depth;
13437 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13448 parse_target_implicit_parameter(parser, target);
13458 if (splat_parent) {
13461 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13486 (call->
block == NULL)
13503 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13508 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13511 parse_write_name(parser, &call->
name);
13512 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13520 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13528 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13539 pm_node_t *result = parse_target(parser, target, multiple,
false);
13548 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13562 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13563 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13586 if (context_def_p(parser)) {
13587 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13590 return parse_shareable_constant_write(parser, node);
13595 if (context_def_p(parser)) {
13596 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13600 return parse_shareable_constant_write(parser, node);
13604 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13617 uint32_t depth = local_read->
depth;
13618 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13621 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13623 parse_target_implicit_parameter(parser, target);
13626 pm_locals_unread(&scope->
locals, name);
13629 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13635 parse_target_implicit_parameter(parser, target);
13655 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13657 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13671 (call->
block == NULL)
13685 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13689 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13691 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13709 pm_arguments_node_arguments_append(arguments, value);
13712 parse_write_name(parser, &call->
name);
13724 call->
arguments = pm_arguments_node_create(parser);
13727 pm_arguments_node_arguments_append(call->
arguments, value);
13731 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13749 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13763 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13764 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13765 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13766 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13767 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13768 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13769 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13791 parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13795 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13803 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13809 if (token_begins_expression_p(parser->
current.type)) {
13810 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13811 name = parse_target(parser, name,
true,
true);
13814 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13815 pm_multi_target_node_targets_append(parser, result, splat);
13819 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13820 target = parse_target(parser, target,
true,
false);
13822 pm_multi_target_node_targets_append(parser, result, target);
13823 context_pop(parser);
13824 }
else if (token_begins_expression_p(parser->
current.type)) {
13825 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13826 target = parse_target(parser, target,
true,
false);
13828 pm_multi_target_node_targets_append(parser, result, target);
13833 pm_multi_target_node_targets_append(parser, result, rest);
13846 parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13847 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13852 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13868 if (context_terminator(context, &parser->
current))
return NULL;
13874 context_push(parser, context);
13877 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13878 pm_statements_node_body_append(parser, statements, node,
true);
13895 if (context_terminator(context, &parser->
current))
break;
13905 if (context_terminator(context, &parser->
current))
break;
13918 parser_lex(parser);
13921 if (context_terminator(context, &parser->
current))
break;
13932 context_pop(parser);
13933 bool last_value =
true;
13937 last_value =
false;
13942 pm_void_statements_check(parser, statements, last_value);
13955 if (duplicated != NULL) {
13963 PM_WARN_DUPLICATED_HASH_KEY,
13986 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13999 bool contains_keyword_splat =
false;
14004 switch (parser->
current.type) {
14006 parser_lex(parser);
14016 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14017 }
else if (token_begins_expression_p(parser->
current.type)) {
14018 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14020 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14023 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14024 contains_keyword_splat =
true;
14029 parser_lex(parser);
14032 pm_hash_key_static_literals_add(parser, literals, key);
14037 if (token_begins_expression_p(parser->
current.type)) {
14038 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14042 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14047 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14048 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14050 depth = pm_parser_local_depth(parser, &identifier);
14054 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14056 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14061 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14064 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14068 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14076 pm_hash_key_static_literals_add(parser, literals, key);
14079 if (pm_symbol_node_label_p(key)) {
14080 operator = not_provided(parser);
14086 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14087 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14107 if (token_begins_expression_p(parser->
current.type))
continue;
14113 return contains_keyword_splat;
14122 arguments->
arguments = pm_arguments_node_create(parser);
14125 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14133 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
14139 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14145 bool parsed_first_argument =
false;
14146 bool parsed_bare_hash =
false;
14147 bool parsed_block_argument =
false;
14148 bool parsed_forwarding_arguments =
false;
14151 if (parsed_block_argument) {
14152 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14154 if (parsed_forwarding_arguments) {
14155 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14160 switch (parser->
current.type) {
14163 if (parsed_bare_hash) {
14164 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14171 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14173 parse_arguments_append(parser, arguments, argument);
14180 parsed_bare_hash =
true;
14185 parser_lex(parser);
14189 if (token_begins_expression_p(parser->
current.type)) {
14190 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14192 pm_parser_scope_forwarding_block_check(parser, &
operator);
14195 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14196 if (parsed_block_argument) {
14197 parse_arguments_append(parser, arguments, argument);
14199 arguments->
block = argument;
14202 parsed_block_argument =
true;
14206 parser_lex(parser);
14210 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14211 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14212 if (parsed_bare_hash) {
14213 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14216 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14218 if (parsed_bare_hash) {
14219 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14222 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14225 parse_arguments_append(parser, arguments, argument);
14229 if (accepts_forwarding) {
14230 parser_lex(parser);
14232 if (token_begins_expression_p(parser->
current.type)) {
14237 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14244 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14247 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14249 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14250 if (parsed_first_argument && terminator ==
PM_TOKEN_EOF) {
14251 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14254 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14255 parse_arguments_append(parser, arguments, argument);
14258 parsed_forwarding_arguments =
true;
14265 if (argument == NULL) {
14266 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14269 bool contains_keywords =
false;
14270 bool contains_keyword_splat =
false;
14273 if (parsed_bare_hash) {
14274 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14281 operator = not_provided(parser);
14285 contains_keywords =
true;
14289 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14292 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14293 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14295 pm_keyword_hash_node_elements_append(bare_hash, argument);
14300 token_begins_expression_p(parser->
current.type) ||
14303 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14307 parsed_bare_hash =
true;
14310 parse_arguments_append(parser, arguments, argument);
14321 parsed_first_argument =
true;
14329 bool accepted_newline =
false;
14341 if (accepted_newline) {
14342 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14352 if (match1(parser, terminator))
break;
14367 parse_required_destructured_parameter(
pm_parser_t *parser) {
14371 pm_multi_target_node_opening_set(node, &parser->
previous);
14382 pm_multi_target_node_targets_append(parser, node, param);
14383 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14388 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14395 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14396 if (pm_parser_parameter_name_check(parser, &name)) {
14397 pm_node_flag_set_repeated_parameter(value);
14399 pm_parser_local_add_token(parser, &name, 1);
14402 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14407 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14408 if (pm_parser_parameter_name_check(parser, &name)) {
14409 pm_node_flag_set_repeated_parameter(param);
14411 pm_parser_local_add_token(parser, &name, 1);
14414 pm_multi_target_node_targets_append(parser, node, param);
14419 pm_multi_target_node_closing_set(node, &parser->
previous);
14429 PM_PARAMETERS_NO_CHANGE = 0,
14430 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14431 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14432 PM_PARAMETERS_ORDER_KEYWORDS,
14433 PM_PARAMETERS_ORDER_REST,
14434 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14435 PM_PARAMETERS_ORDER_OPTIONAL,
14436 PM_PARAMETERS_ORDER_NAMED,
14437 PM_PARAMETERS_ORDER_NONE,
14438 } pm_parameters_order_t;
14444 [0] = PM_PARAMETERS_NO_CHANGE,
14467 pm_parameters_order_t state = parameters_ordering[token->type];
14468 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14472 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14473 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14475 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14479 if (token->type ==
PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14480 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14482 }
else if (token->type ==
PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14483 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14485 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14487 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14491 if (state < *current) *current = state;
14501 pm_binding_power_t binding_power,
14502 bool uses_parentheses,
14503 bool allows_trailing_comma,
14504 bool allows_forwarding_parameters,
14505 bool accepts_blocks_in_defaults,
14508 pm_do_loop_stack_push(parser,
false);
14511 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14514 bool parsing =
true;
14516 switch (parser->
current.type) {
14518 update_parameter_state(parser, &parser->
current, &order);
14521 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14522 pm_parameters_node_requireds_append(params, param);
14524 pm_parameters_node_posts_append(params, param);
14530 update_parameter_state(parser, &parser->
current, &order);
14531 parser_lex(parser);
14536 bool repeated =
false;
14539 repeated = pm_parser_parameter_name_check(parser, &name);
14540 pm_parser_local_add_token(parser, &name, 1);
14542 name = not_provided(parser);
14548 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14550 if (params->
block == NULL) {
14551 pm_parameters_node_block_set(params, param);
14553 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14554 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14560 if (!allows_forwarding_parameters) {
14561 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14564 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14565 parser_lex(parser);
14574 pm_parameters_node_posts_append(params, keyword_rest);
14575 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14579 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14588 parser_lex(parser);
14591 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14594 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14597 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14600 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14603 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14609 update_parameter_state(parser, &parser->
current, &order);
14611 update_parameter_state(parser, &parser->
previous, &order);
14615 bool repeated = pm_parser_parameter_name_check(parser, &name);
14616 pm_parser_local_add_token(parser, &name, 1);
14621 parser_lex(parser);
14626 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14627 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14628 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14633 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14635 pm_parameters_node_optionals_append(params, param);
14641 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14644 context_pop(parser);
14653 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14656 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14658 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14662 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14664 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14671 update_parameter_state(parser, &parser->
current, &order);
14674 parser_lex(parser);
14681 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14682 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14683 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14686 bool repeated = pm_parser_parameter_name_check(parser, &local);
14687 pm_parser_local_add_token(parser, &local, 1);
14689 switch (parser->
current.type) {
14693 context_pop(parser);
14695 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14697 pm_node_flag_set_repeated_parameter(param);
14700 pm_parameters_node_keywords_append(params, param);
14705 context_pop(parser);
14707 if (uses_parentheses) {
14712 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14714 pm_node_flag_set_repeated_parameter(param);
14717 pm_parameters_node_keywords_append(params, param);
14723 if (token_begins_expression_p(parser->
current.type)) {
14727 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14728 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14729 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14732 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14735 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14738 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14742 pm_node_flag_set_repeated_parameter(param);
14745 context_pop(parser);
14746 pm_parameters_node_keywords_append(params, param);
14763 update_parameter_state(parser, &parser->
current, &order);
14764 parser_lex(parser);
14768 bool repeated =
false;
14772 repeated = pm_parser_parameter_name_check(parser, &name);
14773 pm_parser_local_add_token(parser, &name, 1);
14775 name = not_provided(parser);
14779 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14781 pm_node_flag_set_repeated_parameter(param);
14784 if (params->
rest == NULL) {
14785 pm_parameters_node_rest_set(params, param);
14787 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14788 pm_parameters_node_posts_append(params, param);
14795 pm_parameters_order_t previous_order = order;
14796 update_parameter_state(parser, &parser->
current, &order);
14797 parser_lex(parser);
14803 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14804 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14807 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14811 bool repeated =
false;
14814 repeated = pm_parser_parameter_name_check(parser, &name);
14815 pm_parser_local_add_token(parser, &name, 1);
14817 name = not_provided(parser);
14821 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14823 pm_node_flag_set_repeated_parameter(param);
14828 pm_parameters_node_keyword_rest_set(params, param);
14830 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14831 pm_parameters_node_posts_append(params, param);
14838 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14843 if (params->
rest == NULL) {
14844 pm_parameters_node_rest_set(params, param);
14846 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14847 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14850 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14861 if (!parsing)
break;
14863 bool accepted_newline =
false;
14864 if (uses_parentheses) {
14871 if (accepted_newline) {
14872 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14880 pm_do_loop_stack_pop(parser);
14916 token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14918 const uint8_t *end = token->start;
14922 newline_index == 0 &&
14923 parser->
start[0] == 0xef &&
14924 parser->
start[1] == 0xbb &&
14925 parser->
start[2] == 0xbf
14928 int64_t column = 0;
14929 for (; cursor < end; cursor++) {
14932 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14939 if (break_on_non_space)
return -1;
14952 parser_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) {
14957 size_t closing_newline_index = token_newline_index(parser);
14958 if (opening_newline_index == closing_newline_index)
return;
14963 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14964 if (!if_after_else && (opening_column == -1))
return;
14971 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14972 if ((closing_column == -1) || (opening_column == closing_column))
return;
14976 if (allow_indent && (closing_column > opening_column))
return;
14979 PM_PARSER_WARN_FORMAT(
14981 closing_token->
start,
14982 closing_token->
end,
14983 PM_WARN_INDENTATION_MISMATCH,
14984 (
int) (closing_token->
end - closing_token->
start),
14985 (
const char *) closing_token->
start,
14986 (
int) (opening_token->
end - opening_token->
start),
14987 (
const char *) opening_token->
start,
14988 ((int32_t) opening_newline_index) + parser->
start_line
14993 PM_RESCUES_BEGIN = 1,
15000 } pm_rescues_type_t;
15011 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15012 parser_lex(parser);
15016 switch (parser->
current.type) {
15021 parser_lex(parser);
15022 pm_rescue_node_operator_set(rescue, &parser->
previous);
15024 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15025 reference = parse_target(parser, reference,
false,
false);
15027 pm_rescue_node_reference_set(rescue, reference);
15042 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15043 pm_rescue_node_exceptions_append(rescue, expression);
15052 pm_rescue_node_operator_set(rescue, &parser->
previous);
15054 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15055 reference = parse_target(parser, reference,
false,
false);
15057 pm_rescue_node_reference_set(rescue, reference);
15072 pm_accepts_block_stack_push(parser,
true);
15087 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15089 pm_accepts_block_stack_pop(parser);
15093 if (current == NULL) {
15094 pm_begin_node_rescue_clause_set(parent_node, rescue);
15096 pm_rescue_node_subsequent_set(current, rescue);
15105 if (current != NULL) {
15109 while (clause != NULL) {
15117 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15118 opening_newline_index = token_newline_index(parser);
15120 else_keyword = parser->
current;
15121 opening = &else_keyword;
15123 parser_lex(parser);
15128 pm_accepts_block_stack_push(parser,
true);
15142 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15143 pm_accepts_block_stack_pop(parser);
15148 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15149 pm_begin_node_else_clause_set(parent_node, else_clause);
15153 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15157 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15160 parser_lex(parser);
15165 pm_accepts_block_stack_push(parser,
true);
15179 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15180 pm_accepts_block_stack_pop(parser);
15185 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15186 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15190 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15191 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15194 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15204 pm_token_t begin_keyword = not_provided(parser);
15205 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15207 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15217 parse_block_parameters(
15219 bool allows_trailing_comma,
15221 bool is_lambda_literal,
15222 bool accepts_blocks_in_defaults,
15227 parameters = parse_parameters(
15229 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15231 allows_trailing_comma,
15233 accepts_blocks_in_defaults,
15234 (uint16_t) (depth + 1)
15244 switch (parser->
current.type) {
15246 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15247 parser_lex(parser);
15250 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15251 parser_lex(parser);
15254 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15255 parser_lex(parser);
15258 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15259 parser_lex(parser);
15266 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15267 pm_parser_local_add_token(parser, &parser->
previous, 1);
15270 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15272 pm_block_parameters_node_append_local(block_parameters, local);
15277 return block_parameters;
15285 outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15287 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15298 static const char *
const pm_numbered_parameter_names[] = {
15299 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15313 if (parameters != NULL) {
15315 if (implicit_parameters->
size > 0) {
15319 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15321 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15323 assert(
false &&
"unreachable");
15332 if (implicit_parameters->
size == 0) {
15339 uint8_t numbered_parameter = 0;
15340 bool it_parameter =
false;
15342 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15346 if (it_parameter) {
15347 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15348 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15349 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15351 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15353 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15355 assert(
false &&
"unreachable");
15358 if (numbered_parameter > 0) {
15359 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15361 it_parameter =
true;
15366 if (numbered_parameter > 0) {
15370 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15374 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15377 if (it_parameter) {
15378 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15388 parse_block(
pm_parser_t *parser, uint16_t depth) {
15392 pm_accepts_block_stack_push(parser,
true);
15393 pm_parser_scope_push(parser,
false);
15400 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15402 parser_lex(parser);
15404 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15407 expect1(parser,
PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15410 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15425 pm_accepts_block_stack_push(parser,
true);
15427 pm_accepts_block_stack_pop(parser);
15432 statements = (
pm_node_t *) parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1));
15440 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15443 pm_parser_scope_pop(parser);
15444 pm_accepts_block_stack_pop(parser);
15446 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15455 parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15456 bool found =
false;
15465 pm_accepts_block_stack_push(parser,
true);
15474 pm_accepts_block_stack_pop(parser);
15479 pm_accepts_block_stack_push(parser,
false);
15484 parse_arguments(parser, arguments, accepts_block,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
15493 pm_accepts_block_stack_pop(parser);
15499 if (accepts_block) {
15504 block = parse_block(parser, (uint16_t) (depth + 1));
15505 pm_arguments_validate_block(parser, arguments, block);
15508 block = parse_block(parser, (uint16_t) (depth + 1));
15511 if (block != NULL) {
15515 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15517 if (arguments->
block != NULL) {
15519 arguments->
arguments = pm_arguments_node_create(parser);
15521 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15537 bool in_sclass =
false;
15539 switch (context_node->
context) {
15584 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15606 assert(
false &&
"unreachable");
15611 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15622 switch (context_node->
context) {
15696 assert(
false &&
"unreachable");
15710 return previous_block_exits;
15728 default: assert(
false &&
"unreachable");
type =
"";
break;
15731 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15748 }
else if (previous_block_exits != NULL) {
15760 flush_block_exits(parser, previous_block_exits);
15768 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15774 predicate_closed =
true;
15778 if (!predicate_closed) {
15779 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15782 context_pop(parser);
15787 parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15789 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15792 pm_token_t then_keyword = not_provided(parser);
15794 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15798 pm_accepts_block_stack_push(parser,
true);
15799 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15800 pm_accepts_block_stack_pop(parser);
15804 pm_token_t end_keyword = not_provided(parser);
15809 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15812 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15815 assert(
false &&
"unreachable");
15825 if (parser_end_of_line_p(parser)) {
15826 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15829 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15831 parser_lex(parser);
15833 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15834 pm_accepts_block_stack_push(parser,
true);
15837 pm_accepts_block_stack_pop(parser);
15840 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15847 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15848 opening_newline_index = token_newline_index(parser);
15850 parser_lex(parser);
15853 pm_accepts_block_stack_push(parser,
true);
15855 pm_accepts_block_stack_pop(parser);
15858 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15861 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15871 assert(
false &&
"unreachable");
15875 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15883 bool recursing =
true;
15885 while (recursing) {
15890 recursing = current != NULL;
15908 assert(
false &&
"unreachable");
15912 pop_block_exits(parser, previous_block_exits);
15922 #define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15923 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15924 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15925 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15926 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15927 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15928 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15929 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15930 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15931 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15932 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15938 #define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15939 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15940 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15941 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15942 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15943 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15944 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15945 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15952 #define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15953 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15954 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15955 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15956 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15957 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15958 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15959 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15960 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15966 #define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15967 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15968 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15969 case PM_TOKEN_CLASS_VARIABLE
15975 #define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15976 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15977 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15978 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15989 parse_unescaped_encoding(
const pm_parser_t *parser) {
16011 parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16012 switch (parser->
current.type) {
16024 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16026 parser_lex(parser);
16044 lex_state_set(parser, PM_LEX_STATE_BEG);
16045 parser_lex(parser);
16051 pm_accepts_block_stack_push(parser,
true);
16053 pm_accepts_block_stack_pop(parser);
16057 lex_state_set(parser, state);
16065 if (statements != NULL && statements->
body.
size == 1) {
16069 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16083 lex_state_set(parser, PM_LEX_STATE_BEG);
16084 parser_lex(parser);
16089 switch (parser->
current.type) {
16093 parser_lex(parser);
16094 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16099 parser_lex(parser);
16100 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16105 parser_lex(parser);
16106 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16111 parser_lex(parser);
16112 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16117 parser_lex(parser);
16118 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16129 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16132 parser_lex(parser);
16133 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16143 static const uint8_t *
16144 parse_operator_symbol_name(
const pm_token_t *name) {
16145 switch (name->type) {
16148 if (name->end[-1] ==
'@')
return name->end - 1;
16160 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16162 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16163 parser_lex(parser);
16180 if (lex_mode->
mode != PM_LEX_STRING) {
16181 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16183 switch (parser->
current.type) {
16184 case PM_CASE_OPERATOR:
16185 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16194 case PM_CASE_KEYWORD:
16195 parser_lex(parser);
16206 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16211 if (lex_mode->
as.string.interpolation) {
16214 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16215 parser_lex(parser);
16219 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16223 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16228 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16235 if (part) pm_interpolated_symbol_node_append(symbol, part);
16238 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16239 pm_interpolated_symbol_node_append(symbol, part);
16243 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16245 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16250 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16260 parser_lex(parser);
16275 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16276 pm_interpolated_symbol_node_append(symbol, part);
16279 pm_interpolated_symbol_node_append(symbol, part);
16281 if (next_state != PM_LEX_STATE_NONE) {
16282 lex_state_set(parser, next_state);
16285 parser_lex(parser);
16288 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16296 if (next_state != PM_LEX_STATE_NONE) {
16297 lex_state_set(parser, next_state);
16301 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16306 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16314 parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16315 switch (parser->
current.type) {
16316 case PM_CASE_OPERATOR: {
16317 const pm_token_t opening = not_provided(parser);
16318 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16320 case PM_CASE_KEYWORD:
16324 parser_lex(parser);
16331 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16337 parser_lex(parser);
16339 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16342 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16354 parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16355 switch (parser->
current.type) {
16356 case PM_CASE_OPERATOR: {
16357 const pm_token_t opening = not_provided(parser);
16358 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16360 case PM_CASE_KEYWORD:
16364 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16365 parser_lex(parser);
16372 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16378 parser_lex(parser);
16380 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16383 parser_lex(parser);
16384 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16386 parser_lex(parser);
16387 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16389 parser_lex(parser);
16390 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16392 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16406 if ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1) {
16407 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16411 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16417 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16418 for (uint8_t number = 1; number <= maximum; number++) {
16419 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16426 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16449 pm_node_t *node = parse_variable(parser);
16450 if (node != NULL)
return node;
16455 pm_node_flag_set((
pm_node_t *)node, flags);
16466 parse_method_definition_name(
pm_parser_t *parser) {
16467 switch (parser->
current.type) {
16468 case PM_CASE_KEYWORD:
16471 parser_lex(parser);
16474 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16475 parser_lex(parser);
16477 case PM_CASE_OPERATOR:
16478 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16479 parser_lex(parser);
16488 parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16497 const uint8_t *source_cursor = (uint8_t *) string->
source;
16498 const uint8_t *source_end = source_cursor + dest_length;
16503 size_t trimmed_whitespace = 0;
16510 if (*source_cursor ==
'\t') {
16511 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16512 if (trimmed_whitespace > common_whitespace)
break;
16514 trimmed_whitespace++;
16521 memmove((uint8_t *) string->
source, source_cursor, (
size_t) (source_end - source_cursor));
16522 string->length = dest_length;
16532 bool dedent_next =
true;
16537 size_t write_index = 0;
16545 nodes->
nodes[write_index++] = node;
16546 dedent_next =
false;
16552 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16558 nodes->
nodes[write_index++] = node;
16562 dedent_next =
true;
16565 nodes->
size = write_index;
16572 parse_strings_empty_content(
const uint8_t *location) {
16582 bool concating =
false;
16590 assert(lex_mode->
mode == PM_LEX_STRING);
16591 bool lex_interpolation = lex_mode->
as.string.interpolation;
16592 bool label_allowed = lex_mode->
as.string.label_allowed && accepts_label;
16595 parser_lex(parser);
16617 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16618 }
else if (!lex_interpolation) {
16626 content = not_provided(parser);
16647 pm_token_t delimiters = not_provided(parser);
16648 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16652 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16654 parser_lex(parser);
16658 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16662 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16663 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16665 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16666 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16668 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16673 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16682 parser_lex(parser);
16685 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16686 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16694 if (location > parser->
start && location[-1] ==
'\n') location--;
16695 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16701 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16702 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16707 pm_token_t string_opening = not_provided(parser);
16708 pm_token_t string_closing = not_provided(parser);
16710 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16711 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16715 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16721 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16722 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16724 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16725 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16728 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16741 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16747 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16748 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16750 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16751 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16754 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16760 if (current == NULL) {
16776 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16786 pm_interpolated_string_node_append(container, current);
16797 #define PM_PARSE_PATTERN_SINGLE 0
16798 #define PM_PARSE_PATTERN_TOP 1
16799 #define PM_PARSE_PATTERN_MULTI 2
16812 if (*location->
start ==
'_')
return;
16815 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16831 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16850 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16857 parser_lex(parser);
16862 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16873 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16889 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16890 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16905 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16906 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16921 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16922 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16936 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16937 pm_array_pattern_node_requireds_append(pattern_node, inner);
16955 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16958 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16959 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16962 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16963 name = (
pm_node_t *) pm_local_variable_target_node_create(
16965 &PM_LOCATION_TOKEN_VALUE(&identifier),
16967 (uint32_t) (depth == -1 ? 0 : depth)
16972 return pm_splat_node_create(parser, &
operator, name);
16981 parser_lex(parser);
16987 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
16994 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16998 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16999 value = (
pm_node_t *) pm_local_variable_target_node_create(
17001 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17003 (uint32_t) (depth == -1 ? 0 : depth)
17007 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17015 pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17016 ptrdiff_t length = end - start;
17017 if (length == 0)
return false;
17020 size_t width = char_is_identifier_start(parser, start);
17021 if (width == 0)
return false;
17032 const uint8_t *cursor = start + width;
17033 while ((cursor < end) && (width = char_is_identifier(parser, cursor))) cursor += width;
17034 return cursor == end;
17048 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17049 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17051 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17053 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17054 PM_PARSER_ERR_LOCATION_FORMAT(parser, value_loc, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (value_loc->
end - value_loc->
start), (
const char *) value_loc->
start);
17059 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17062 parse_pattern_capture(parser, captures, constant_id, value_loc);
17067 (uint32_t) (depth == -1 ? 0 : depth)
17080 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17099 if (pm_symbol_node_label_p(first_node)) {
17100 parse_pattern_hash_key(parser, &keys, first_node);
17106 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17110 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17114 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17126 pm_parser_err_node(parser, first_node, diag_id);
17130 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17142 if (rest != NULL) {
17143 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17150 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17152 if (rest == NULL) {
17155 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17162 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17165 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17166 }
else if (!pm_symbol_node_label_p(key)) {
17167 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17170 expect1(parser,
PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17174 parse_pattern_hash_key(parser, &keys, key);
17178 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17180 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17184 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17186 if (rest != NULL) {
17187 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17206 switch (parser->
current.type) {
17209 parser_lex(parser);
17213 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17217 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17218 return (
pm_node_t *) pm_local_variable_target_node_create(
17220 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17222 (uint32_t) (depth == -1 ? 0 : depth)
17227 parser_lex(parser);
17232 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17237 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17250 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17251 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17264 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17265 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17277 pm_array_pattern_node_requireds_append(node, inner);
17286 parser_lex(parser);
17291 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17295 switch (parser->
current.type) {
17297 parser_lex(parser);
17298 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17301 first_node = parse_pattern_keyword_rest(parser, captures);
17304 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17308 parser_lex(parser);
17315 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17324 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17325 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17334 parser_lex(parser);
17338 switch (parser->
current.type) {
17339 case PM_CASE_PRIMITIVE: {
17340 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17341 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17344 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17345 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17346 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17350 case PM_CASE_PRIMITIVE: {
17351 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17354 if (pm_symbol_node_label_p(node))
return node;
17363 switch (parser->
current.type) {
17364 case PM_CASE_PRIMITIVE: {
17365 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17366 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17369 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17376 parser_lex(parser);
17381 switch (parser->
current.type) {
17383 parser_lex(parser);
17386 if (variable == NULL) {
17387 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17388 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17391 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17394 parser_lex(parser);
17397 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17400 parser_lex(parser);
17403 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17406 parser_lex(parser);
17409 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17412 parser_lex(parser);
17415 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17418 parser_lex(parser);
17421 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17428 parser_lex(parser);
17430 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17435 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17440 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17441 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17442 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17448 parser_lex(parser);
17453 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17457 parser_lex(parser);
17460 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17463 pm_parser_err_current(parser, diag_id);
17479 switch (parser->
current.type) {
17488 case PM_CASE_PRIMITIVE: {
17489 if (node == NULL) {
17490 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17492 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17493 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17501 parser_lex(parser);
17503 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17508 if (node == NULL) {
17511 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17517 pm_parser_err_current(parser, diag_id);
17520 if (node == NULL) {
17523 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17540 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17544 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17547 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17549 (uint32_t) (depth == -1 ? 0 : depth)
17552 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17565 bool leading_rest =
false;
17566 bool trailing_rest =
false;
17568 switch (parser->
current.type) {
17570 parser_lex(parser);
17572 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17574 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17575 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17581 node = parse_pattern_keyword_rest(parser, captures);
17582 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17584 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17585 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17593 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17595 if (pm_symbol_node_label_p(node)) {
17596 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17598 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17599 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17605 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17609 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17610 parser_lex(parser);
17611 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17612 leading_rest =
true;
17618 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17624 if (pm_symbol_node_label_p(node)) {
17625 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17628 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser,
PM_TOKEN_COMMA)) {
17641 trailing_rest =
true;
17646 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17651 if (trailing_rest) {
17652 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17655 trailing_rest =
true;
17657 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17668 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17670 if (nodes.
size == 2) {
17671 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17674 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17676 if (leading_rest && trailing_rest) {
17677 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17682 }
else if (leading_rest) {
17685 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17697 parse_negative_numeric(
pm_node_t *node) {
17722 assert(
false &&
"unreachable");
17735 case PM_ERR_HASH_KEY: {
17739 case PM_ERR_HASH_VALUE:
17740 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17744 case PM_ERR_UNARY_RECEIVER: {
17749 case PM_ERR_UNARY_DISALLOWED:
17750 case PM_ERR_EXPECT_ARGUMENT: {
17755 pm_parser_err_previous(parser, diag_id);
17765 #define CONTEXT_NONE 0
17766 #define CONTEXT_THROUGH_ENSURE 1
17767 #define CONTEXT_THROUGH_ELSE 2
17770 int context = CONTEXT_NONE;
17772 while (context_node != NULL) {
17773 switch (context_node->
context) {
17794 if (context == CONTEXT_NONE) {
17795 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17796 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17797 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17798 }
else if (context == CONTEXT_THROUGH_ELSE) {
17799 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17811 context = CONTEXT_THROUGH_ELSE;
17822 context = CONTEXT_THROUGH_ENSURE;
17826 assert(
false &&
"unreachable");
17856 context_node = context_node->
prev;
17859 #undef CONTEXT_NONE
17860 #undef CONTEXT_ENSURE
17861 #undef CONTEXT_ELSE
17871 while (context_node != NULL) {
17872 switch (context_node->
context) {
17897 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17901 assert(
false &&
"unreachable");
17942 context_node = context_node->
prev;
17974 parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17978 if (callback_data->
shared) {
17984 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
17997 .shared = unescaped->
type == PM_STRING_SHARED
18007 parse_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) {
18008 switch (parser->
current.type) {
18010 parser_lex(parser);
18013 pm_accepts_block_stack_push(parser,
true);
18014 bool parsed_bare_hash =
false;
18030 if (accepted_newline) {
18031 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18056 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18058 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18061 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18063 if (parsed_bare_hash) {
18064 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18067 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18071 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18075 parsed_bare_hash =
true;
18077 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18080 if (parsed_bare_hash) {
18081 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18086 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18092 operator = not_provided(parser);
18095 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18096 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18097 pm_keyword_hash_node_elements_append(hash, assoc);
18101 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18105 parsed_bare_hash =
true;
18109 pm_array_node_elements_append(array, element);
18121 pm_array_node_close_set(array, &parser->
previous);
18122 pm_accepts_block_stack_pop(parser);
18131 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18133 parser_lex(parser);
18141 pop_block_exits(parser, previous_block_exits);
18144 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous);
18149 pm_accepts_block_stack_push(parser,
true);
18151 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18152 context_pop(parser);
18158 if (terminator_found) {
18167 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18170 parser_lex(parser);
18171 pm_accepts_block_stack_pop(parser);
18173 pop_block_exits(parser, previous_block_exits);
18185 multi_target = pm_multi_target_node_create(parser);
18186 pm_multi_target_node_targets_append(parser, multi_target, statement);
18189 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18198 if (match1(parser,
PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18199 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18211 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18214 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18219 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18229 pm_statements_node_body_append(parser, statements, statement,
true);
18239 pm_statements_node_body_append(parser, statements, statement,
true);
18243 if (!terminator_found && !match1(parser,
PM_TOKEN_EOF)) {
18249 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18250 pm_statements_node_body_append(parser, statements, node,
true);
18279 context_pop(parser);
18280 pm_accepts_block_stack_pop(parser);
18292 pm_multi_target_node_targets_append(parser, multi_target, statement);
18294 statement = (
pm_node_t *) multi_target;
18306 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18310 pop_block_exits(parser, previous_block_exits);
18313 pm_void_statements_check(parser, statements,
true);
18327 pm_accepts_block_stack_push(parser,
true);
18328 parser_lex(parser);
18333 if (current_hash_keys != NULL) {
18334 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18337 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18344 pm_accepts_block_stack_pop(parser);
18346 pm_hash_node_closing_loc_set(node, &parser->
previous);
18351 parser_lex(parser);
18362 pm_node_t *node = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18363 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18368 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18374 parser_lex(parser);
18377 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18378 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18384 parser_lex(parser);
18396 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18397 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18402 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18405 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18411 parser_lex(parser);
18417 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18418 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18426 parser_lex(parser);
18428 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));
18435 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18438 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18441 parser_lex(parser);
18444 parser_lex(parser);
18445 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18447 parser_lex(parser);
18450 parser_lex(parser);
18451 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18453 parser_lex(parser);
18456 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18457 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18463 parser_lex(parser);
18466 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18467 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18473 parser_lex(parser);
18476 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18477 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18484 parser_lex(parser);
18486 pm_node_t *node = parse_variable_call(parser);
18496 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18506 if (arguments.
block != NULL) {
18528 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18529 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18535 parse_target_implicit_parameter(parser, node);
18543 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18544 parse_target_implicit_parameter(parser, node);
18547 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18556 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18557 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18568 size_t common_whitespace = (size_t) -1;
18571 parser_lex(parser);
18583 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18590 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18603 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18606 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18610 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18615 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18616 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18629 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18636 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18638 cast->
parts = parts;
18641 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18650 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18658 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18660 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18666 parse_heredoc_dedent(parser, nodes, common_whitespace);
18671 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18677 parser_lex(parser);
18680 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18681 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18688 parser_lex(parser);
18693 parser_lex(parser);
18694 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18698 parser_lex(parser);
18699 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18703 parser_lex(parser);
18704 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18707 parser_lex(parser);
18708 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18710 parser_lex(parser);
18713 parser_lex(parser);
18716 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18717 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18720 parser_lex(parser);
18723 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18724 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18732 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18735 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18738 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18743 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18748 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18752 size_t opening_newline_index = token_newline_index(parser);
18753 parser_lex(parser);
18759 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18766 }
else if (!token_begins_expression_p(parser->
current.type)) {
18769 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18774 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18775 parser_lex(parser);
18777 pop_block_exits(parser, previous_block_exits);
18780 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18781 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18786 pm_token_t end_keyword = not_provided(parser);
18790 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18797 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18798 parser_lex(parser);
18801 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18806 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18808 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18809 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18813 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18814 pm_when_node_conditions_append(when_node, condition);
18825 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18828 pm_when_clause_static_literals_add(parser, &literals, condition);
18834 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18838 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18843 if (statements != NULL) {
18844 pm_when_node_statements_set(when_node, statements);
18848 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18854 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18860 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18864 if (predicate == NULL) {
18865 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18872 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18877 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18879 parser_lex(parser);
18884 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));
18894 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18895 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
18898 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18899 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
18910 then_keyword = not_provided(parser);
18928 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
18929 pm_case_match_node_condition_append(case_node, condition);
18935 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18947 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18949 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18953 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18959 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18968 pop_block_exits(parser, previous_block_exits);
18974 size_t opening_newline_index = token_newline_index(parser);
18975 parser_lex(parser);
18981 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18985 pm_accepts_block_stack_push(parser,
true);
18986 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18987 pm_accepts_block_stack_pop(parser);
18991 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18992 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18996 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
18998 pop_block_exits(parser, previous_block_exits);
19005 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19007 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19008 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19011 parser_lex(parser);
19021 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19024 flush_block_exits(parser, previous_block_exits);
19027 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19032 parser_lex(parser);
19038 token_begins_expression_p(parser->
current.type) ||
19041 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19043 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19044 parse_arguments(parser, &arguments,
false,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
19048 switch (keyword.
type) {
19061 parse_return(parser, node);
19065 assert(
false &&
"unreachable");
19070 parser_lex(parser);
19074 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19081 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19084 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19087 parser_lex(parser);
19091 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19097 if (arguments.
block != NULL) {
19098 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19100 arguments.
block = NULL;
19109 size_t opening_newline_index = token_newline_index(parser);
19110 parser_lex(parser);
19113 pm_do_loop_stack_push(parser,
false);
19116 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19120 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));
19122 pm_parser_scope_push(parser,
true);
19129 pm_accepts_block_stack_push(parser,
true);
19131 pm_accepts_block_stack_pop(parser);
19136 statements = (
pm_node_t *) 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));
19138 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19146 pm_parser_scope_pop(parser);
19147 pm_do_loop_stack_pop(parser);
19149 flush_block_exits(parser, previous_block_exits);
19152 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19155 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19158 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19165 inheritance_operator = parser->
current;
19166 lex_state_set(parser, PM_LEX_STATE_BEG);
19169 parser_lex(parser);
19171 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19173 inheritance_operator = not_provided(parser);
19177 pm_parser_scope_push(parser,
true);
19187 pm_accepts_block_stack_push(parser,
true);
19189 pm_accepts_block_stack_pop(parser);
19194 statements = (
pm_node_t *) 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));
19196 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19201 if (context_def_p(parser)) {
19202 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19208 pm_parser_scope_pop(parser);
19209 pm_do_loop_stack_pop(parser);
19212 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19215 pop_block_exits(parser, previous_block_exits);
19218 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19222 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19225 size_t opening_newline_index = token_newline_index(parser);
19235 parser_lex(parser);
19239 bool valid_name =
true;
19241 switch (parser->
current.type) {
19242 case PM_CASE_OPERATOR:
19243 pm_parser_scope_push(parser,
true);
19244 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19245 parser_lex(parser);
19250 parser_lex(parser);
19253 receiver = parse_variable_call(parser);
19255 pm_parser_scope_push(parser,
true);
19256 lex_state_set(parser, PM_LEX_STATE_FNAME);
19257 parser_lex(parser);
19260 name = parse_method_definition_name(parser);
19263 pm_parser_scope_push(parser,
true);
19273 valid_name =
false;
19283 pm_parser_scope_push(parser,
true);
19284 parser_lex(parser);
19289 lex_state_set(parser, PM_LEX_STATE_FNAME);
19290 parser_lex(parser);
19293 switch (identifier.
type) {
19295 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19298 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19301 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19304 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19307 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19310 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19313 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19316 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19319 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19322 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19325 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19331 name = parse_method_definition_name(parser);
19346 context_pop(parser);
19347 parser_lex(parser);
19350 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19356 lex_state_set(parser, PM_LEX_STATE_FNAME);
19360 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
19364 pm_parser_scope_push(parser,
true);
19366 name = parse_method_definition_name(parser);
19370 pm_parser_scope_push(parser,
true);
19371 name = parse_method_definition_name(parser);
19379 switch (parser->
current.type) {
19381 parser_lex(parser);
19387 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true, (uint16_t) (depth + 1));
19390 lex_state_set(parser, PM_LEX_STATE_BEG);
19393 context_pop(parser);
19403 case PM_CASE_PARAMETER: {
19407 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19410 lparen = not_provided(parser);
19411 rparen = not_provided(parser);
19412 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true, (uint16_t) (depth + 1));
19414 context_pop(parser);
19418 lparen = not_provided(parser);
19419 rparen = not_provided(parser);
19422 context_pop(parser);
19432 if (token_is_setter_name(&name)) {
19433 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19438 pm_do_loop_stack_push(parser,
false);
19439 statements = (
pm_node_t *) pm_statements_node_create(parser);
19441 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, binding_power < PM_BINDING_POWER_COMPOSITION,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
19447 pm_node_t *value = parse_expression(parser, binding_power,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
19448 context_pop(parser);
19450 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19453 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19454 pm_do_loop_stack_pop(parser);
19455 context_pop(parser);
19456 end_keyword = not_provided(parser);
19458 equal = not_provided(parser);
19461 lex_state_set(parser, PM_LEX_STATE_BEG);
19468 pm_accepts_block_stack_push(parser,
true);
19469 pm_do_loop_stack_push(parser,
false);
19472 pm_accepts_block_stack_push(parser,
true);
19474 pm_accepts_block_stack_pop(parser);
19479 statements = (
pm_node_t *) 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));
19481 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19484 pm_accepts_block_stack_pop(parser);
19485 pm_do_loop_stack_pop(parser);
19493 pm_parser_scope_pop(parser);
19500 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
19502 flush_block_exits(parser, previous_block_exits);
19505 return (
pm_node_t *) pm_def_node_create(
19522 parser_lex(parser);
19532 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19535 rparen = not_provided(parser);
19542 lparen = not_provided(parser);
19543 rparen = not_provided(parser);
19544 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19547 context_pop(parser);
19548 return (
pm_node_t *) pm_defined_node_create(
19553 &PM_LOCATION_TOKEN_VALUE(&keyword)
19557 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19558 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19561 parser_lex(parser);
19564 if (context_def_p(parser)) {
19565 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19573 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19576 parser_lex(parser);
19579 size_t opening_newline_index = token_newline_index(parser);
19580 parser_lex(parser);
19592 if (token_begins_expression_p(parser->
current.type)) {
19593 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19596 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19597 }
else if (token_begins_expression_p(parser->
current.type)) {
19598 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19600 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19601 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19606 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19608 index = parse_target(parser, index,
false,
false);
19611 context_pop(parser);
19612 pm_do_loop_stack_push(parser,
true);
19617 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19618 pm_do_loop_stack_pop(parser);
19624 do_keyword = not_provided(parser);
19632 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19635 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19638 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19641 if (parser_end_of_line_p(parser)) {
19642 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19645 size_t opening_newline_index = token_newline_index(parser);
19647 parser_lex(parser);
19649 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19651 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19652 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19655 parser_lex(parser);
19657 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19662 pm_undef_node_append(undef, name);
19665 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19666 parser_lex(parser);
19667 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19674 pm_undef_node_append(undef, name);
19681 parser_lex(parser);
19695 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19704 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19707 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19710 size_t opening_newline_index = token_newline_index(parser);
19711 parser_lex(parser);
19713 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19717 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19719 size_t opening_newline_index = token_newline_index(parser);
19720 parser_lex(parser);
19723 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19729 pop_block_exits(parser, previous_block_exits);
19733 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19740 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19748 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19751 pm_parser_scope_push(parser,
true);
19756 pm_accepts_block_stack_push(parser,
true);
19758 pm_accepts_block_stack_pop(parser);
19763 statements = (
pm_node_t *) 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));
19765 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19771 pm_parser_scope_pop(parser);
19774 if (context_def_p(parser)) {
19775 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19778 pop_block_exits(parser, previous_block_exits);
19781 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19784 parser_lex(parser);
19787 parser_lex(parser);
19795 parser_lex(parser);
19798 parse_retry(parser, node);
19803 parser_lex(parser);
19806 parser_lex(parser);
19809 size_t opening_newline_index = token_newline_index(parser);
19812 pm_do_loop_stack_push(parser,
true);
19814 parser_lex(parser);
19816 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19818 pm_do_loop_stack_pop(parser);
19819 context_pop(parser);
19825 pm_accepts_block_stack_push(parser,
true);
19826 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19827 pm_accepts_block_stack_pop(parser);
19831 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19834 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &parser->
previous, predicate, statements, 0);
19837 size_t opening_newline_index = token_newline_index(parser);
19840 pm_do_loop_stack_push(parser,
true);
19842 parser_lex(parser);
19844 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19846 pm_do_loop_stack_pop(parser);
19847 context_pop(parser);
19853 pm_accepts_block_stack_push(parser,
true);
19854 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19855 pm_accepts_block_stack_pop(parser);
19859 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19862 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &parser->
previous, predicate, statements, 0);
19865 parser_lex(parser);
19876 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19884 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19889 pm_array_node_close_set(array, &closing);
19894 parser_lex(parser);
19903 switch (parser->
current.type) {
19905 if (current == NULL) {
19911 pm_array_node_elements_append(array, current);
19915 parser_lex(parser);
19922 if (current == NULL) {
19926 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
19927 parser_lex(parser);
19933 parser_lex(parser);
19945 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
19946 parser_lex(parser);
19949 pm_interpolated_symbol_node_append(interpolated, first_string);
19950 pm_interpolated_symbol_node_append(interpolated, second_string);
19955 assert(
false &&
"unreachable");
19961 bool start_location_set =
false;
19962 if (current == NULL) {
19968 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19978 pm_interpolated_symbol_node_append(interpolated, current);
19980 start_location_set =
true;
19987 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19989 if (!start_location_set) {
19995 bool start_location_set =
false;
19996 if (current == NULL) {
20002 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20013 pm_interpolated_symbol_node_append(interpolated, current);
20015 start_location_set =
true;
20021 assert(
false &&
"unreachable");
20024 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20026 if (!start_location_set) {
20033 parser_lex(parser);
20040 pm_array_node_elements_append(array, current);
20045 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20050 pm_array_node_close_set(array, &closing);
20055 parser_lex(parser);
20071 pm_array_node_elements_append(array,
string);
20079 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20085 pm_array_node_close_set(array, &closing);
20089 parser_lex(parser);
20098 switch (parser->
current.type) {
20104 if (current == NULL) {
20111 pm_array_node_elements_append(array, current);
20115 parser_lex(parser);
20123 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20124 parser_lex(parser);
20126 if (current == NULL) {
20143 pm_interpolated_string_node_append(interpolated, current);
20144 pm_interpolated_string_node_append(interpolated,
string);
20147 assert(
false &&
"unreachable");
20153 if (current == NULL) {
20160 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20169 pm_interpolated_string_node_append(interpolated, current);
20177 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20182 if (current == NULL) {
20189 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20198 pm_interpolated_string_node_append(interpolated, current);
20205 assert(
false &&
"unreachable");
20208 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20214 parser_lex(parser);
20221 pm_array_node_elements_append(array, current);
20226 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20232 pm_array_node_close_set(array, &closing);
20237 parser_lex(parser);
20249 parser_lex(parser);
20267 parser_lex(parser);
20280 parse_regular_expression_errors(parser, node);
20283 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20289 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20302 pm_interpolated_regular_expression_node_append(interpolated, part);
20307 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20314 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20315 pm_interpolated_regular_expression_node_append(interpolated, part);
20321 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20327 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20332 parser_lex(parser);
20349 parser_lex(parser);
20350 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20362 parser_lex(parser);
20365 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20366 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20367 parser_lex(parser);
20373 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20379 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20381 pm_interpolated_xstring_node_append(node, part);
20386 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20391 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20392 pm_interpolated_xstring_node_append(node, part);
20398 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20403 pm_interpolated_xstring_node_closing_set(node, &closing);
20408 parser_lex(parser);
20413 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20414 pm_parser_err_prefix(parser, diag_id);
20421 if (token_begins_expression_p(parser->
current.type)) {
20422 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20428 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20430 return parse_target_validate(parser, splat,
true);
20434 if (binding_power > PM_BINDING_POWER_UNARY) {
20435 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20438 parser_lex(parser);
20441 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));
20442 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20444 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20448 if (binding_power > PM_BINDING_POWER_UNARY) {
20449 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20451 parser_lex(parser);
20454 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20455 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20460 if (binding_power > PM_BINDING_POWER_UNARY) {
20461 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20463 parser_lex(parser);
20466 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20467 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20472 parser_lex(parser);
20475 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20479 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20480 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20481 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20488 parse_negative_numeric(node);
20491 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20502 size_t opening_newline_index = token_newline_index(parser);
20503 pm_accepts_block_stack_push(parser,
true);
20504 parser_lex(parser);
20507 pm_parser_scope_push(parser,
false);
20511 switch (parser->
current.type) {
20514 parser_lex(parser);
20517 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20519 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20525 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20528 case PM_CASE_PARAMETER: {
20529 pm_accepts_block_stack_push(parser,
false);
20531 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20532 pm_accepts_block_stack_pop(parser);
20536 block_parameters = NULL;
20552 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20559 pm_accepts_block_stack_push(parser,
true);
20561 pm_accepts_block_stack_pop(parser);
20566 body = (
pm_node_t *) parse_rescues_implicit_begin(parser, opening_newline_index, &
operator, opening.
start, (
pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1));
20568 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20575 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20578 pm_parser_scope_pop(parser);
20579 pm_accepts_block_stack_pop(parser);
20581 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20584 if (binding_power > PM_BINDING_POWER_UNARY) {
20585 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20587 parser_lex(parser);
20590 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20591 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20596 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20599 parser_lex(parser);
20601 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20612 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20613 pm_parser_err_prefix(parser, diag_id);
20619 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20620 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20626 pm_parser_err_prefix(parser, diag_id);
20644 parse_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) {
20645 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));
20653 parser_lex(parser);
20655 pm_node_t *right = parse_expression(parser, binding_power,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20656 context_pop(parser);
20658 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20678 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20683 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20691 parse_assignment_value_local(parser, statement);
20713 parse_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) {
20714 bool permitted =
true;
20715 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_USTAR)) permitted =
false;
20717 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_MATCH, diag_id, (uint16_t) (depth + 1));
20718 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20720 parse_assignment_value_local(parser, value);
20721 bool single_value =
true;
20724 single_value =
false;
20729 pm_array_node_elements_append(array, value);
20733 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20735 pm_array_node_elements_append(array, element);
20738 parse_assignment_value_local(parser, element);
20748 parser_lex(parser);
20750 bool accepts_command_call_inner =
false;
20757 accepts_command_call_inner =
true;
20761 pm_node_t *right = parse_expression(parser, binding_power, accepts_command_call_inner,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20762 context_pop(parser);
20764 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20780 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20785 if (call_node->
block != NULL) {
20786 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20788 call_node->
block = NULL;
20822 parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20837 if (!pm_slice_is_valid_local(parser, source, source + length))
return;
20839 if (callback_data->
shared) {
20843 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20849 void *memory =
xmalloc(length);
20850 if (memory == NULL) abort();
20852 memcpy(memory, source, length);
20853 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20862 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20865 if (pm_local_is_keyword((
const char *) source, length))
return;
20869 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20874 if (callback_data->
match == NULL) {
20875 callback_data->
match = pm_match_write_node_create(parser, call);
20880 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
20895 .shared = content->
type == PM_STRING_SHARED
20902 .shared = content->
type == PM_STRING_SHARED
20908 if (callback_data.
match != NULL) {
20916 parse_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) {
20919 switch (token.type) {
20933 case PM_CASE_WRITABLE: {
20934 parser_lex(parser);
20935 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));
20938 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20941 return parse_write(parser, node, &token, value);
20945 pm_multi_target_node_targets_append(parser, multi_target, node);
20947 parser_lex(parser);
20948 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));
20949 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
20960 parser_lex(parser);
20961 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));
20962 return parse_unwriteable_write(parser, node, &token, value);
20968 parser_lex(parser);
20969 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20977 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20980 parser_lex(parser);
20982 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));
20983 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
20989 parser_lex(parser);
20991 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));
20998 parser_lex(parser);
21000 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));
21003 return parse_shareable_constant_write(parser, write);
21006 parser_lex(parser);
21008 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));
21012 return parse_shareable_constant_write(parser, write);
21015 parser_lex(parser);
21017 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));
21025 parser_lex(parser);
21027 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));
21041 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21044 parser_lex(parser);
21046 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));
21047 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21055 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_AMPAMPEQ, (uint16_t) (depth + 1));
21062 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21066 if (pm_call_node_writable_p(parser, cast)) {
21067 parse_write_name(parser, &cast->
name);
21069 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21072 parse_call_operator_write(parser, cast, &token);
21073 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));
21074 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21077 parser_lex(parser);
21078 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21082 parser_lex(parser);
21087 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21095 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21098 parser_lex(parser);
21100 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));
21101 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21107 parser_lex(parser);
21109 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));
21116 parser_lex(parser);
21118 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));
21121 return parse_shareable_constant_write(parser, write);
21124 parser_lex(parser);
21126 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));
21130 return parse_shareable_constant_write(parser, write);
21133 parser_lex(parser);
21135 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));
21143 parser_lex(parser);
21145 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));
21159 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21162 parser_lex(parser);
21164 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));
21165 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21173 parser_lex(parser);
21179 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));
21180 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21184 if (pm_call_node_writable_p(parser, cast)) {
21185 parse_write_name(parser, &cast->
name);
21187 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21190 parse_call_operator_write(parser, cast, &token);
21191 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));
21192 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21195 parser_lex(parser);
21196 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21200 parser_lex(parser);
21205 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21223 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21226 parser_lex(parser);
21228 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));
21229 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21235 parser_lex(parser);
21237 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));
21244 parser_lex(parser);
21246 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));
21249 return parse_shareable_constant_write(parser, write);
21252 parser_lex(parser);
21254 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));
21258 return parse_shareable_constant_write(parser, write);
21261 parser_lex(parser);
21263 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));
21271 parser_lex(parser);
21273 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));
21274 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21280 parser_lex(parser);
21288 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21291 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));
21292 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21302 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));
21303 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21307 if (pm_call_node_writable_p(parser, cast)) {
21308 parse_write_name(parser, &cast->
name);
21310 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21313 parse_call_operator_write(parser, cast, &token);
21314 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));
21315 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21318 parser_lex(parser);
21319 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21323 parser_lex(parser);
21334 parser_lex(parser);
21337 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21341 parser_lex(parser);
21344 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21354 parser_lex(parser);
21355 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21358 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21371 bool interpolated =
false;
21372 size_t total_length = 0;
21379 interpolated =
true;
21384 if (!interpolated && total_length > 0) {
21385 void *memory =
xmalloc(total_length);
21386 if (!memory) abort();
21388 uint8_t *cursor = memory;
21433 parser_lex(parser);
21439 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21446 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21453 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21461 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21462 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21469 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21472 parser_lex(parser);
21473 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21474 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21478 parser_lex(parser);
21484 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21485 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21492 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21499 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21506 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21516 switch (parser->
current.type) {
21517 case PM_CASE_OPERATOR:
21518 case PM_CASE_KEYWORD:
21522 parser_lex(parser);
21532 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21533 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21536 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21541 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21548 parser_lex(parser);
21551 if (token_begins_expression_p(parser->
current.type)) {
21552 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21555 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21559 parser_lex(parser);
21561 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21562 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21566 parser_lex(parser);
21568 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21569 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21572 parser_lex(parser);
21574 pm_statements_node_body_append(parser, statements, node,
true);
21576 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21580 parser_lex(parser);
21582 pm_statements_node_body_append(parser, statements, node,
true);
21584 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21590 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21593 parser_lex(parser);
21595 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21607 context_pop(parser);
21608 pop_block_exits(parser, previous_block_exits);
21611 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21618 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21620 context_pop(parser);
21621 pop_block_exits(parser, previous_block_exits);
21624 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21627 parser_lex(parser);
21630 switch (parser->
current.type) {
21632 parser_lex(parser);
21648 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21649 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21652 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21656 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21657 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21662 case PM_CASE_OPERATOR:
21663 case PM_CASE_KEYWORD:
21666 parser_lex(parser);
21672 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21673 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21676 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21677 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21686 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21688 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
21692 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21698 parser_lex(parser);
21701 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21702 context_pop(parser);
21704 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
21707 parser_lex(parser);
21713 pm_accepts_block_stack_push(parser,
true);
21715 pm_accepts_block_stack_pop(parser);
21723 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21724 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21725 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21733 block = parse_block(parser, (uint16_t) (depth + 1));
21734 pm_arguments_validate_block(parser, &arguments, block);
21736 block = parse_block(parser, (uint16_t) (depth + 1));
21739 if (block != NULL) {
21740 if (arguments.
block != NULL) {
21741 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
21743 arguments.
arguments = pm_arguments_node_create(parser);
21745 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21751 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
21759 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21760 parser_lex(parser);
21763 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));
21768 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
21776 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21777 parser_lex(parser);
21780 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));
21785 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
21788 assert(
false &&
"unreachable");
21793 #undef PM_PARSE_PATTERN_SINGLE
21794 #undef PM_PARSE_PATTERN_TOP
21795 #undef PM_PARSE_PATTERN_MULTI
21819 parse_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) {
21821 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21825 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21840 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21850 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21858 if (pm_symbol_node_label_p(node)) {
21871 current_token_type = parser->
current.type,
21872 current_binding_powers = pm_binding_powers[current_token_type],
21873 binding_power <= current_binding_powers.
left &&
21874 current_binding_powers.
binary
21876 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21882 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21894 if (
PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21902 if (
PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21912 if (current_binding_powers.
nonassoc) {
21915 if (match1(parser, current_token_type)) {
21933 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21936 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21941 if (accepts_command_call) {
21950 switch (node->
type) {
21965 cast->
block == NULL &&
21978 accepts_command_call =
false;
21986 accepts_command_call =
false;
22001 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22003 pm_arguments_node_arguments_append(
22005 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22008 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22011 pm_parser_constant_id_constant(parser,
"print", 5)
22015 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22016 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22018 pm_arguments_node_arguments_append(
22020 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22023 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22024 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22028 pm_parser_constant_id_constant(parser,
"$F", 2),
22032 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22036 pm_arguments_node_arguments_append(
22038 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22041 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22043 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22045 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22047 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22050 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22055 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22057 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22061 statements = wrapped_statements;
22076 pm_parser_scope_push(parser,
true);
22080 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22082 parser_lex(parser);
22085 if (statements == NULL) {
22086 statements = pm_statements_node_create(parser);
22091 assert(statements->
body.
size > 0);
22092 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22097 pm_parser_scope_pop(parser);
22102 if (pm_statements_node_body_length(statements) == 0) {
22103 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22109 statements = wrap_statements(parser, statements);
22111 flush_block_exits(parser, previous_block_exits);
22115 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22131 static const char *
22132 pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22133 size_t little_length = strlen(little);
22135 for (
const char *big_end = big + big_length; big < big_end; big++) {
22136 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22143 #define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22151 pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22152 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22153 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22163 pm_parser_init_shebang(
pm_parser_t *parser,
const pm_options_t *options,
const char *engine,
size_t length) {
22164 const char *switches = pm_strnstr(engine,
" -", length);
22165 if (switches == NULL)
return;
22170 (
const uint8_t *) (switches + 1),
22171 length - ((
size_t) (switches - engine)) - 1,
22175 size_t encoding_length;
22178 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22190 assert(source != NULL);
22194 .lex_state = PM_LEX_STATE_BEG,
22195 .enclosure_nesting = 0,
22196 .lambda_enclosure_nesting = -1,
22197 .brace_nesting = 0,
22198 .do_loop_stack = 0,
22199 .accepts_block_stack = 0,
22202 .stack = {{ .mode = PM_LEX_DEFAULT }},
22206 .end = source + size,
22207 .previous = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22208 .current = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22209 .next_start = NULL,
22210 .heredoc_end = NULL,
22211 .data_loc = { .start = NULL, .end = NULL },
22212 .comment_list = { 0 },
22213 .magic_comment_list = { 0 },
22214 .warning_list = { 0 },
22215 .error_list = { 0 },
22216 .current_scope = NULL,
22217 .current_context = NULL,
22219 .encoding_changed_callback = NULL,
22220 .encoding_comment_start = source,
22221 .lex_callback = NULL,
22223 .constant_pool = { 0 },
22224 .newline_list = { 0 },
22228 .explicit_encoding = NULL,
22230 .parsing_eval =
false,
22231 .partial_script =
false,
22232 .command_start =
true,
22233 .recovering =
false,
22234 .encoding_locked =
false,
22235 .encoding_changed =
false,
22236 .pattern_matching_newlines =
false,
22237 .in_keyword_arg =
false,
22238 .current_block_exits = NULL,
22239 .semantic_token_seen =
false,
22241 .current_regular_expression_ascii_only =
false,
22242 .warn_mismatched_indentation =
true
22259 uint32_t constant_size = ((uint32_t) size) / 95;
22265 size_t newline_size = size / 22;
22269 if (options != NULL) {
22278 if (encoding_length > 0) {
22280 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22302 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22304 pm_parser_scope_push(parser, scope_index == 0);
22310 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22316 void *allocated =
xmalloc(length);
22317 if (allocated == NULL)
continue;
22319 memcpy(allocated, source, length);
22320 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22325 pm_accepts_block_stack_push(parser,
true);
22328 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22341 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22358 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22359 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22361 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22362 const char *engine;
22364 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22365 if (newline != NULL) {
22369 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22374 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22377 search_shebang =
false;
22379 search_shebang =
true;
22385 if (search_shebang) {
22388 bool found_shebang =
false;
22392 const uint8_t *cursor = parser->
start;
22396 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22398 while (newline != NULL) {
22401 cursor = newline + 1;
22402 newline = next_newline(cursor, parser->
end - cursor);
22404 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22405 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22406 const char *engine;
22407 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22408 found_shebang =
true;
22410 if (newline != NULL) {
22411 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22416 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22424 if (found_shebang) {
22428 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22452 pm_comment_list_free(
pm_list_t *list) {
22455 for (node = list->
head; node != NULL; node = next) {
22467 pm_magic_comment_list_free(
pm_list_t *list) {
22470 for (node = list->
head; node != NULL; node = next) {
22496 pm_parser_scope_pop(parser);
22500 lex_mode_pop(parser);
22509 return parse_program(parser);
22519 #define LINE_SIZE 4096
22520 char line[LINE_SIZE];
22522 while (memset(line,
'\n', LINE_SIZE), fgets(line, LINE_SIZE, stream) != NULL) {
22523 size_t length = LINE_SIZE;
22524 while (length > 0 && line[length - 1] ==
'\n') length--;
22526 if (length == LINE_SIZE) {
22545 if (strncmp(line,
"__END__", 7) == 0)
return false;
22548 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22551 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22570 pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22574 if (diagnostic->
diag_id == PM_ERR_HEREDOC_TERM) {
22592 bool eof = pm_parse_stream_read(buffer, stream, fgets);
22598 eof = pm_parse_stream_read(buffer, stream, fgets);
22629 #undef PM_CASE_KEYWORD
22630 #undef PM_CASE_OPERATOR
22631 #undef PM_CASE_WRITABLE
22632 #undef PM_STRING_EMPTY
22633 #undef PM_LOCATION_NODE_BASE_VALUE
22634 #undef PM_LOCATION_NODE_VALUE
22635 #undef PM_LOCATION_NULL_VALUE
22636 #undef PM_LOCATION_TOKEN_VALUE
22641 #ifndef PRISM_EXCLUDE_SERIALIZATION
22657 pm_serialize_header(buffer);
22676 pm_serialize_header(buffer);
22697 pm_serialize_header(buffer);
22719 pm_serialize_header(buffer);
22738 PM_SLICE_TYPE_ERROR = -1,
22741 PM_SLICE_TYPE_NONE,
22744 PM_SLICE_TYPE_LOCAL,
22747 PM_SLICE_TYPE_CONSTANT,
22750 PM_SLICE_TYPE_METHOD_NAME
22757 pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22759 const pm_encoding_t *encoding =
pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22760 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22763 if (length == 0)
return PM_SLICE_TYPE_NONE;
22766 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22768 }
else if (*source ==
'_') {
22771 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22775 return PM_SLICE_TYPE_NONE;
22779 const uint8_t *end = source + length;
22780 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22786 while (source < end) {
22787 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22790 }
else if (*source ==
'_') {
22793 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22803 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22805 result = PM_SLICE_TYPE_METHOD_NAME;
22809 return source == end ? result : PM_SLICE_TYPE_NONE;
22817 switch (pm_slice_type(source, length, encoding_name)) {
22818 case PM_SLICE_TYPE_ERROR:
22820 case PM_SLICE_TYPE_NONE:
22821 case PM_SLICE_TYPE_CONSTANT:
22822 case PM_SLICE_TYPE_METHOD_NAME:
22824 case PM_SLICE_TYPE_LOCAL:
22828 assert(
false &&
"unreachable");
22837 switch (pm_slice_type(source, length, encoding_name)) {
22838 case PM_SLICE_TYPE_ERROR:
22840 case PM_SLICE_TYPE_NONE:
22841 case PM_SLICE_TYPE_LOCAL:
22842 case PM_SLICE_TYPE_METHOD_NAME:
22844 case PM_SLICE_TYPE_CONSTANT:
22848 assert(
false &&
"unreachable");
22857 #define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22858 #define C1(c) (*source == c)
22859 #define C2(s) (memcmp(source, s, 2) == 0)
22860 #define C3(s) (memcmp(source, s, 3) == 0)
22862 switch (pm_slice_type(source, length, encoding_name)) {
22863 case PM_SLICE_TYPE_ERROR:
22865 case PM_SLICE_TYPE_NONE:
22867 case PM_SLICE_TYPE_LOCAL:
22870 case PM_SLICE_TYPE_CONSTANT:
22872 case PM_SLICE_TYPE_METHOD_NAME:
22879 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22881 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22883 return B(C3(
"===") || C3(
"<=>") || C3(
"[]="));
@ PM_RANGE_FLAGS_EXCLUDE_END
...
@ PM_DEFINED_NODE
DefinedNode.
@ PM_PRE_EXECUTION_NODE
PreExecutionNode.
@ PM_RETRY_NODE
RetryNode.
@ PM_CONSTANT_PATH_WRITE_NODE
ConstantPathWriteNode.
@ PM_SOURCE_LINE_NODE
SourceLineNode.
@ PM_UNLESS_NODE
UnlessNode.
@ PM_GLOBAL_VARIABLE_READ_NODE
GlobalVariableReadNode.
@ PM_RATIONAL_NODE
RationalNode.
@ PM_FIND_PATTERN_NODE
FindPatternNode.
@ PM_ARRAY_NODE
ArrayNode.
@ PM_CONSTANT_PATH_TARGET_NODE
ConstantPathTargetNode.
@ PM_MULTI_WRITE_NODE
MultiWriteNode.
@ PM_INTERPOLATED_STRING_NODE
InterpolatedStringNode.
@ PM_FALSE_NODE
FalseNode.
@ PM_MATCH_PREDICATE_NODE
MatchPredicateNode.
@ PM_X_STRING_NODE
XStringNode.
@ PM_GLOBAL_VARIABLE_TARGET_NODE
GlobalVariableTargetNode.
@ PM_CONSTANT_TARGET_NODE
ConstantTargetNode.
@ PM_IT_LOCAL_VARIABLE_READ_NODE
ItLocalVariableReadNode.
@ PM_SOURCE_FILE_NODE
SourceFileNode.
@ PM_NO_KEYWORDS_PARAMETER_NODE
NoKeywordsParameterNode.
@ PM_MULTI_TARGET_NODE
MultiTargetNode.
@ PM_SPLAT_NODE
SplatNode.
@ PM_CLASS_VARIABLE_READ_NODE
ClassVariableReadNode.
@ PM_INTERPOLATED_MATCH_LAST_LINE_NODE
InterpolatedMatchLastLineNode.
@ PM_SYMBOL_NODE
SymbolNode.
@ PM_RESCUE_MODIFIER_NODE
RescueModifierNode.
@ PM_ALIAS_METHOD_NODE
AliasMethodNode.
@ PM_MATCH_REQUIRED_NODE
MatchRequiredNode.
@ PM_BACK_REFERENCE_READ_NODE
BackReferenceReadNode.
@ PM_BLOCK_ARGUMENT_NODE
BlockArgumentNode.
@ PM_MISSING_NODE
MissingNode.
@ PM_ASSOC_SPLAT_NODE
AssocSplatNode.
@ PM_RANGE_NODE
RangeNode.
@ PM_LOCAL_VARIABLE_READ_NODE
LocalVariableReadNode.
@ PM_REGULAR_EXPRESSION_NODE
RegularExpressionNode.
@ PM_CONSTANT_WRITE_NODE
ConstantWriteNode.
@ PM_HASH_PATTERN_NODE
HashPatternNode.
@ PM_UNDEF_NODE
UndefNode.
@ PM_ENSURE_NODE
EnsureNode.
@ PM_LOCAL_VARIABLE_WRITE_NODE
LocalVariableWriteNode.
@ PM_KEYWORD_HASH_NODE
KeywordHashNode.
@ PM_PARENTHESES_NODE
ParenthesesNode.
@ PM_CLASS_VARIABLE_WRITE_NODE
ClassVariableWriteNode.
@ PM_POST_EXECUTION_NODE
PostExecutionNode.
@ PM_RETURN_NODE
ReturnNode.
@ PM_ARRAY_PATTERN_NODE
ArrayPatternNode.
@ PM_MATCH_LAST_LINE_NODE
MatchLastLineNode.
@ PM_CONSTANT_PATH_NODE
ConstantPathNode.
@ PM_INTERPOLATED_SYMBOL_NODE
InterpolatedSymbolNode.
@ PM_CLASS_VARIABLE_TARGET_NODE
ClassVariableTargetNode.
@ PM_BREAK_NODE
BreakNode.
@ PM_IMAGINARY_NODE
ImaginaryNode.
@ PM_CONSTANT_READ_NODE
ConstantReadNode.
@ PM_GLOBAL_VARIABLE_WRITE_NODE
GlobalVariableWriteNode.
@ PM_SOURCE_ENCODING_NODE
SourceEncodingNode.
@ PM_BEGIN_NODE
BeginNode.
@ PM_INSTANCE_VARIABLE_READ_NODE
InstanceVariableReadNode.
@ PM_FLIP_FLOP_NODE
FlipFlopNode.
@ PM_INSTANCE_VARIABLE_WRITE_NODE
InstanceVariableWriteNode.
@ PM_INSTANCE_VARIABLE_TARGET_NODE
InstanceVariableTargetNode.
@ PM_FLOAT_NODE
FloatNode.
@ PM_ASSOC_NODE
AssocNode.
@ PM_INTEGER_NODE
IntegerNode.
@ PM_LOCAL_VARIABLE_TARGET_NODE
LocalVariableTargetNode.
@ PM_STRING_NODE
StringNode.
@ PM_ALIAS_GLOBAL_VARIABLE_NODE
AliasGlobalVariableNode.
@ PM_NUMBERED_REFERENCE_READ_NODE
NumberedReferenceReadNode.
@ PM_STATEMENTS_NODE
StatementsNode.
@ PM_BLOCK_NODE
BlockNode.
@ PM_INTERPOLATED_REGULAR_EXPRESSION_NODE
InterpolatedRegularExpressionNode.
static const pm_node_flags_t PM_NODE_FLAG_NEWLINE
We store the flags enum in every node in the tree.
@ PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING
internal bytes forced the encoding to US-ASCII
@ PM_STRING_FLAGS_FROZEN
frozen by virtue of a frozen_string_literal: true comment or --enable-frozen-string-literal
@ PM_STRING_FLAGS_FORCED_BINARY_ENCODING
internal bytes forced the encoding to binary
@ PM_STRING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING
if the arguments contain forwarding
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS
if the arguments contain keywords
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT
if the arguments contain a keyword splat
#define PM_NODE_FLAG_P(node, flag)
Return true if the given flag is set on the given node.
#define PM_NODE_TYPE_P(node, type)
Return true if the type of the given node matches the given type.
#define PM_NODE_TYPE(node)
Cast the type to an enum to allow the compiler to provide exhaustiveness checking.
@ PM_INTEGER_BASE_FLAGS_HEXADECIMAL
0x prefix
@ PM_INTEGER_BASE_FLAGS_OCTAL
0o or 0 prefix
@ PM_INTEGER_BASE_FLAGS_DECIMAL
0d or no prefix
@ PM_INTEGER_BASE_FLAGS_BINARY
0b prefix
enum pm_token_type pm_token_type_t
This enum represents every type of token in the Ruby source.
#define PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
When we're serializing to Java, we want to skip serializing the location fields as they won't be used...
@ PM_CALL_NODE_FLAGS_SAFE_NAVIGATION
&.
@ PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE
a call that is an attribute write, so the value being written should be returned
@ PM_CALL_NODE_FLAGS_VARIABLE_CALL
a call that could have been a local variable
@ PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING
internal bytes forced the encoding to US-ASCII
@ PM_REGULAR_EXPRESSION_FLAGS_EXTENDED
x - ignores whitespace and allows comments in regular expressions
uint16_t pm_node_flags_t
These are the flags embedded in the node struct.
@ PM_TOKEN_DOT_DOT_DOT
the ...
@ PM_TOKEN_IGNORED_NEWLINE
an ignored newline
@ PM_TOKEN_KEYWORD___FILE__
FILE
@ PM_TOKEN_KEYWORD_WHEN
when
@ PM_TOKEN_FLOAT
a floating point number
@ PM_TOKEN_UDOT_DOT
unary .
@ PM_TOKEN_AMPERSAND_DOT
&.
@ PM_TOKEN_NEWLINE
a newline character outside of other tokens
@ PM_TOKEN_NUMBERED_REFERENCE
a numbered reference to a capture group in the previous regular expression match
@ PM_TOKEN_KEYWORD_YIELD
yield
@ PM_TOKEN_KEYWORD_END
end
@ PM_TOKEN_KEYWORD_UNTIL_MODIFIER
until in the modifier form
@ PM_TOKEN_EQUAL_EQUAL_EQUAL
===
@ PM_TOKEN_INTEGER_RATIONAL
an integer with a rational suffix
@ PM_TOKEN_KEYWORD___ENCODING__
ENCODING
@ PM_TOKEN_REGEXP_END
the end of a regular expression
@ PM_TOKEN_KEYWORD_UNTIL
until
@ PM_TOKEN_MAXIMUM
The maximum token value.
@ PM_TOKEN_INTEGER
an integer (any base)
@ PM_TOKEN_UMINUS_NUM
-@ for a number
@ PM_TOKEN_KEYWORD_UNLESS_MODIFIER
unless in the modifier form
@ PM_TOKEN_INTEGER_RATIONAL_IMAGINARY
an integer with a rational and imaginary suffix
@ PM_TOKEN_FLOAT_RATIONAL_IMAGINARY
a floating pointer number with a rational and imaginary suffix
@ PM_TOKEN_BRACKET_LEFT_RIGHT
[]
@ PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL
&&=
@ PM_TOKEN_KEYWORD_CLASS
class
@ PM_TOKEN_KEYWORD_BEGIN
begin
@ PM_TOKEN_NOT_PROVIDED
a token that was not present but it is okay
@ PM_TOKEN_USTAR_STAR
unary **
@ PM_TOKEN_GREATER_GREATER_EQUAL
>>=
@ PM_TOKEN_PERCENT_EQUAL
%=
@ PM_TOKEN_KEYWORD_NOT
not
@ PM_TOKEN_BRACKET_LEFT_ARRAY
[ for the beginning of an array
@ PM_TOKEN_HEREDOC_END
the end of a heredoc
@ PM_TOKEN_HEREDOC_START
the start of a heredoc
@ PM_TOKEN_KEYWORD_DEFINED
defined?
@ PM_TOKEN_UCOLON_COLON
unary ::
@ PM_TOKEN_LABEL_END
the end of a label
@ PM_TOKEN_EQUAL_GREATER
=>
@ PM_TOKEN_KEYWORD_UNLESS
unless
@ PM_TOKEN_KEYWORD_ENSURE
ensure
@ PM_TOKEN_AMPERSAND_EQUAL
&=
@ PM_TOKEN_FLOAT_IMAGINARY
a floating pointer number with an imaginary suffix
@ PM_TOKEN_KEYWORD_BEGIN_UPCASE
BEGIN.
@ PM_TOKEN_LESS_EQUAL_GREATER
<=>
@ PM_TOKEN_KEYWORD_RESCUE_MODIFIER
rescue in the modifier form
@ PM_TOKEN_MISSING
a token that was expected but not found
@ PM_TOKEN_MINUS_GREATER
->
@ PM_TOKEN_KEYWORD_FALSE
false
@ PM_TOKEN_PIPE_PIPE_EQUAL
||=
@ PM_TOKEN_EMBEXPR_BEGIN
#{
@ PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES
( for a parentheses node
@ PM_TOKEN_EMBDOC_END
=end
@ PM_TOKEN_KEYWORD_ELSE
else
@ PM_TOKEN_BACK_REFERENCE
a back reference
@ PM_TOKEN_EOF
final token in the file
@ PM_TOKEN_KEYWORD_NIL
nil
@ PM_TOKEN_PERCENT_UPPER_W
W
@ PM_TOKEN_KEYWORD_RETURN
return
@ PM_TOKEN_CLASS_VARIABLE
a class variable
@ PM_TOKEN_PARENTHESIS_LEFT
(
@ PM_TOKEN_PARENTHESIS_RIGHT
)
@ PM_TOKEN_KEYWORD_RESCUE
rescue
@ PM_TOKEN_INSTANCE_VARIABLE
an instance variable
@ PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL
[]=
@ PM_TOKEN_UAMPERSAND
unary &
@ PM_TOKEN_CONSTANT
a constant
@ PM_TOKEN_IDENTIFIER
an identifier
@ PM_TOKEN_EMBDOC_BEGIN
=begin
@ PM_TOKEN_KEYWORD_AND
and
@ PM_TOKEN_KEYWORD_BREAK
break
@ PM_TOKEN_PERCENT_LOWER_W
w
@ PM_TOKEN_SYMBOL_BEGIN
the beginning of a symbol
@ PM_TOKEN_METHOD_NAME
a method name
@ PM_TOKEN_KEYWORD_CASE
case
@ PM_TOKEN_WORDS_SEP
a separator between words in a list
@ PM_TOKEN_FLOAT_RATIONAL
a floating pointer number with a rational suffix
@ PM_TOKEN_LESS_LESS_EQUAL
<<=
@ PM_TOKEN_EMBDOC_LINE
a line inside of embedded documentation
@ PM_TOKEN_KEYWORD_SUPER
super
@ PM_TOKEN_KEYWORD_REDO
redo
@ PM_TOKEN_KEYWORD_END_UPCASE
END.
@ PM_TOKEN_KEYWORD___LINE__
LINE
@ PM_TOKEN_STRING_END
the end of a string
@ PM_TOKEN_STRING_CONTENT
the contents of a string
@ PM_TOKEN_GREATER_GREATER
@ PM_TOKEN_PERCENT_LOWER_X
x
@ PM_TOKEN_KEYWORD_SELF
self
@ PM_TOKEN_PERCENT_LOWER_I
i
@ PM_TOKEN_KEYWORD_ALIAS
alias
@ PM_TOKEN_GLOBAL_VARIABLE
a global variable
@ PM_TOKEN_KEYWORD_IF_MODIFIER
if in the modifier form
@ PM_TOKEN_KEYWORD_RETRY
retry
@ PM_TOKEN_KEYWORD_UNDEF
undef
@ PM_TOKEN_BRACKET_RIGHT
]
@ PM_TOKEN_KEYWORD_FOR
for
@ PM_TOKEN_KEYWORD_THEN
then
@ PM_TOKEN_QUESTION_MARK
?
@ PM_TOKEN___END__
marker for the point in the file at which the parser should stop
@ PM_TOKEN_KEYWORD_WHILE
while
@ PM_TOKEN_KEYWORD_DEF
def
@ PM_TOKEN_UDOT_DOT_DOT
unary ...
@ PM_TOKEN_KEYWORD_WHILE_MODIFIER
while in the modifier form
@ PM_TOKEN_KEYWORD_TRUE
true
@ PM_TOKEN_REGEXP_BEGIN
the beginning of a regular expression
@ PM_TOKEN_PERCENT_UPPER_I
I
@ PM_TOKEN_KEYWORD_DO_LOOP
do keyword for a predicate in a while, until, or for loop
@ PM_TOKEN_KEYWORD_MODULE
module
@ PM_TOKEN_KEYWORD_NEXT
next
@ PM_TOKEN_INTEGER_IMAGINARY
an integer with an imaginary suffix
@ PM_TOKEN_STAR_STAR_EQUAL
**=
@ PM_TOKEN_CHARACTER_LITERAL
a character literal
@ PM_TOKEN_AMPERSAND_AMPERSAND
&&
@ PM_TOKEN_GREATER_EQUAL
>=
@ PM_TOKEN_COMMENT
a comment
@ PM_TOKEN_KEYWORD_ELSIF
elsif
@ PM_TOKEN_STRING_BEGIN
the beginning of a string
@ PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
@ PM_LOOP_FLAGS_BEGIN_MODIFIER
a loop after a begin statement, so the body is executed first before the condition
void pm_diagnostic_list_free(pm_list_t *list)
Deallocate the internal state of the given diagnostic list.
bool pm_diagnostic_list_append_format(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id,...)
Append a diagnostic to the given list of diagnostics that is using a format string for its message.
pm_diagnostic_id_t
The diagnostic IDs of all of the diagnostics, used to communicate the types of errors between the par...
bool pm_diagnostic_list_append(pm_list_t *list, const uint8_t *start, const uint8_t *end, pm_diagnostic_id_t diag_id)
Append a diagnostic to the given list of diagnostics that is using shared memory for its message.
#define xfree
Old name of ruby_xfree.
#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.
void pm_options_read(pm_options_t *options, const char *data)
Deserialize an options struct from the given binary string.
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.
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.
#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.
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.
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_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_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_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.
bool pm_buffer_init_capacity(pm_buffer_t *buffer, size_t capacity)
Initialize a pm_buffer_t with the given capacity.
void pm_buffer_append_format(pm_buffer_t *buffer, const char *format,...) PRISM_ATTRIBUTE_FORMAT(2
Append a formatted string to the buffer.
void void pm_buffer_append_string(pm_buffer_t *buffer, const char *value, size_t length)
Append a string to the buffer.
PRISM_EXPORTED_FUNCTION size_t pm_buffer_length(const pm_buffer_t *buffer)
Return the length of the buffer.
void pm_buffer_append_byte(pm_buffer_t *buffer, uint8_t value)
Append a single byte to the buffer.
PRISM_EXPORTED_FUNCTION bool pm_buffer_init(pm_buffer_t *buffer)
Initialize a pm_buffer_t with its default values.
void pm_buffer_append_varsint(pm_buffer_t *buffer, int32_t value)
Append a 32-bit signed integer to the buffer as a variable-length integer.
PRISM_EXPORTED_FUNCTION char * pm_buffer_value(const pm_buffer_t *buffer)
Return the value of the buffer.
PRISM_EXPORTED_FUNCTION void pm_buffer_free(pm_buffer_t *buffer)
Free the memory associated with the buffer.
void pm_buffer_append_bytes(pm_buffer_t *buffer, const uint8_t *value, size_t length)
Append a list of bytes to the buffer.
size_t pm_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length)
Returns the number of characters at the start of the string that are hexadecimal digits.
bool pm_char_is_decimal_digit(const uint8_t b)
Returns true if the given character is a decimal digit.
size_t pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length)
Returns the number of characters at the start of the string that are whitespace.
size_t pm_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid)
Returns the number of characters at the start of the string that are hexadecimal digits or underscore...
size_t pm_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid)
Returns the number of characters at the start of the string that are decimal digits or underscores.
size_t pm_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length)
Returns the number of characters at the start of the string that are decimal digits.
size_t pm_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid)
Returns the number of characters at the start of the string that are binary digits or underscores.
size_t pm_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid)
Returns the number of characters at the start of the string that are octal digits or underscores.
size_t pm_strspn_whitespace_newlines(const uint8_t *string, ptrdiff_t length, pm_newline_list_t *newline_list)
Returns the number of characters at the start of the string that are whitespace while also tracking t...
bool pm_char_is_hexadecimal_digit(const uint8_t b)
Returns true if the given character is a hexadecimal digit.
bool pm_char_is_octal_digit(const uint8_t b)
Returns true if the given character is an octal digit.
bool pm_char_is_binary_digit(const uint8_t b)
Returns true if the given character is a binary digit.
bool pm_char_is_inline_whitespace(const uint8_t b)
Returns true if the given character is an inline whitespace character.
size_t pm_strspn_inline_whitespace(const uint8_t *string, ptrdiff_t length)
Returns the number of characters at the start of the string that are inline whitespace.
bool pm_char_is_whitespace(const uint8_t b)
Returns true if the given character is a whitespace character.
size_t pm_strspn_regexp_option(const uint8_t *string, ptrdiff_t length)
Returns the number of characters at the start of the string that are regexp options.
#define PM_CONSTANT_ID_UNSET
When we allocate constants into the pool, we reserve 0 to mean that the slot is not yet filled.
bool pm_constant_pool_init(pm_constant_pool_t *pool, uint32_t capacity)
Initialize a new constant pool with a given capacity.
pm_constant_id_t pm_constant_pool_insert_shared(pm_constant_pool_t *pool, const uint8_t *start, size_t length)
Insert a constant into a constant pool that is a slice of a source string.
void pm_constant_id_list_free(pm_constant_id_list_t *list)
Free the memory associated with a list of constant ids.
pm_constant_id_t pm_constant_pool_insert_constant(pm_constant_pool_t *pool, const uint8_t *start, size_t length)
Insert a constant into a constant pool from memory that is constant.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
void pm_constant_id_list_insert(pm_constant_id_list_t *list, size_t index, pm_constant_id_t id)
Insert a constant id into a list of constant ids at the specified index.
bool pm_constant_id_list_append(pm_constant_id_list_t *list, pm_constant_id_t id)
Append a constant id to a list of constant ids.
pm_constant_id_t pm_constant_pool_insert_owned(pm_constant_pool_t *pool, uint8_t *start, size_t length)
Insert a constant into a constant pool from memory that is now owned by the constant pool.
void pm_constant_id_list_init_capacity(pm_constant_id_list_t *list, size_t capacity)
Initialize a list of constant ids with a given capacity.
pm_constant_t * pm_constant_pool_id_to_constant(const pm_constant_pool_t *pool, pm_constant_id_t constant_id)
Return a pointer to the constant indicated by the given constant id.
bool pm_constant_id_list_includes(pm_constant_id_list_t *list, pm_constant_id_t id)
Checks if the current constant id list includes the given constant id.
void pm_constant_pool_free(pm_constant_pool_t *pool)
Free the memory associated with a constant pool.
void pm_list_append(pm_list_t *list, pm_list_node_t *node)
Append a node to the given list.
void * pm_memchr(const void *source, int character, size_t number, bool encoding_changed, const pm_encoding_t *encoding)
We need to roll our own memchr to handle cases where the encoding changes and we need to search for a...
pm_line_column_t pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line)
Returns the line and column of the given offset.
void pm_newline_list_free(pm_newline_list_t *list)
Free the internal memory allocated for the newline list.
int32_t pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line)
Returns the line of the given offset.
bool pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity)
Initialize a new newline list with the given capacity.
bool pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor)
Append a new offset to the newline list.
void pm_newline_list_clear(pm_newline_list_t *list)
Clear out the newlines that have been appended to the list.
PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string)
Returns the length associated with the string.
void pm_string_ensure_owned(pm_string_t *string)
Ensure the string is owned.
void pm_string_owned_init(pm_string_t *string, uint8_t *source, size_t length)
Initialize an owned string that is responsible for freeing allocated memory.
void pm_string_shared_init(pm_string_t *string, const uint8_t *start, const uint8_t *end)
Initialize a shared string that is based on initial input.
#define PM_STRING_EMPTY
Defines an empty string.
PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string)
Free the associated memory of the given string.
PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string)
Returns the start pointer associated with the string.
int pm_strncasecmp(const uint8_t *string1, const uint8_t *string2, size_t length)
Compare two strings, ignoring case, up to the given length.
const uint8_t * pm_strpbrk(pm_parser_t *parser, const uint8_t *source, const uint8_t *charset, ptrdiff_t length, bool validate)
Here we have rolled our own version of strpbrk.
#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.
bool pm_encoding_utf_8_isupper_char(const uint8_t *b, ptrdiff_t n)
Return true if the next character in the UTF-8 encoding if it is an uppercase character.
#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...
const uint8_t pm_encoding_unicode_table[256]
This lookup table is referenced in both the UTF-8 encoding file and the parser directly in order to s...
const pm_encoding_t * pm_encoding_find(const uint8_t *start, const uint8_t *end)
Parse the given name of an encoding and return a pointer to the corresponding encoding struct if one ...
size_t pm_encoding_utf_8_char_width(const uint8_t *b, ptrdiff_t n)
Return the size of the next character in the UTF-8 encoding.
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
PRISM_EXPORTED_FUNCTION void pm_node_destroy(pm_parser_t *parser, struct pm_node *node)
Deallocate a node and all of its children.
#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.
void pm_node_list_free(pm_node_list_t *list)
Free the internal memory associated with the given node list.
void pm_node_list_concat(pm_node_list_t *list, pm_node_list_t *other)
Concatenate the given node list onto the end of the other node list.
void pm_node_list_append(pm_node_list_t *list, pm_node_t *node)
Append a new node onto the end of the node list.
#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.
The main header file for the prism parser.
PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_method_name(const uint8_t *source, size_t length, const char *encoding_name)
Check that the slice is a valid method name.
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 const char * pm_version(void)
The prism version and the serialization format.
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser)
Free any memory associated with the given 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.
PRISM_EXPORTED_FUNCTION void pm_serialize(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the AST represented by the given node to the given buffer.
PRISM_EXPORTED_FUNCTION void pm_serialize_parse_comments(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data)
Parse and serialize the comments in the given source to the given buffer.
PRISM_EXPORTED_FUNCTION void pm_serialize_parse_stream(pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *fgets, const char *data)
Parse and serialize the AST represented by the source that is read out of the given stream into to th...
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *fgets, const pm_options_t *options)
Parse a stream of Ruby source and return the tree.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser)
Initiate the parser with the given parser.
PRISM_EXPORTED_FUNCTION void pm_serialize_parse(pm_buffer_t *buffer, const uint8_t *source, size_t size, const char *data)
Parse the given source to the AST and dump the AST to the given buffer.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
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.
PRISM_EXPORTED_FUNCTION bool pm_parse_success_p(const uint8_t *source, size_t size, const char *data)
Parse the source and return true if it parses without errors or warnings.
PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_constant(const uint8_t *source, size_t length, const char *encoding_name)
Check that the slice is a valid constant name.
PRISM_EXPORTED_FUNCTION pm_string_query_t pm_string_query_local(const uint8_t *source, size_t length, const char *encoding_name)
Check that the slice is a valid local variable name.
void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer)
Serialize the given list of comments to the given buffer.
const char * pm_token_type_human(pm_token_type_t token_type)
Returns the human name of the given token type.
PRISM_EXPORTED_FUNCTION void pm_regexp_parse(pm_parser_t *parser, const uint8_t *source, size_t size, bool extended_mode, pm_regexp_name_callback_t name_callback, void *name_data, pm_regexp_error_callback_t error_callback, void *error_data)
Parse a regular expression.
void pm_static_literal_inspect(pm_buffer_t *buffer, const pm_newline_list_t *newline_list, int32_t start_line, const char *encoding_name, const pm_node_t *node)
Create a string-based representation of the given static literal.
pm_node_t * pm_static_literals_add(const pm_newline_list_t *newline_list, int32_t start_line, pm_static_literals_t *literals, pm_node_t *node, bool replace)
Add a node to the set of static literals.
void pm_static_literals_free(pm_static_literals_t *literals)
Free the internal memory associated with the given static literals set.
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.
struct pm_node * left
AndNode::left.
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.
struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
struct pm_node * value
AssocNode::value.
struct pm_node * key
AssocNode::key.
struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
struct pm_statements_node * statements
BeginNode::statements.
pm_node_t base
The embedded base node.
struct pm_else_node * else_clause
BeginNode::else_clause.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
size_t length
The length of the buffer in bytes.
char * value
A pointer to the start of the buffer.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
struct pm_node * receiver
CallNode::receiver.
pm_constant_id_t name
CallNode::name.
pm_node_t base
The embedded base node.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
struct pm_arguments_node * arguments
CallNode::arguments.
struct pm_node * block
CallNode::block.
struct pm_node_list conditions
CaseMatchNode::conditions.
struct pm_node_list conditions
CaseNode::conditions.
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.
This struct represents a diagnostic generated during parsing.
pm_list_node_t node
The embedded base node.
pm_diagnostic_id_t diag_id
The ID of the diagnostic.
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...
struct pm_statements_node * statements
EnsureNode::statements.
struct pm_node * constant
FindPatternNode::constant.
pm_location_t opening_loc
FindPatternNode::opening_loc.
pm_node_t base
The embedded base node.
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_location_t opening_loc
HashPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
HashPatternNode::closing_loc.
struct pm_node * constant
HashPatternNode::constant.
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.
struct pm_statements_node * statements
IfNode::statements.
struct pm_node * subsequent
IfNode::subsequent.
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_node_t base
The embedded base node.
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...
enum pm_lex_mode::@91 mode
The type of this lex mode.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
union pm_lex_mode::@92 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.
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 represents a range of bytes in the source string to which a node or token corresponds.
const uint8_t * start
A pointer to the start location of the range in the source.
const uint8_t * end
A pointer to the end location of the range in the source.
struct pm_node_list targets
MatchWriteNode::targets.
pm_node_t base
The embedded base node.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
size_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_node_flags_t flags
This represents any flags on 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.
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.
struct pm_node * left
OrNode::left.
struct pm_node * right
OrNode::right.
struct pm_node * rest
ParametersNode::rest.
struct pm_block_parameter_node * block
ParametersNode::block.
pm_node_t base
The embedded base node.
struct pm_node * keyword_rest
ParametersNode::keyword_rest.
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.
struct pm_parser::@97 lex_modes
A stack of lex modes.
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_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 ...
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.
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
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.
struct pm_node * right
RangeNode::right.
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_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode::unescaped.
struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_node_t base
The embedded base node.
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.
struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
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 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::@98 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.
struct pm_statements_node * statements
UnlessNode::statements.
struct pm_else_node * else_clause
UnlessNode::else_clause.