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).
4145 if (errno == ERANGE && isinf(value)) {
4147 const char *ellipsis;
4153 warn_width = (int) length;
4157 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);
4158 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4161 // Finally we can free the buffer and return the value.
4162 xfree((void *) buffer);
4169 static pm_float_node_t *
4170 pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4171 assert(token->type == PM_TOKEN_FLOAT);
4172 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4174 *node = (pm_float_node_t) {
4176 .type = PM_FLOAT_NODE,
4177 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4178 .node_id = PM_NODE_IDENTIFY(parser),
4179 .location = PM_LOCATION_TOKEN_VALUE(token)
4181 .value = pm_double_parse(parser, token)
4190 static pm_imaginary_node_t *
4191 pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4192 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4194 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4195 *node = (pm_imaginary_node_t) {
4197 .type = PM_IMAGINARY_NODE,
4198 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4199 .node_id = PM_NODE_IDENTIFY(parser),
4200 .location = PM_LOCATION_TOKEN_VALUE(token)
4202 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4203 .type = PM_TOKEN_FLOAT,
4204 .start = token->start,
4205 .end = token->end - 1
4215 static pm_rational_node_t *
4216 pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4217 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4219 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4220 *node = (pm_rational_node_t) {
4222 .type = PM_RATIONAL_NODE,
4223 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4224 .node_id = PM_NODE_IDENTIFY(parser),
4225 .location = PM_LOCATION_TOKEN_VALUE(token)
4228 .denominator = { 0 }
4231 const uint8_t *start = token->start;
4232 const uint8_t *end = token->end - 1; // r
4234 while (start < end && *start == '0') start++; // 0.1 -> .1
4235 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4237 size_t length = (size_t) (end - start);
4239 node->denominator.value = 1;
4243 const uint8_t *point = memchr(start, '.', length);
4244 assert(point && "should have a decimal point");
4246 uint8_t *digits = malloc(length);
4247 if (digits == NULL) {
4248 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4252 memcpy(digits, start, (unsigned long) (point - start));
4253 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4254 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4257 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4258 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4261 pm_integers_reduce(&node->numerator, &node->denominator);
4269 static pm_imaginary_node_t *
4270 pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4271 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4273 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4274 *node = (pm_imaginary_node_t) {
4276 .type = PM_IMAGINARY_NODE,
4277 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4278 .node_id = PM_NODE_IDENTIFY(parser),
4279 .location = PM_LOCATION_TOKEN_VALUE(token)
4281 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4282 .type = PM_TOKEN_FLOAT_RATIONAL,
4283 .start = token->start,
4284 .end = token->end - 1
4294 static pm_for_node_t *
4296 pm_parser_t *parser,
4298 pm_node_t *collection,
4299 pm_statements_node_t *statements,
4300 const pm_token_t *for_keyword,
4301 const pm_token_t *in_keyword,
4302 const pm_token_t *do_keyword,
4303 const pm_token_t *end_keyword
4305 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4307 *node = (pm_for_node_t) {
4309 .type = PM_FOR_NODE,
4310 .node_id = PM_NODE_IDENTIFY(parser),
4312 .start = for_keyword->start,
4313 .end = end_keyword->end
4317 .collection = collection,
4318 .statements = statements,
4319 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4320 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4321 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4322 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4331 static pm_forwarding_arguments_node_t *
4332 pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4333 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4334 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4336 *node = (pm_forwarding_arguments_node_t) {{
4337 .type = PM_FORWARDING_ARGUMENTS_NODE,
4338 .node_id = PM_NODE_IDENTIFY(parser),
4339 .location = PM_LOCATION_TOKEN_VALUE(token)
4348 static pm_forwarding_parameter_node_t *
4349 pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4350 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4351 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4353 *node = (pm_forwarding_parameter_node_t) {{
4354 .type = PM_FORWARDING_PARAMETER_NODE,
4355 .node_id = PM_NODE_IDENTIFY(parser),
4356 .location = PM_LOCATION_TOKEN_VALUE(token)
4365 static pm_forwarding_super_node_t *
4366 pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4367 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4368 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4369 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4371 pm_block_node_t *block = NULL;
4372 if (arguments->block != NULL) {
4373 block = (pm_block_node_t *) arguments->block;
4376 *node = (pm_forwarding_super_node_t) {
4378 .type = PM_FORWARDING_SUPER_NODE,
4379 .node_id = PM_NODE_IDENTIFY(parser),
4381 .start = token->start,
4382 .end = block != NULL ? block->base.location.end : token->end
4395 static pm_hash_pattern_node_t *
4396 pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4397 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4399 *node = (pm_hash_pattern_node_t) {
4401 .type = PM_HASH_PATTERN_NODE,
4402 .node_id = PM_NODE_IDENTIFY(parser),
4404 .start = opening->start,
4409 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4410 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4421 static pm_hash_pattern_node_t *
4422 pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4423 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4425 const uint8_t *start;
4428 if (elements->size > 0) {
4430 start = elements->nodes[0]->location.start;
4431 end = rest->location.end;
4433 start = elements->nodes[0]->location.start;
4434 end = elements->nodes[elements->size - 1]->location.end;
4437 assert(rest != NULL);
4438 start = rest->location.start;
4439 end = rest->location.end;
4442 *node = (pm_hash_pattern_node_t) {
4444 .type = PM_HASH_PATTERN_NODE,
4445 .node_id = PM_NODE_IDENTIFY(parser),
4454 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4455 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4459 PM_NODE_LIST_FOREACH(elements, index, element) {
4460 pm_node_list_append(&node->elements, element);
4469 static pm_constant_id_t
4470 pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4471 switch (PM_NODE_TYPE(target)) {
4472 case PM_GLOBAL_VARIABLE_READ_NODE:
4473 return ((pm_global_variable_read_node_t *) target)->name;
4474 case PM_BACK_REFERENCE_READ_NODE:
4475 return ((pm_back_reference_read_node_t *) target)->name;
4476 case PM_NUMBERED_REFERENCE_READ_NODE:
4477 // This will only ever happen in the event of a syntax error, but we
4478 // still need to provide something for the node.
4479 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4481 assert(false && "unreachable");
4482 return (pm_constant_id_t) -1;
4489 static pm_global_variable_and_write_node_t *
4490 pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4491 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4492 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4494 *node = (pm_global_variable_and_write_node_t) {
4496 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4497 .node_id = PM_NODE_IDENTIFY(parser),
4499 .start = target->location.start,
4500 .end = value->location.end
4503 .name = pm_global_variable_write_name(parser, target),
4504 .name_loc = target->location,
4505 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4515 static pm_global_variable_operator_write_node_t *
4516 pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4517 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4519 *node = (pm_global_variable_operator_write_node_t) {
4521 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4522 .node_id = PM_NODE_IDENTIFY(parser),
4524 .start = target->location.start,
4525 .end = value->location.end
4528 .name = pm_global_variable_write_name(parser, target),
4529 .name_loc = target->location,
4530 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4532 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4541 static pm_global_variable_or_write_node_t *
4542 pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4543 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4544 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4546 *node = (pm_global_variable_or_write_node_t) {
4548 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4549 .node_id = PM_NODE_IDENTIFY(parser),
4551 .start = target->location.start,
4552 .end = value->location.end
4555 .name = pm_global_variable_write_name(parser, target),
4556 .name_loc = target->location,
4557 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4567 static pm_global_variable_read_node_t *
4568 pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4569 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4571 *node = (pm_global_variable_read_node_t) {
4573 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4574 .node_id = PM_NODE_IDENTIFY(parser),
4575 .location = PM_LOCATION_TOKEN_VALUE(name),
4577 .name = pm_parser_constant_id_token(parser, name)
4586 static pm_global_variable_read_node_t *
4587 pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4588 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4590 *node = (pm_global_variable_read_node_t) {
4592 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4593 .node_id = PM_NODE_IDENTIFY(parser),
4594 .location = PM_LOCATION_NULL_VALUE(parser)
4605 static pm_global_variable_write_node_t *
4606 pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4607 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4609 *node = (pm_global_variable_write_node_t) {
4611 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4612 .node_id = PM_NODE_IDENTIFY(parser),
4613 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4615 .start = target->location.start,
4616 .end = value->location.end
4619 .name = pm_global_variable_write_name(parser, target),
4620 .name_loc = PM_LOCATION_NODE_VALUE(target),
4621 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4631 static pm_global_variable_write_node_t *
4632 pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4633 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4635 *node = (pm_global_variable_write_node_t) {
4637 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4638 .node_id = PM_NODE_IDENTIFY(parser),
4639 .location = PM_LOCATION_NULL_VALUE(parser)
4642 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4643 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4653 static pm_hash_node_t *
4654 pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4655 assert(opening != NULL);
4656 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4658 *node = (pm_hash_node_t) {
4660 .type = PM_HASH_NODE,
4661 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4662 .node_id = PM_NODE_IDENTIFY(parser),
4663 .location = PM_LOCATION_TOKEN_VALUE(opening)
4665 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4666 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4677 pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4678 pm_node_list_append(&hash->elements, element);
4680 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4681 if (static_literal) {
4682 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4683 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);
4684 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4685 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4688 if (!static_literal) {
4689 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4694 pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4695 hash->base.location.end = token->end;
4696 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4702 static pm_if_node_t *
4703 pm_if_node_create(pm_parser_t *parser,
4704 const pm_token_t *if_keyword,
4705 pm_node_t *predicate,
4706 const pm_token_t *then_keyword,
4707 pm_statements_node_t *statements,
4708 pm_node_t *subsequent,
4709 const pm_token_t *end_keyword
4711 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4712 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4715 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4716 end = end_keyword->end;
4717 } else if (subsequent != NULL) {
4718 end = subsequent->location.end;
4719 } else if (pm_statements_node_body_length(statements) != 0) {
4720 end = statements->base.location.end;
4722 end = predicate->location.end;
4725 *node = (pm_if_node_t) {
4728 .flags = PM_NODE_FLAG_NEWLINE,
4729 .node_id = PM_NODE_IDENTIFY(parser),
4731 .start = if_keyword->start,
4735 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4736 .predicate = predicate,
4737 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4738 .statements = statements,
4739 .subsequent = subsequent,
4740 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4749 static pm_if_node_t *
4750 pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4751 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4752 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4754 pm_statements_node_t *statements = pm_statements_node_create(parser);
4755 pm_statements_node_body_append(parser, statements, statement, true);
4757 *node = (pm_if_node_t) {
4760 .flags = PM_NODE_FLAG_NEWLINE,
4761 .node_id = PM_NODE_IDENTIFY(parser),
4763 .start = statement->location.start,
4764 .end = predicate->location.end
4767 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4768 .predicate = predicate,
4769 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4770 .statements = statements,
4772 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4781 static pm_if_node_t *
4782 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) {
4783 pm_assert_value_expression(parser, predicate);
4784 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4786 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4787 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4789 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4790 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4792 pm_token_t end_keyword = not_provided(parser);
4793 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4795 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4797 *node = (pm_if_node_t) {
4800 .flags = PM_NODE_FLAG_NEWLINE,
4801 .node_id = PM_NODE_IDENTIFY(parser),
4803 .start = predicate->location.start,
4804 .end = false_expression->location.end,
4807 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4808 .predicate = predicate,
4809 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4810 .statements = if_statements,
4811 .subsequent = (pm_node_t *) else_node,
4812 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4820 pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4821 node->base.location.end = keyword->end;
4822 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4826 pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4827 node->base.location.end = keyword->end;
4828 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4834 static pm_implicit_node_t *
4835 pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4836 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4838 *node = (pm_implicit_node_t) {
4840 .type = PM_IMPLICIT_NODE,
4841 .node_id = PM_NODE_IDENTIFY(parser),
4842 .location = value->location
4853 static pm_implicit_rest_node_t *
4854 pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4855 assert(token->type == PM_TOKEN_COMMA);
4857 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4859 *node = (pm_implicit_rest_node_t) {
4861 .type = PM_IMPLICIT_REST_NODE,
4862 .node_id = PM_NODE_IDENTIFY(parser),
4863 .location = PM_LOCATION_TOKEN_VALUE(token)
4873 static pm_integer_node_t *
4874 pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4875 assert(token->type == PM_TOKEN_INTEGER);
4876 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4878 *node = (pm_integer_node_t) {
4880 .type = PM_INTEGER_NODE,
4881 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4882 .node_id = PM_NODE_IDENTIFY(parser),
4883 .location = PM_LOCATION_TOKEN_VALUE(token)
4888 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4890 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4891 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4892 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4893 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4894 default: assert(false && "unreachable"); break;
4897 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4905 static pm_imaginary_node_t *
4906 pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4907 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4909 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4910 *node = (pm_imaginary_node_t) {
4912 .type = PM_IMAGINARY_NODE,
4913 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4914 .node_id = PM_NODE_IDENTIFY(parser),
4915 .location = PM_LOCATION_TOKEN_VALUE(token)
4917 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4918 .type = PM_TOKEN_INTEGER,
4919 .start = token->start,
4920 .end = token->end - 1
4931 static pm_rational_node_t *
4932 pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4933 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4935 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4936 *node = (pm_rational_node_t) {
4938 .type = PM_RATIONAL_NODE,
4939 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4940 .node_id = PM_NODE_IDENTIFY(parser),
4941 .location = PM_LOCATION_TOKEN_VALUE(token)
4944 .denominator = { .value = 1, 0 }
4947 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4949 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4950 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4951 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4952 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4953 default: assert(false && "unreachable"); break;
4956 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4965 static pm_imaginary_node_t *
4966 pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4967 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4969 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4970 *node = (pm_imaginary_node_t) {
4972 .type = PM_IMAGINARY_NODE,
4973 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4974 .node_id = PM_NODE_IDENTIFY(parser),
4975 .location = PM_LOCATION_TOKEN_VALUE(token)
4977 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4978 .type = PM_TOKEN_INTEGER_RATIONAL,
4979 .start = token->start,
4980 .end = token->end - 1
4990 static pm_in_node_t *
4991 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) {
4992 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4995 if (statements != NULL) {
4996 end = statements->base.location.end;
4997 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4998 end = then_keyword->end;
5000 end = pattern->location.end;
5003 *node = (pm_in_node_t) {
5006 .node_id = PM_NODE_IDENTIFY(parser),
5008 .start = in_keyword->start,
5013 .statements = statements,
5014 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5015 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5024 static pm_instance_variable_and_write_node_t *
5025 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) {
5026 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5027 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5029 *node = (pm_instance_variable_and_write_node_t) {
5031 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5032 .node_id = PM_NODE_IDENTIFY(parser),
5034 .start = target->base.location.start,
5035 .end = value->location.end
5038 .name = target->name,
5039 .name_loc = target->base.location,
5040 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5050 static pm_instance_variable_operator_write_node_t *
5051 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) {
5052 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5054 *node = (pm_instance_variable_operator_write_node_t) {
5056 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5057 .node_id = PM_NODE_IDENTIFY(parser),
5059 .start = target->base.location.start,
5060 .end = value->location.end
5063 .name = target->name,
5064 .name_loc = target->base.location,
5065 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5067 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5076 static pm_instance_variable_or_write_node_t *
5077 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) {
5078 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5079 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5081 *node = (pm_instance_variable_or_write_node_t) {
5083 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5084 .node_id = PM_NODE_IDENTIFY(parser),
5086 .start = target->base.location.start,
5087 .end = value->location.end
5090 .name = target->name,
5091 .name_loc = target->base.location,
5092 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5102 static pm_instance_variable_read_node_t *
5103 pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5104 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5105 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5107 *node = (pm_instance_variable_read_node_t) {
5109 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5110 .node_id = PM_NODE_IDENTIFY(parser),
5111 .location = PM_LOCATION_TOKEN_VALUE(token)
5113 .name = pm_parser_constant_id_token(parser, token)
5123 static pm_instance_variable_write_node_t *
5124 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) {
5125 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5126 *node = (pm_instance_variable_write_node_t) {
5128 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5129 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5130 .node_id = PM_NODE_IDENTIFY(parser),
5132 .start = read_node->base.location.start,
5133 .end = value->location.end
5136 .name = read_node->name,
5137 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5138 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5151 pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5152 switch (PM_NODE_TYPE(part)) {
5153 case PM_STRING_NODE:
5154 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5156 case PM_EMBEDDED_STATEMENTS_NODE: {
5157 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5158 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5160 if (embedded == NULL) {
5161 // If there are no statements or more than one statement, then
5162 // we lose the static literal flag.
5163 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5164 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5165 // If the embedded statement is a string, then we can keep the
5166 // static literal flag and mark the string as frozen.
5167 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5168 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5169 // If the embedded statement is an interpolated string and it's
5170 // a static literal, then we can keep the static literal flag.
5172 // Otherwise we lose the static literal flag.
5173 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5178 case PM_EMBEDDED_VARIABLE_NODE:
5179 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5182 assert(false && "unexpected node type");
5186 pm_node_list_append(parts, part);
5192 static pm_interpolated_regular_expression_node_t *
5193 pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5194 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5196 *node = (pm_interpolated_regular_expression_node_t) {
5198 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5199 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5200 .node_id = PM_NODE_IDENTIFY(parser),
5202 .start = opening->start,
5206 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5207 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5215 pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5216 if (node->base.location.start > part->location.start) {
5217 node->base.location.start = part->location.start;
5219 if (node->base.location.end < part->location.end) {
5220 node->base.location.end = part->location.end;
5223 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5227 pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5228 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5229 node->base.location.end = closing->end;
5230 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5257 pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5258 #define CLEAR_FLAGS(node) \
5259 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))
5261 #define MUTABLE_FLAGS(node) \
5262 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5264 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5265 node->base.location.start = part->location.start;
5268 node->base.location.end = MAX(node->base.location.end, part->location.end);
5270 switch (PM_NODE_TYPE(part)) {
5271 case PM_STRING_NODE:
5272 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5274 case PM_INTERPOLATED_STRING_NODE:
5275 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5276 // If the string that we're concatenating is a static literal,
5277 // then we can keep the static literal flag for this string.
5279 // Otherwise, we lose the static literal flag here and we should
5280 // also clear the mutability flags.
5284 case PM_EMBEDDED_STATEMENTS_NODE: {
5285 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5286 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5288 if (embedded == NULL) {
5289 // If we're embedding multiple statements or no statements, then
5290 // the string is not longer a static literal.
5292 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5293 // If the embedded statement is a string, then we can make that
5294 // string as frozen and static literal, and not touch the static
5295 // literal status of this string.
5296 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5298 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5299 MUTABLE_FLAGS(node);
5301 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5302 // If the embedded statement is an interpolated string, but that
5303 // string is marked as static literal, then we can keep our
5304 // static literal status for this string.
5305 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5306 MUTABLE_FLAGS(node);
5309 // In all other cases, we lose the static literal flag here and
5316 case PM_EMBEDDED_VARIABLE_NODE:
5317 // Embedded variables clear static literal, which means we also
5318 // should clear the mutability flags.
5322 assert(false && "unexpected node type");
5326 pm_node_list_append(&node->parts, part);
5329 #undef MUTABLE_FLAGS
5335 static pm_interpolated_string_node_t *
5336 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) {
5337 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5338 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5340 switch (parser->frozen_string_literal) {
5341 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5342 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5344 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5345 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5349 *node = (pm_interpolated_string_node_t) {
5351 .type = PM_INTERPOLATED_STRING_NODE,
5353 .node_id = PM_NODE_IDENTIFY(parser),
5355 .start = opening->start,
5356 .end = closing->end,
5359 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5360 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5364 if (parts != NULL) {
5366 PM_NODE_LIST_FOREACH(parts, index, part) {
5367 pm_interpolated_string_node_append(node, part);
5378 pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5379 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5380 node->base.location.end = closing->end;
5384 pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5385 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5386 node->base.location.start = part->location.start;
5389 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5390 node->base.location.end = MAX(node->base.location.end, part->location.end);
5394 pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5395 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5396 node->base.location.end = closing->end;
5402 static pm_interpolated_symbol_node_t *
5403 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) {
5404 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5406 *node = (pm_interpolated_symbol_node_t) {
5408 .type = PM_INTERPOLATED_SYMBOL_NODE,
5409 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5410 .node_id = PM_NODE_IDENTIFY(parser),
5412 .start = opening->start,
5413 .end = closing->end,
5416 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5417 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5421 if (parts != NULL) {
5423 PM_NODE_LIST_FOREACH(parts, index, part) {
5424 pm_interpolated_symbol_node_append(node, part);
5434 static pm_interpolated_x_string_node_t *
5435 pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5436 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5438 *node = (pm_interpolated_x_string_node_t) {
5440 .type = PM_INTERPOLATED_X_STRING_NODE,
5441 .node_id = PM_NODE_IDENTIFY(parser),
5443 .start = opening->start,
5447 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5448 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5456 pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5457 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5458 node->base.location.end = part->location.end;
5462 pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5463 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5464 node->base.location.end = closing->end;
5470 static pm_it_local_variable_read_node_t *
5471 pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5472 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5474 *node = (pm_it_local_variable_read_node_t) {
5476 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5477 .node_id = PM_NODE_IDENTIFY(parser),
5478 .location = PM_LOCATION_TOKEN_VALUE(name)
5488 static pm_it_parameters_node_t *
5489 pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5490 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5492 *node = (pm_it_parameters_node_t) {
5494 .type = PM_IT_PARAMETERS_NODE,
5495 .node_id = PM_NODE_IDENTIFY(parser),
5497 .start = opening->start,
5509 static pm_keyword_hash_node_t *
5510 pm_keyword_hash_node_create(pm_parser_t *parser) {
5511 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5513 *node = (pm_keyword_hash_node_t) {
5515 .type = PM_KEYWORD_HASH_NODE,
5516 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5517 .node_id = PM_NODE_IDENTIFY(parser),
5518 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5530 pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5531 // If the element being added is not an AssocNode or does not have a symbol
5532 // key, then we want to turn the SYMBOL_KEYS flag off.
5533 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5534 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5537 pm_node_list_append(&hash->elements, element);
5538 if (hash->base.location.start == NULL) {
5539 hash->base.location.start = element->location.start;
5541 hash->base.location.end = element->location.end;
5547 static pm_required_keyword_parameter_node_t *
5548 pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5549 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5551 *node = (pm_required_keyword_parameter_node_t) {
5553 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5554 .node_id = PM_NODE_IDENTIFY(parser),
5556 .start = name->start,
5560 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5561 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5570 static pm_optional_keyword_parameter_node_t *
5571 pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5572 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5574 *node = (pm_optional_keyword_parameter_node_t) {
5576 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5577 .node_id = PM_NODE_IDENTIFY(parser),
5579 .start = name->start,
5580 .end = value->location.end
5583 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5584 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5594 static pm_keyword_rest_parameter_node_t *
5595 pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5596 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5598 *node = (pm_keyword_rest_parameter_node_t) {
5600 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5601 .node_id = PM_NODE_IDENTIFY(parser),
5603 .start = operator->start,
5604 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5607 .name = pm_parser_optional_constant_id_token(parser, name),
5608 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5609 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5618 static pm_lambda_node_t *
5619 pm_lambda_node_create(
5620 pm_parser_t *parser,
5621 pm_constant_id_list_t *locals,
5622 const pm_token_t *operator,
5623 const pm_token_t *opening,
5624 const pm_token_t *closing,
5625 pm_node_t *parameters,
5628 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5630 *node = (pm_lambda_node_t) {
5632 .type = PM_LAMBDA_NODE,
5633 .node_id = PM_NODE_IDENTIFY(parser),
5635 .start = operator->start,
5640 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5641 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5642 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5643 .parameters = parameters,
5653 static pm_local_variable_and_write_node_t *
5654 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) {
5655 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5656 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5657 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5659 *node = (pm_local_variable_and_write_node_t) {
5661 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5662 .node_id = PM_NODE_IDENTIFY(parser),
5664 .start = target->location.start,
5665 .end = value->location.end
5668 .name_loc = target->location,
5669 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5681 static pm_local_variable_operator_write_node_t *
5682 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) {
5683 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5685 *node = (pm_local_variable_operator_write_node_t) {
5687 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5688 .node_id = PM_NODE_IDENTIFY(parser),
5690 .start = target->location.start,
5691 .end = value->location.end
5694 .name_loc = target->location,
5695 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5698 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5708 static pm_local_variable_or_write_node_t *
5709 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) {
5710 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5711 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5712 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5714 *node = (pm_local_variable_or_write_node_t) {
5716 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5717 .node_id = PM_NODE_IDENTIFY(parser),
5719 .start = target->location.start,
5720 .end = value->location.end
5723 .name_loc = target->location,
5724 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5736 static pm_local_variable_read_node_t *
5737 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) {
5738 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5740 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5742 *node = (pm_local_variable_read_node_t) {
5744 .type = PM_LOCAL_VARIABLE_READ_NODE,
5745 .node_id = PM_NODE_IDENTIFY(parser),
5746 .location = PM_LOCATION_TOKEN_VALUE(name)
5758 static pm_local_variable_read_node_t *
5759 pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5760 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5761 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5768 static pm_local_variable_read_node_t *
5769 pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5770 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5771 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5777 static pm_local_variable_write_node_t *
5778 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) {
5779 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5781 *node = (pm_local_variable_write_node_t) {
5783 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5784 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5785 .node_id = PM_NODE_IDENTIFY(parser),
5787 .start = name_loc->start,
5788 .end = value->location.end
5794 .name_loc = *name_loc,
5795 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5805 pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5806 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5814 pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5815 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5823 pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5824 if (pm_token_is_numbered_parameter(start, end)) {
5825 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5833 static pm_local_variable_target_node_t *
5834 pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5835 pm_refute_numbered_parameter(parser, location->start, location->end);
5836 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5838 *node = (pm_local_variable_target_node_t) {
5840 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5841 .node_id = PM_NODE_IDENTIFY(parser),
5842 .location = *location
5854 static pm_match_predicate_node_t *
5855 pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5856 pm_assert_value_expression(parser, value);
5858 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5860 *node = (pm_match_predicate_node_t) {
5862 .type = PM_MATCH_PREDICATE_NODE,
5863 .node_id = PM_NODE_IDENTIFY(parser),
5865 .start = value->location.start,
5866 .end = pattern->location.end
5871 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5880 static pm_match_required_node_t *
5881 pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5882 pm_assert_value_expression(parser, value);
5884 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5886 *node = (pm_match_required_node_t) {
5888 .type = PM_MATCH_REQUIRED_NODE,
5889 .node_id = PM_NODE_IDENTIFY(parser),
5891 .start = value->location.start,
5892 .end = pattern->location.end
5897 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5906 static pm_match_write_node_t *
5907 pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5908 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5910 *node = (pm_match_write_node_t) {
5912 .type = PM_MATCH_WRITE_NODE,
5913 .node_id = PM_NODE_IDENTIFY(parser),
5914 .location = call->base.location
5926 static pm_module_node_t *
5927 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) {
5928 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5930 *node = (pm_module_node_t) {
5932 .type = PM_MODULE_NODE,
5933 .node_id = PM_NODE_IDENTIFY(parser),
5935 .start = module_keyword->start,
5936 .end = end_keyword->end
5939 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5940 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5941 .constant_path = constant_path,
5943 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5944 .name = pm_parser_constant_id_token(parser, name)
5953 static pm_multi_target_node_t *
5954 pm_multi_target_node_create(pm_parser_t *parser) {
5955 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5957 *node = (pm_multi_target_node_t) {
5959 .type = PM_MULTI_TARGET_NODE,
5960 .node_id = PM_NODE_IDENTIFY(parser),
5961 .location = { .start = NULL, .end = NULL }
5966 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5967 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5977 pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5978 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5979 if (node->rest == NULL) {
5980 node->rest = target;
5982 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5983 pm_node_list_append(&node->rights, target);
5985 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5986 if (node->rest == NULL) {
5987 node->rest = target;
5989 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5990 pm_node_list_append(&node->rights, target);
5992 } else if (node->rest == NULL) {
5993 pm_node_list_append(&node->lefts, target);
5995 pm_node_list_append(&node->rights, target);
5998 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
5999 node->base.location.start = target->location.start;
6002 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6003 node->base.location.end = target->location.end;
6011 pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6012 node->base.location.start = lparen->start;
6013 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6020 pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6021 node->base.location.end = rparen->end;
6022 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6028 static pm_multi_write_node_t *
6029 pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6030 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6032 *node = (pm_multi_write_node_t) {
6034 .type = PM_MULTI_WRITE_NODE,
6035 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6036 .node_id = PM_NODE_IDENTIFY(parser),
6038 .start = target->base.location.start,
6039 .end = value->location.end
6042 .lefts = target->lefts,
6043 .rest = target->rest,
6044 .rights = target->rights,
6045 .lparen_loc = target->lparen_loc,
6046 .rparen_loc = target->rparen_loc,
6047 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6051 // Explicitly do not call pm_node_destroy here because we want to keep
6052 // around all of the information within the MultiWriteNode node.
6061 static pm_next_node_t *
6062 pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6063 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6064 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6066 *node = (pm_next_node_t) {
6068 .type = PM_NEXT_NODE,
6069 .node_id = PM_NODE_IDENTIFY(parser),
6071 .start = keyword->start,
6072 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6075 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6076 .arguments = arguments
6085 static pm_nil_node_t *
6086 pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6087 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6088 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6090 *node = (pm_nil_node_t) {{
6091 .type = PM_NIL_NODE,
6092 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6093 .node_id = PM_NODE_IDENTIFY(parser),
6094 .location = PM_LOCATION_TOKEN_VALUE(token)
6103 static pm_no_keywords_parameter_node_t *
6104 pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6105 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6106 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6107 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6109 *node = (pm_no_keywords_parameter_node_t) {
6111 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6112 .node_id = PM_NODE_IDENTIFY(parser),
6114 .start = operator->start,
6118 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6119 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6128 static pm_numbered_parameters_node_t *
6129 pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6130 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6132 *node = (pm_numbered_parameters_node_t) {
6134 .type = PM_NUMBERED_PARAMETERS_NODE,
6135 .node_id = PM_NODE_IDENTIFY(parser),
6136 .location = *location
6148 #define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6157 pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6158 const uint8_t *start = token->start + 1;
6159 const uint8_t *end = token->end;
6161 ptrdiff_t diff = end - start;
6162 assert(diff > 0 && ((unsigned long) diff < SIZE_MAX));
6163 size_t length = (size_t) diff;
6165 char *digits = xcalloc(length + 1, sizeof(char));
6166 memcpy(digits, start, length);
6167 digits[length] = '\0';
6171 unsigned long value = strtoul(digits, &endptr, 10);
6173 if ((digits == endptr) || (*endptr != '\0')) {
6174 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6180 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6181 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6185 return (uint32_t) value;
6193 static pm_numbered_reference_read_node_t *
6194 pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6195 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6196 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6198 *node = (pm_numbered_reference_read_node_t) {
6200 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6201 .node_id = PM_NODE_IDENTIFY(parser),
6202 .location = PM_LOCATION_TOKEN_VALUE(name),
6204 .number = pm_numbered_reference_read_node_number(parser, name)
6213 static pm_optional_parameter_node_t *
6214 pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6215 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6217 *node = (pm_optional_parameter_node_t) {
6219 .type = PM_OPTIONAL_PARAMETER_NODE,
6220 .node_id = PM_NODE_IDENTIFY(parser),
6222 .start = name->start,
6223 .end = value->location.end
6226 .name = pm_parser_constant_id_token(parser, name),
6227 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6228 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6238 static pm_or_node_t *
6239 pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6240 pm_assert_value_expression(parser, left);
6242 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6244 *node = (pm_or_node_t) {
6247 .node_id = PM_NODE_IDENTIFY(parser),
6249 .start = left->location.start,
6250 .end = right->location.end
6255 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6264 static pm_parameters_node_t *
6265 pm_parameters_node_create(pm_parser_t *parser) {
6266 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6268 *node = (pm_parameters_node_t) {
6270 .type = PM_PARAMETERS_NODE,
6271 .node_id = PM_NODE_IDENTIFY(parser),
6272 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6275 .keyword_rest = NULL,
6290 pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6291 if (params->base.location.start == NULL) {
6292 params->base.location.start = param->location.start;
6294 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6297 if (params->base.location.end == NULL) {
6298 params->base.location.end = param->location.end;
6300 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6308 pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6309 pm_parameters_node_location_set(params, param);
6310 pm_node_list_append(¶ms->requireds, param);
6317 pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6318 pm_parameters_node_location_set(params, (pm_node_t *) param);
6319 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6326 pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6327 pm_parameters_node_location_set(params, param);
6328 pm_node_list_append(¶ms->posts, param);
6335 pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6336 pm_parameters_node_location_set(params, param);
6337 params->rest = param;
6344 pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6345 pm_parameters_node_location_set(params, param);
6346 pm_node_list_append(¶ms->keywords, param);
6353 pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6354 assert(params->keyword_rest == NULL);
6355 pm_parameters_node_location_set(params, param);
6356 params->keyword_rest = param;
6363 pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6364 assert(params->block == NULL);
6365 pm_parameters_node_location_set(params, (pm_node_t *) param);
6366 params->block = param;
6372 static pm_program_node_t *
6373 pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6374 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6376 *node = (pm_program_node_t) {
6378 .type = PM_PROGRAM_NODE,
6379 .node_id = PM_NODE_IDENTIFY(parser),
6381 .start = statements == NULL ? parser->start : statements->base.location.start,
6382 .end = statements == NULL ? parser->end : statements->base.location.end
6386 .statements = statements
6395 static pm_parentheses_node_t *
6396 pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
6397 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6399 *node = (pm_parentheses_node_t) {
6401 .type = PM_PARENTHESES_NODE,
6402 .node_id = PM_NODE_IDENTIFY(parser),
6404 .start = opening->start,
6409 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6410 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6419 static pm_pinned_expression_node_t *
6420 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) {
6421 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6423 *node = (pm_pinned_expression_node_t) {
6425 .type = PM_PINNED_EXPRESSION_NODE,
6426 .node_id = PM_NODE_IDENTIFY(parser),
6428 .start = operator->start,
6432 .expression = expression,
6433 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6434 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6435 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6444 static pm_pinned_variable_node_t *
6445 pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6446 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6448 *node = (pm_pinned_variable_node_t) {
6450 .type = PM_PINNED_VARIABLE_NODE,
6451 .node_id = PM_NODE_IDENTIFY(parser),
6453 .start = operator->start,
6454 .end = variable->location.end
6457 .variable = variable,
6458 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6467 static pm_post_execution_node_t *
6468 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) {
6469 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6471 *node = (pm_post_execution_node_t) {
6473 .type = PM_POST_EXECUTION_NODE,
6474 .node_id = PM_NODE_IDENTIFY(parser),
6476 .start = keyword->start,
6480 .statements = statements,
6481 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6482 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6483 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6492 static pm_pre_execution_node_t *
6493 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) {
6494 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6496 *node = (pm_pre_execution_node_t) {
6498 .type = PM_PRE_EXECUTION_NODE,
6499 .node_id = PM_NODE_IDENTIFY(parser),
6501 .start = keyword->start,
6505 .statements = statements,
6506 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6507 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6508 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6517 static pm_range_node_t *
6518 pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6519 pm_assert_value_expression(parser, left);
6520 pm_assert_value_expression(parser, right);
6522 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6523 pm_node_flags_t flags = 0;
6525 // Indicate that this node is an exclusive range if the operator is `...`.
6526 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6527 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6530 // Indicate that this node is a static literal (i.e., can be compiled with
6531 // a putobject in CRuby) if the left and right are implicit nil, explicit
6532 // nil, or integers.
6534 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6535 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6537 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6540 *node = (pm_range_node_t) {
6542 .type = PM_RANGE_NODE,
6544 .node_id = PM_NODE_IDENTIFY(parser),
6546 .start = (left == NULL ? operator->start : left->location.start),
6547 .end = (right == NULL ? operator->end : right->location.end)
6552 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6561 static pm_redo_node_t *
6562 pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6563 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6564 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6566 *node = (pm_redo_node_t) {{
6567 .type = PM_REDO_NODE,
6568 .node_id = PM_NODE_IDENTIFY(parser),
6569 .location = PM_LOCATION_TOKEN_VALUE(token)
6579 static pm_regular_expression_node_t *
6580 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) {
6581 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6583 *node = (pm_regular_expression_node_t) {
6585 .type = PM_REGULAR_EXPRESSION_NODE,
6586 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6587 .node_id = PM_NODE_IDENTIFY(parser),
6589 .start = MIN(opening->start, closing->start),
6590 .end = MAX(opening->end, closing->end)
6593 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6594 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6595 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6596 .unescaped = *unescaped
6605 static inline pm_regular_expression_node_t *
6606 pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6607 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6613 static pm_required_parameter_node_t *
6614 pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6615 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6617 *node = (pm_required_parameter_node_t) {
6619 .type = PM_REQUIRED_PARAMETER_NODE,
6620 .node_id = PM_NODE_IDENTIFY(parser),
6621 .location = PM_LOCATION_TOKEN_VALUE(token)
6623 .name = pm_parser_constant_id_token(parser, token)
6632 static pm_rescue_modifier_node_t *
6633 pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6634 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6636 *node = (pm_rescue_modifier_node_t) {
6638 .type = PM_RESCUE_MODIFIER_NODE,
6639 .node_id = PM_NODE_IDENTIFY(parser),
6641 .start = expression->location.start,
6642 .end = rescue_expression->location.end
6645 .expression = expression,
6646 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6647 .rescue_expression = rescue_expression
6656 static pm_rescue_node_t *
6657 pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6658 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6660 *node = (pm_rescue_node_t) {
6662 .type = PM_RESCUE_NODE,
6663 .node_id = PM_NODE_IDENTIFY(parser),
6664 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6666 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6667 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6678 pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6679 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6686 pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6687 node->reference = reference;
6688 node->base.location.end = reference->location.end;
6695 pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6696 node->statements = statements;
6697 if (pm_statements_node_body_length(statements) > 0) {
6698 node->base.location.end = statements->base.location.end;
6706 pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6707 node->subsequent = subsequent;
6708 node->base.location.end = subsequent->base.location.end;
6715 pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6716 pm_node_list_append(&node->exceptions, exception);
6717 node->base.location.end = exception->location.end;
6723 static pm_rest_parameter_node_t *
6724 pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6725 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6727 *node = (pm_rest_parameter_node_t) {
6729 .type = PM_REST_PARAMETER_NODE,
6730 .node_id = PM_NODE_IDENTIFY(parser),
6732 .start = operator->start,
6733 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6736 .name = pm_parser_optional_constant_id_token(parser, name),
6737 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6738 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6747 static pm_retry_node_t *
6748 pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6749 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6750 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6752 *node = (pm_retry_node_t) {{
6753 .type = PM_RETRY_NODE,
6754 .node_id = PM_NODE_IDENTIFY(parser),
6755 .location = PM_LOCATION_TOKEN_VALUE(token)
6764 static pm_return_node_t *
6765 pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6766 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6768 *node = (pm_return_node_t) {
6770 .type = PM_RETURN_NODE,
6771 .node_id = PM_NODE_IDENTIFY(parser),
6773 .start = keyword->start,
6774 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6777 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6778 .arguments = arguments
6787 static pm_self_node_t *
6788 pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6789 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6790 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6792 *node = (pm_self_node_t) {{
6793 .type = PM_SELF_NODE,
6794 .node_id = PM_NODE_IDENTIFY(parser),
6795 .location = PM_LOCATION_TOKEN_VALUE(token)
6804 static pm_shareable_constant_node_t *
6805 pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6806 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6808 *node = (pm_shareable_constant_node_t) {
6810 .type = PM_SHAREABLE_CONSTANT_NODE,
6811 .flags = (pm_node_flags_t) value,
6812 .node_id = PM_NODE_IDENTIFY(parser),
6813 .location = PM_LOCATION_NODE_VALUE(write)
6824 static pm_singleton_class_node_t *
6825 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) {
6826 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6828 *node = (pm_singleton_class_node_t) {
6830 .type = PM_SINGLETON_CLASS_NODE,
6831 .node_id = PM_NODE_IDENTIFY(parser),
6833 .start = class_keyword->start,
6834 .end = end_keyword->end
6838 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6839 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6840 .expression = expression,
6842 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6851 static pm_source_encoding_node_t *
6852 pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6853 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6854 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6856 *node = (pm_source_encoding_node_t) {{
6857 .type = PM_SOURCE_ENCODING_NODE,
6858 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6859 .node_id = PM_NODE_IDENTIFY(parser),
6860 .location = PM_LOCATION_TOKEN_VALUE(token)
6869 static pm_source_file_node_t*
6870 pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6871 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6872 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6874 pm_node_flags_t flags = 0;
6876 switch (parser->frozen_string_literal) {
6877 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6878 flags |= PM_STRING_FLAGS_MUTABLE;
6880 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6881 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6885 *node = (pm_source_file_node_t) {
6887 .type = PM_SOURCE_FILE_NODE,
6889 .node_id = PM_NODE_IDENTIFY(parser),
6890 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6892 .filepath = parser->filepath
6901 static pm_source_line_node_t *
6902 pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6903 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6904 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6906 *node = (pm_source_line_node_t) {{
6907 .type = PM_SOURCE_LINE_NODE,
6908 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6909 .node_id = PM_NODE_IDENTIFY(parser),
6910 .location = PM_LOCATION_TOKEN_VALUE(token)
6919 static pm_splat_node_t *
6920 pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6921 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6923 *node = (pm_splat_node_t) {
6925 .type = PM_SPLAT_NODE,
6926 .node_id = PM_NODE_IDENTIFY(parser),
6928 .start = operator->start,
6929 .end = (expression == NULL ? operator->end : expression->location.end)
6932 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6933 .expression = expression
6942 static pm_statements_node_t *
6943 pm_statements_node_create(pm_parser_t *parser) {
6944 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6946 *node = (pm_statements_node_t) {
6948 .type = PM_STATEMENTS_NODE,
6949 .node_id = PM_NODE_IDENTIFY(parser),
6950 .location = PM_LOCATION_NULL_VALUE(parser)
6962 pm_statements_node_body_length(pm_statements_node_t *node) {
6963 return node && node->body.size;
6970 pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6971 node->base.location = (pm_location_t) { .start = start, .end = end };
6979 pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6980 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6981 node->base.location.start = statement->location.start;
6984 if (statement->location.end > node->base.location.end) {
6985 node->base.location.end = statement->location.end;
6993 pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6994 pm_statements_node_body_update(node, statement);
6996 if (node->body.size > 0) {
6997 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6999 switch (PM_NODE_TYPE(previous)) {
7004 case PM_RETURN_NODE:
7005 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7012 pm_node_list_append(&node->body, statement);
7013 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7020 pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7021 pm_statements_node_body_update(node, statement);
7022 pm_node_list_prepend(&node->body, statement);
7023 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7029 static inline pm_string_node_t *
7030 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) {
7031 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7032 pm_node_flags_t flags = 0;
7034 switch (parser->frozen_string_literal) {
7035 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7036 flags = PM_STRING_FLAGS_MUTABLE;
7038 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7039 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7043 *node = (pm_string_node_t) {
7045 .type = PM_STRING_NODE,
7047 .node_id = PM_NODE_IDENTIFY(parser),
7049 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7050 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7053 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7054 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7055 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7056 .unescaped = *string
7065 static pm_string_node_t *
7066 pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7067 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7074 static pm_string_node_t *
7075 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) {
7076 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7077 parser->current_string = PM_STRING_EMPTY;
7084 static pm_super_node_t *
7085 pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7086 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7087 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7089 const uint8_t *end = pm_arguments_end(arguments);
7091 assert(false && "unreachable");
7094 *node = (pm_super_node_t) {
7096 .type = PM_SUPER_NODE,
7097 .node_id = PM_NODE_IDENTIFY(parser),
7099 .start = keyword->start,
7103 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7104 .lparen_loc = arguments->opening_loc,
7105 .arguments = arguments->arguments,
7106 .rparen_loc = arguments->closing_loc,
7107 .block = arguments->block
7118 pm_ascii_only_p(const pm_string_t *contents) {
7119 const size_t length = pm_string_length(contents);
7120 const uint8_t *source = pm_string_source(contents);
7122 for (size_t index = 0; index < length; index++) {
7123 if (source[index] & 0x80) return false;
7133 parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7134 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7135 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7138 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7151 parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7152 const pm_encoding_t *encoding = parser->encoding;
7154 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7155 size_t width = encoding->char_width(cursor, end - cursor);
7158 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7175 static inline pm_node_flags_t
7176 parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7177 if (parser->explicit_encoding != NULL) {
7178 // A Symbol may optionally have its encoding explicitly set. This will
7179 // happen if an escape sequence results in a non-ASCII code point.
7180 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7181 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7182 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7183 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7184 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7185 } else if (validate) {
7186 parse_symbol_encoding_validate_other(parser, location, contents);
7188 } else if (pm_ascii_only_p(contents)) {
7189 // Ruby stipulates that all source files must use an ASCII-compatible
7190 // encoding. Thus, all symbols appearing in source are eligible for
7191 // "downgrading" to US-ASCII.
7192 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7193 } else if (validate) {
7194 parse_symbol_encoding_validate_other(parser, location, contents);
7200 static pm_node_flags_t
7201 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) {
7202 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7203 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7204 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7205 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7207 // There's special validation logic used if a string does not contain any character escape sequences.
7208 if (parser->explicit_encoding == NULL) {
7209 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7210 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7211 // the US-ASCII encoding.
7213 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7216 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7218 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7220 } else if (parser->encoding != modifier_encoding) {
7221 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7223 if (modifier == 'n' && !ascii_only) {
7224 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));
7231 // 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.
7232 bool mixed_encoding = false;
7234 if (mixed_encoding) {
7235 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7236 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7237 // 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.
7238 bool valid_string_in_modifier_encoding = true;
7240 if (!valid_string_in_modifier_encoding) {
7241 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 != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7244 // 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.
7245 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7246 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));
7250 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7260 static pm_node_flags_t
7261 parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7262 // 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.
7263 bool valid_unicode_range = true;
7264 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7265 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));
7269 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7270 // to multi-byte characters are allowed.
7271 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7272 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7273 // following error message appearing twice. We do the same for compatibility.
7274 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7285 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7286 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7289 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7290 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7293 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7294 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7297 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7298 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7301 // At this point no encoding modifiers will be present on the regular expression as they would have already
7302 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7303 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7305 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7308 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7309 // or by specifying a modifier.
7311 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7312 if (parser->explicit_encoding != NULL) {
7313 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7314 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7315 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7316 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7327 static pm_symbol_node_t *
7328 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) {
7329 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7331 *node = (pm_symbol_node_t) {
7333 .type = PM_SYMBOL_NODE,
7334 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7335 .node_id = PM_NODE_IDENTIFY(parser),
7337 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7338 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7341 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7342 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7343 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7344 .unescaped = *unescaped
7353 static inline pm_symbol_node_t *
7354 pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7355 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7361 static pm_symbol_node_t *
7362 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) {
7363 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));
7364 parser->current_string = PM_STRING_EMPTY;
7371 static pm_symbol_node_t *
7372 pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7373 pm_symbol_node_t *node;
7375 switch (token->type) {
7376 case PM_TOKEN_LABEL: {
7377 pm_token_t opening = not_provided(parser);
7378 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7380 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7381 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7383 assert((label.end - label.start) >= 0);
7384 pm_string_shared_init(&node->unescaped, label.start, label.end);
7385 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7389 case PM_TOKEN_MISSING: {
7390 pm_token_t opening = not_provided(parser);
7391 pm_token_t closing = not_provided(parser);
7393 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7394 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7398 assert(false && "unreachable");
7409 static pm_symbol_node_t *
7410 pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7411 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7413 *node = (pm_symbol_node_t) {
7415 .type = PM_SYMBOL_NODE,
7416 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7417 .node_id = PM_NODE_IDENTIFY(parser),
7418 .location = PM_LOCATION_NULL_VALUE(parser)
7420 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7424 pm_string_constant_init(&node->unescaped, content, strlen(content));
7432 pm_symbol_node_label_p(pm_node_t *node) {
7433 const uint8_t *end = NULL;
7435 switch (PM_NODE_TYPE(node)) {
7436 case PM_SYMBOL_NODE:
7437 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7439 case PM_INTERPOLATED_SYMBOL_NODE:
7440 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7446 return (end != NULL) && (end[-1] == ':');
7452 static pm_symbol_node_t *
7453 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) {
7454 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7456 *new_node = (pm_symbol_node_t) {
7458 .type = PM_SYMBOL_NODE,
7459 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7460 .node_id = PM_NODE_IDENTIFY(parser),
7462 .start = opening->start,
7466 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7467 .value_loc = node->content_loc,
7468 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7469 .unescaped = node->unescaped
7472 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7473 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7475 // We are explicitly _not_ using pm_node_destroy here because we don't want
7476 // to trash the unescaped string. We could instead copy the string if we
7477 // know that it is owned, but we're taking the fast path for now.
7486 static pm_string_node_t *
7487 pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7488 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7489 pm_node_flags_t flags = 0;
7491 switch (parser->frozen_string_literal) {
7492 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7493 flags = PM_STRING_FLAGS_MUTABLE;
7495 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7496 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7500 *new_node = (pm_string_node_t) {
7502 .type = PM_STRING_NODE,
7504 .node_id = PM_NODE_IDENTIFY(parser),
7505 .location = node->base.location
7507 .opening_loc = node->opening_loc,
7508 .content_loc = node->value_loc,
7509 .closing_loc = node->closing_loc,
7510 .unescaped = node->unescaped
7513 // We are explicitly _not_ using pm_node_destroy here because we don't want
7514 // to trash the unescaped string. We could instead copy the string if we
7515 // know that it is owned, but we're taking the fast path for now.
7524 static pm_true_node_t *
7525 pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7526 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7527 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7529 *node = (pm_true_node_t) {{
7530 .type = PM_TRUE_NODE,
7531 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7532 .node_id = PM_NODE_IDENTIFY(parser),
7533 .location = PM_LOCATION_TOKEN_VALUE(token)
7542 static pm_true_node_t *
7543 pm_true_node_synthesized_create(pm_parser_t *parser) {
7544 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7546 *node = (pm_true_node_t) {{
7547 .type = PM_TRUE_NODE,
7548 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7549 .node_id = PM_NODE_IDENTIFY(parser),
7550 .location = { .start = parser->start, .end = parser->end }
7559 static pm_undef_node_t *
7560 pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7561 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7562 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7564 *node = (pm_undef_node_t) {
7566 .type = PM_UNDEF_NODE,
7567 .node_id = PM_NODE_IDENTIFY(parser),
7568 .location = PM_LOCATION_TOKEN_VALUE(token),
7570 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7581 pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7582 node->base.location.end = name->location.end;
7583 pm_node_list_append(&node->names, name);
7589 static pm_unless_node_t *
7590 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) {
7591 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7592 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7595 if (statements != NULL) {
7596 end = statements->base.location.end;
7598 end = predicate->location.end;
7601 *node = (pm_unless_node_t) {
7603 .type = PM_UNLESS_NODE,
7604 .flags = PM_NODE_FLAG_NEWLINE,
7605 .node_id = PM_NODE_IDENTIFY(parser),
7607 .start = keyword->start,
7611 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7612 .predicate = predicate,
7613 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7614 .statements = statements,
7615 .else_clause = NULL,
7616 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7625 static pm_unless_node_t *
7626 pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7627 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7628 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7630 pm_statements_node_t *statements = pm_statements_node_create(parser);
7631 pm_statements_node_body_append(parser, statements, statement, true);
7633 *node = (pm_unless_node_t) {
7635 .type = PM_UNLESS_NODE,
7636 .flags = PM_NODE_FLAG_NEWLINE,
7637 .node_id = PM_NODE_IDENTIFY(parser),
7639 .start = statement->location.start,
7640 .end = predicate->location.end
7643 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7644 .predicate = predicate,
7645 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7646 .statements = statements,
7647 .else_clause = NULL,
7648 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7655 pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7656 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7657 node->base.location.end = end_keyword->end;
7666 pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7667 assert(parser->current_block_exits != NULL);
7669 // All of the block exits that we want to remove should be within the
7670 // statements, and since we are modifying the statements, we shouldn't have
7671 // to check the end location.
7672 const uint8_t *start = statements->base.location.start;
7674 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7675 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7676 if (block_exit->location.start < start) break;
7678 // Implicitly remove from the list by lowering the size.
7679 parser->current_block_exits->size--;
7686 static pm_until_node_t *
7687 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) {
7688 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7689 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7691 *node = (pm_until_node_t) {
7693 .type = PM_UNTIL_NODE,
7695 .node_id = PM_NODE_IDENTIFY(parser),
7697 .start = keyword->start,
7698 .end = closing->end,
7701 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7702 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7703 .predicate = predicate,
7704 .statements = statements
7713 static pm_until_node_t *
7714 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) {
7715 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7716 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7717 pm_loop_modifier_block_exits(parser, statements);
7719 *node = (pm_until_node_t) {
7721 .type = PM_UNTIL_NODE,
7723 .node_id = PM_NODE_IDENTIFY(parser),
7725 .start = statements->base.location.start,
7726 .end = predicate->location.end,
7729 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7730 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7731 .predicate = predicate,
7732 .statements = statements
7741 static pm_when_node_t *
7742 pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7743 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7745 *node = (pm_when_node_t) {
7747 .type = PM_WHEN_NODE,
7748 .node_id = PM_NODE_IDENTIFY(parser),
7750 .start = keyword->start,
7754 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7756 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7767 pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7768 node->base.location.end = condition->location.end;
7769 pm_node_list_append(&node->conditions, condition);
7776 pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7777 node->base.location.end = then_keyword->end;
7778 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7785 pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7786 if (statements->base.location.end > node->base.location.end) {
7787 node->base.location.end = statements->base.location.end;
7790 node->statements = statements;
7796 static pm_while_node_t *
7797 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) {
7798 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7799 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7801 *node = (pm_while_node_t) {
7803 .type = PM_WHILE_NODE,
7805 .node_id = PM_NODE_IDENTIFY(parser),
7807 .start = keyword->start,
7811 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7812 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7813 .predicate = predicate,
7814 .statements = statements
7823 static pm_while_node_t *
7824 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) {
7825 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7826 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7827 pm_loop_modifier_block_exits(parser, statements);
7829 *node = (pm_while_node_t) {
7831 .type = PM_WHILE_NODE,
7833 .node_id = PM_NODE_IDENTIFY(parser),
7835 .start = statements->base.location.start,
7836 .end = predicate->location.end
7839 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7840 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7841 .predicate = predicate,
7842 .statements = statements
7851 static pm_while_node_t *
7852 pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7853 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7855 *node = (pm_while_node_t) {
7857 .type = PM_WHILE_NODE,
7858 .node_id = PM_NODE_IDENTIFY(parser),
7859 .location = PM_LOCATION_NULL_VALUE(parser)
7861 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7862 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7863 .predicate = predicate,
7864 .statements = statements
7874 static pm_x_string_node_t *
7875 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) {
7876 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7878 *node = (pm_x_string_node_t) {
7880 .type = PM_X_STRING_NODE,
7881 .flags = PM_STRING_FLAGS_FROZEN,
7882 .node_id = PM_NODE_IDENTIFY(parser),
7884 .start = opening->start,
7888 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7889 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7890 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7891 .unescaped = *unescaped
7900 static inline pm_x_string_node_t *
7901 pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7902 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7908 static pm_yield_node_t *
7909 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) {
7910 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7913 if (rparen_loc->start != NULL) {
7914 end = rparen_loc->end;
7915 } else if (arguments != NULL) {
7916 end = arguments->base.location.end;
7917 } else if (lparen_loc->start != NULL) {
7918 end = lparen_loc->end;
7923 *node = (pm_yield_node_t) {
7925 .type = PM_YIELD_NODE,
7926 .node_id = PM_NODE_IDENTIFY(parser),
7928 .start = keyword->start,
7932 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7933 .lparen_loc = *lparen_loc,
7934 .arguments = arguments,
7935 .rparen_loc = *rparen_loc
7941 #undef PM_NODE_ALLOC
7942 #undef PM_NODE_IDENTIFY
7949 pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7950 pm_scope_t *scope = parser->current_scope;
7953 while (scope != NULL) {
7954 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7955 if (scope->closed) break;
7957 scope = scope->previous;
7970 pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7971 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7978 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) {
7979 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7985 static pm_constant_id_t
7986 pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7987 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7988 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7995 static inline pm_constant_id_t
7996 pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7997 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8003 static pm_constant_id_t
8004 pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8005 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8006 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8013 static pm_constant_id_t
8014 pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8015 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8016 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8028 pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8029 // We want to check whether the parameter name is a numbered parameter or
8031 pm_refute_numbered_parameter(parser, name->start, name->end);
8033 // Otherwise we'll fetch the constant id for the parameter name and check
8034 // whether it's already in the current scope.
8035 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8037 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8038 // Add an error if the parameter doesn't start with _ and has been seen before
8039 if ((name->start < name->end) && (*name->start != '_')) {
8040 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8051 pm_parser_scope_pop(pm_parser_t *parser) {
8052 pm_scope_t *scope = parser->current_scope;
8053 parser->current_scope = scope->previous;
8054 pm_locals_free(&scope->locals);
8055 pm_node_list_free(&scope->implicit_parameters);
8059 /******************************************************************************/
8061 /******************************************************************************/
8067 pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8068 *stack = (*stack << 1) | (value & 1);
8075 pm_state_stack_pop(pm_state_stack_t *stack) {
8083 pm_state_stack_p(const pm_state_stack_t *stack) {
8088 pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8089 // Use the negation of the value to prevent stack overflow.
8090 pm_state_stack_push(&parser->accepts_block_stack, !value);
8094 pm_accepts_block_stack_pop(pm_parser_t *parser) {
8095 pm_state_stack_pop(&parser->accepts_block_stack);
8099 pm_accepts_block_stack_p(pm_parser_t *parser) {
8100 return !pm_state_stack_p(&parser->accepts_block_stack);
8104 pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8105 pm_state_stack_push(&parser->do_loop_stack, value);
8109 pm_do_loop_stack_pop(pm_parser_t *parser) {
8110 pm_state_stack_pop(&parser->do_loop_stack);
8114 pm_do_loop_stack_p(pm_parser_t *parser) {
8115 return pm_state_stack_p(&parser->do_loop_stack);
8118 /******************************************************************************/
8119 /* Lexer check helpers */
8120 /******************************************************************************/
8126 static inline uint8_t
8127 peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8128 if (cursor < parser->end) {
8140 static inline uint8_t
8141 peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8142 return peek_at(parser, parser->current.end + offset);
8149 static inline uint8_t
8150 peek(const pm_parser_t *parser) {
8151 return peek_at(parser, parser->current.end);
8159 match(pm_parser_t *parser, uint8_t value) {
8160 if (peek(parser) == value) {
8161 parser->current.end++;
8171 static inline size_t
8172 match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8173 if (peek_at(parser, cursor) == '\n') {
8176 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8187 static inline size_t
8188 match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8189 return match_eol_at(parser, parser->current.end + offset);
8197 static inline size_t
8198 match_eol(pm_parser_t *parser) {
8199 return match_eol_at(parser, parser->current.end);
8205 static inline const uint8_t *
8206 next_newline(const uint8_t *cursor, ptrdiff_t length) {
8207 assert(length >= 0);
8209 // Note that it's okay for us to use memchr here to look for \n because none
8210 // of the encodings that we support have \n as a component of a multi-byte
8212 return memchr(cursor, '\n', (size_t) length);
8219 ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8220 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));
8228 parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8229 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8231 if (encoding != NULL) {
8232 if (parser->encoding != encoding) {
8233 parser->encoding = encoding;
8234 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8237 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8249 parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8250 const uint8_t *cursor = parser->current.start + 1;
8251 const uint8_t *end = parser->current.end;
8253 bool separator = false;
8255 if (end - cursor <= 6) return;
8256 switch (cursor[6]) {
8257 case 'C': case 'c': cursor += 6; continue;
8258 case 'O': case 'o': cursor += 5; continue;
8259 case 'D': case 'd': cursor += 4; continue;
8260 case 'I': case 'i': cursor += 3; continue;
8261 case 'N': case 'n': cursor += 2; continue;
8262 case 'G': case 'g': cursor += 1; continue;
8269 if (pm_char_is_whitespace(*cursor)) break;
8272 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8278 if (++cursor >= end) return;
8279 } while (pm_char_is_whitespace(*cursor));
8281 if (separator) break;
8282 if (*cursor != '=' && *cursor != ':') return;
8288 const uint8_t *value_start = cursor;
8289 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8291 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8292 // If we were unable to parse the encoding value, then we've got an
8293 // issue because we didn't understand the encoding that the user was
8294 // trying to use. In this case we'll keep using the default encoding but
8295 // add an error to the parser to indicate an unsuccessful parse.
8296 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8301 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8302 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8303 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8304 } pm_magic_comment_boolean_value_t;
8310 static pm_magic_comment_boolean_value_t
8311 parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8312 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8313 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8314 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8315 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8317 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8322 pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8323 return b == '\'' || b == '"' || b == ':' || b == ';';
8331 static inline const uint8_t *
8332 parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8334 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8353 parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8356 const uint8_t *start = parser->
current.start + 1;
8357 const uint8_t *end = parser->
current.end;
8358 if (end - start <= 7)
return false;
8360 const uint8_t *cursor;
8361 bool indicator =
false;
8363 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8366 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8377 while (cursor < end) {
8378 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) ||
pm_char_is_whitespace(*cursor))) cursor++;
8380 const uint8_t *key_start = cursor;
8381 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !
pm_char_is_whitespace(*cursor))) cursor++;
8383 const uint8_t *key_end = cursor;
8385 if (cursor == end)
break;
8387 if (*cursor ==
':') {
8390 if (!indicator)
return false;
8395 if (cursor == end)
break;
8397 const uint8_t *value_start;
8398 const uint8_t *value_end;
8400 if (*cursor ==
'"') {
8401 value_start = ++cursor;
8402 for (; cursor < end && *cursor !=
'"'; cursor++) {
8403 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8406 if (*cursor ==
'"') cursor++;
8408 value_start = cursor;
8409 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !
pm_char_is_whitespace(*cursor)) cursor++;
8417 if (cursor != end)
return false;
8423 const size_t key_length = (size_t) (key_end - key_start);
8429 uint8_t *buffer =
xmalloc(key_length);
8430 if (buffer == NULL)
break;
8432 memcpy(buffer, key_start, key_length);
8433 buffer[dash - key_start] =
'_';
8436 buffer[dash - key_start] =
'_';
8445 uint32_t value_length = (uint32_t) (value_end - value_start);
8451 (key_length == 8 &&
pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8452 (key_length == 6 &&
pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8454 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8458 if (key_length == 11) {
8459 if (
pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8460 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8461 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8462 PM_PARSER_WARN_TOKEN_FORMAT(
8465 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8467 (
const char *) key_source,
8469 (
const char *) value_start
8472 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8475 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8480 }
else if (key_length == 21) {
8481 if (
pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8484 if (semantic_token_seen) {
8485 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8487 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8488 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8489 PM_PARSER_WARN_TOKEN_FORMAT(
8492 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8494 (
const char *) key_source,
8496 (
const char *) value_start
8499 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8502 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8508 }
else if (key_length == 24) {
8509 if (
pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8510 const uint8_t *cursor = parser->
current.start;
8511 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8513 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8514 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8515 }
else if (value_length == 4 &&
pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8516 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8517 }
else if (value_length == 7 &&
pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8518 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8519 }
else if (value_length == 23 &&
pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8520 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8521 }
else if (value_length == 17 &&
pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8522 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8524 PM_PARSER_WARN_TOKEN_FORMAT(
8527 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8529 (
const char *) key_source,
8531 (
const char *) value_start
8648 while (context_node != NULL) {
8649 if (context_terminator(context_node->
context, token))
return context_node->
context;
8650 context_node = context_node->
prev;
8659 if (context_node == NULL)
return false;
8684 while (context_node != NULL) {
8685 if (context_node->
context == context)
return true;
8686 context_node = context_node->
prev;
8696 while (context_node != NULL) {
8697 switch (context_node->
context) {
8718 context_node = context_node->
prev;
8733 assert(
false &&
"unreachable");
8790 assert(
false &&
"unreachable");
8799 pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8800 if (invalid != NULL) {
8801 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8802 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8807 pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8808 const uint8_t *invalid = NULL;
8810 pm_strspn_number_validate(parser,
string, length, invalid);
8815 pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8816 const uint8_t *invalid = NULL;
8818 pm_strspn_number_validate(parser,
string, length, invalid);
8823 pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8824 const uint8_t *invalid = NULL;
8826 pm_strspn_number_validate(parser,
string, length, invalid);
8831 pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8832 const uint8_t *invalid = NULL;
8834 pm_strspn_number_validate(parser,
string, length, invalid);
8839 lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8844 if (peek(parser) ==
'.') {
8847 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8858 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8859 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8864 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8866 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8870 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8883 lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8887 if (peek_offset(parser, -1) ==
'0') {
8888 switch (*parser->
current.end) {
8894 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8897 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8907 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8910 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8921 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8924 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8940 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8949 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8952 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8960 type = lex_optional_float_suffix(parser, seen_e);
8967 type = lex_optional_float_suffix(parser, seen_e);
8974 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8977 type = lex_optional_float_suffix(parser, seen_e);
8984 const uint8_t *fraction_start = parser->
current.end;
8985 const uint8_t *fraction_end = parser->
current.end + 2;
8987 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
8999 bool seen_e =
false;
9000 type = lex_numeric_prefix(parser, &seen_e);
9002 const uint8_t *end = parser->
current.end;
9006 if (match(parser,
'r')) {
9009 if (match(parser,
'i')) {
9012 }
else if (match(parser,
'i')) {
9016 if (!seen_e && match(parser,
'r')) {
9019 if (match(parser,
'i')) {
9022 }
else if (match(parser,
'i')) {
9027 const uint8_t b = peek(parser);
9028 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9041 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9047 bool allow_multiple =
true;
9049 switch (*parser->
current.end) {
9080 if (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0) {
9083 }
while (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0);
9087 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9107 allow_multiple =
false;
9112 if ((width = char_is_identifier(parser, parser->
current.end)) > 0) {
9115 }
while (allow_multiple && parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0);
9119 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9125 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9147 if (memcmp(current_start, value, vlen) == 0) {
9150 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9151 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9153 lex_state_set(parser, state);
9154 if (state == PM_LEX_STATE_BEG) {
9158 if ((modifier_type !=
PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9159 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9160 return modifier_type;
9171 lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9174 const uint8_t *end = parser->
end;
9175 const uint8_t *current_start = parser->
current.start;
9176 const uint8_t *current_end = parser->
current.end;
9179 if (encoding_changed) {
9180 while (current_end < end && (width = char_is_identifier(parser, current_end)) > 0) {
9181 current_end += width;
9184 while (current_end < end && (width = char_is_identifier_utf8(current_end, end)) > 0) {
9185 current_end += width;
9188 parser->
current.end = current_end;
9192 width = (size_t) (current_end - current_start);
9194 if (current_end < end) {
9195 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9201 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9202 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9206 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9207 (void) match(parser,
':');
9211 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9220 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,
'=')) {
9227 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9228 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9232 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9233 (void) match(parser,
':');
9238 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9243 if (pm_do_loop_stack_p(parser)) {
9304 if (encoding_changed) {
9334 lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9337 if (pound + 1 >= parser->
end) {
9338 parser->
current.end = pound + 1;
9348 if (pound + 2 >= parser->
end) {
9349 parser->
current.end = pound + 1;
9355 const uint8_t *variable = pound + 2;
9356 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9358 if (char_is_identifier_start(parser, variable)) {
9362 if (pound > parser->
current.start) {
9369 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9370 parser->
current.end = pound + 1;
9377 parser->
current.end = pound + 1;
9383 if (pound + 2 >= parser->
end) {
9384 parser->
current.end = pound + 1;
9391 const uint8_t *check = pound + 2;
9393 if (pound[2] ==
'-') {
9394 if (pound + 3 >= parser->
end) {
9395 parser->
current.end = pound + 2;
9407 char_is_identifier_start(parser, check) ||
9413 if (pound > parser->
current.start) {
9420 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9421 parser->
current.end = pound + 1;
9427 parser->
current.end = pound + 1;
9433 if (pound > parser->
current.start) {
9442 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9443 parser->
current.end = pound + 2;
9445 pm_do_loop_stack_push(parser,
false);
9451 parser->
current.end = pound + 1;
9456 static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9457 static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9458 static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9459 static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9460 static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9465 static const bool ascii_printable_chars[] = {
9466 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9467 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9468 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9469 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9470 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9471 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9472 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9473 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9477 char_is_ascii_printable(
const uint8_t b) {
9478 return (b < 0x80) && ascii_printable_chars[b];
9485 static inline uint8_t
9486 escape_hexadecimal_digit(
const uint8_t value) {
9487 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9495 static inline uint32_t
9496 escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9498 for (
size_t index = 0; index < length; index++) {
9499 if (index != 0) value <<= 4;
9500 value |= escape_hexadecimal_digit(
string[index]);
9505 if (value >= 0xD800 && value <= 0xDFFF) {
9506 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9516 static inline uint8_t
9517 escape_byte(uint8_t value,
const uint8_t flags) {
9518 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9519 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9527 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) {
9531 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9539 if (value <= 0x7F) {
9541 }
else if (value <= 0x7FF) {
9544 }
else if (value <= 0xFFFF) {
9548 }
else if (value <= 0x10FFFF) {
9554 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9569 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9592 width = (width == 0) ? 1 : width;
9594 for (
size_t index = 0; index < width; index++) {
9595 escape_write_byte_encoded(parser, buffer, *parser->
current.end);
9617 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9621 escape_write_byte_encoded(parser, buffer,
byte);
9630 escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9631 #define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9633 PM_PARSER_WARN_TOKEN_FORMAT(
9636 PM_WARN_INVALID_CHARACTER,
9650 switch (peek(parser)) {
9653 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9658 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9663 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9668 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9673 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9678 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9683 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9688 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9693 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9698 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9703 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9706 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9707 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9711 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9715 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9720 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9724 const uint8_t *start = parser->
current.end - 1;
9727 uint8_t
byte = peek(parser);
9730 uint8_t value = escape_hexadecimal_digit(
byte);
9733 byte = peek(parser);
9735 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9739 value = escape_byte(value, flags);
9740 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9741 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9748 escape_write_byte_encoded(parser, buffer, value);
9750 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9756 const uint8_t *start = parser->
current.end - 1;
9760 const uint8_t *start = parser->
current.end - 2;
9761 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9762 }
else if (peek(parser) ==
'{') {
9763 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9769 parser->
current.end += whitespace;
9770 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9781 const uint8_t *extra_codepoints_start = NULL;
9782 int codepoints_count = 0;
9785 const uint8_t *unicode_start = parser->
current.end;
9788 if (hexadecimal_length > 6) {
9790 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9791 }
else if (hexadecimal_length == 0) {
9794 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9800 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9801 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9807 parser->
current.end += hexadecimal_length;
9809 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9810 extra_codepoints_start = unicode_start;
9813 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9814 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9821 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9822 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9826 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9827 }
else if (peek(parser) ==
'}') {
9830 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9836 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9840 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9847 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9850 const uint8_t *start = parser->
current.end - 2;
9851 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9853 }
else if (length == 4) {
9854 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9856 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9860 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9863 parser->
current.end += length;
9865 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9871 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9880 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9881 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9885 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9889 uint8_t peeked = peek(parser);
9893 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9899 if (match(parser,
'u') || match(parser,
'U')) {
9900 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9904 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9908 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9909 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9913 escape_read_warn(parser, flags, 0,
"\\t");
9914 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9917 if (!char_is_ascii_printable(peeked)) {
9918 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9923 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9930 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9931 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9934 if (peek(parser) !=
'-') {
9936 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9942 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9946 uint8_t peeked = peek(parser);
9950 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9956 if (match(parser,
'u') || match(parser,
'U')) {
9957 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9961 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9965 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9966 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9970 escape_read_warn(parser, flags, 0,
"\\t");
9971 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9974 if (!char_is_ascii_printable(peeked)) {
9976 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9981 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9988 if (flags & PM_ESCAPE_FLAG_META) {
9989 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9992 if (peek(parser) !=
'-') {
9994 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10000 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10004 uint8_t peeked = peek(parser);
10009 if (match(parser,
'u') || match(parser,
'U')) {
10010 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10014 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10018 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10019 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10023 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10024 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10027 if (!char_is_ascii_printable(peeked)) {
10029 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10034 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10039 if (peek_offset(parser, 1) ==
'\n') {
10041 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10048 escape_write_escape_encoded(parser, buffer);
10050 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10084 if (lex_state_end_p(parser)) {
10085 lex_state_set(parser, PM_LEX_STATE_BEG);
10090 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10096 lex_state_set(parser, PM_LEX_STATE_BEG);
10100 lex_state_set(parser, PM_LEX_STATE_BEG);
10102 if (match(parser,
'\\')) {
10103 lex_state_set(parser, PM_LEX_STATE_END);
10108 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10120 (parser->
current.end + encoding_width >= parser->
end) ||
10121 !char_is_identifier(parser, parser->
current.end + encoding_width)
10124 lex_state_set(parser, PM_LEX_STATE_END);
10125 parser->
current.end += encoding_width;
10143 if (parser->
current.end < parser->
end && (width = char_is_identifier_start(parser, parser->
current.end)) > 0) {
10144 parser->
current.end += width;
10146 while (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0) {
10147 parser->
current.end += width;
10156 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10159 pm_parser_err_token(parser, &parser->
current, diag_id);
10165 lex_mode_pop(parser);
10187 if (comment == NULL)
return NULL;
10205 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10207 if (newline == NULL) {
10211 parser->
current.end = newline + 1;
10215 parser_lex_callback(parser);
10218 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10223 while (parser->
current.end + 4 <= parser->
end) {
10229 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10233 (parser->
current.end[4] ==
'\0') ||
10234 (parser->
current.end[4] ==
'\004') ||
10235 (parser->
current.end[4] ==
'\032')
10238 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10240 if (newline == NULL) {
10244 parser->
current.end = newline + 1;
10248 parser_lex_callback(parser);
10258 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10260 if (newline == NULL) {
10264 parser->
current.end = newline + 1;
10268 parser_lex_callback(parser);
10271 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10285 parser_lex_ignored_newline(
pm_parser_t *parser) {
10287 parser_lex_callback(parser);
10310 parser_end_of_line_p(
const pm_parser_t *parser) {
10311 const uint8_t *cursor = parser->
current.end;
10313 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10388 static inline size_t
10399 return (width == 0 ? 1 : width);
10407 size_t width = parser_char_width(parser);
10409 parser->
current.end += width;
10414 size_t width = parser_char_width(parser);
10417 parser->
current.end += width;
10421 pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10422 for (
size_t index = 0; index < length; index++) {
10423 if (value[index] & 0x80)
return false;
10458 if (token_buffer->
cursor == NULL) {
10462 pm_token_buffer_copy(parser, token_buffer);
10474 pm_regexp_token_buffer_copy(parser, token_buffer);
10478 #define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10490 const uint8_t *start;
10491 if (token_buffer->
cursor == NULL) {
10493 start = parser->
current.start;
10495 start = token_buffer->
cursor;
10498 const uint8_t *end = parser->
current.end - 1;
10501 token_buffer->
cursor = end;
10506 const uint8_t *start;
10510 start = parser->
current.start;
10515 const uint8_t *end = parser->
current.end - 1;
10522 #undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10528 static inline size_t
10530 size_t whitespace = 0;
10533 case PM_HEREDOC_INDENT_NONE:
10538 case PM_HEREDOC_INDENT_DASH:
10542 case PM_HEREDOC_INDENT_TILDE:
10546 if (**cursor ==
'\t') {
10547 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10566 size_t eol_length = match_eol(parser);
10573 parser_flush_heredoc_end(parser);
10579 const uint8_t delimiter = *parser->
current.end;
10580 parser->
current.end += eol_length;
10585 return *parser->
current.end++;
10592 #define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10611 bool lexed_comment =
false;
10619 case PM_LEX_DEFAULT:
10620 case PM_LEX_EMBEXPR:
10621 case PM_LEX_EMBVAR:
10637 bool space_seen =
false;
10641 bool chomping =
true;
10642 while (parser->
current.end < parser->
end && chomping) {
10643 switch (*parser->
current.end) {
10652 if (match_eol_offset(parser, 1)) {
10655 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10661 size_t eol_length = match_eol_offset(parser, 1);
10667 parser->
current.end += eol_length + 1;
10696 switch (*parser->
current.end++) {
10704 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10705 parser->
current.end = ending == NULL ? parser->
end : ending;
10710 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10713 if (ending) parser->
current.end++;
10715 parser_lex_callback(parser);
10727 parser_lex_magic_comment_encoding(parser);
10731 lexed_comment =
true;
10737 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10749 if (!lexed_comment) {
10750 parser->
current.end += eol_length - 1;
10759 parser_flush_heredoc_end(parser);
10764 switch (lex_state_ignored_p(parser)) {
10765 case PM_IGNORED_NEWLINE_NONE:
10767 case PM_IGNORED_NEWLINE_PATTERN:
10769 if (!lexed_comment) parser_lex_ignored_newline(parser);
10770 lex_state_set(parser, PM_LEX_STATE_BEG);
10776 case PM_IGNORED_NEWLINE_ALL:
10777 if (!lexed_comment) parser_lex_ignored_newline(parser);
10778 lexed_comment =
false;
10779 goto lex_next_token;
10789 if (next_content < parser->end) {
10795 if (next_content[0] ==
'#') {
10797 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10799 while (following && (following + 1 < parser->
end)) {
10805 if (peek_at(parser, following) !=
'#')
break;
10809 following = next_newline(following, parser->
end - following);
10815 lex_state_ignored_p(parser) ||
10817 (peek_at(parser, following) ==
'.') ||
10818 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10821 if (!lexed_comment) parser_lex_ignored_newline(parser);
10822 lexed_comment =
false;
10823 goto lex_next_token;
10829 if (next_content[0] ==
'.') {
10833 if (peek_at(parser, next_content + 1) ==
'.') {
10834 if (!lexed_comment) parser_lex_ignored_newline(parser);
10835 lex_state_set(parser, PM_LEX_STATE_BEG);
10841 if (!lexed_comment) parser_lex_ignored_newline(parser);
10842 lex_state_set(parser, PM_LEX_STATE_DOT);
10843 parser->
current.start = next_content;
10844 parser->
current.end = next_content + 1;
10851 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10852 if (!lexed_comment) parser_lex_ignored_newline(parser);
10853 lex_state_set(parser, PM_LEX_STATE_DOT);
10854 parser->
current.start = next_content;
10855 parser->
current.end = next_content + 2;
10863 lex_state_set(parser, PM_LEX_STATE_BEG);
10866 if (!lexed_comment) parser_lex_callback(parser);
10872 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10879 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10884 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10885 pm_do_loop_stack_push(parser,
false);
10892 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10893 pm_do_loop_stack_pop(parser);
10898 lex_state_set(parser, PM_LEX_STATE_BEG);
10907 if (lex_state_operator_p(parser)) {
10908 if (match(parser,
']')) {
10910 lex_state_set(parser, PM_LEX_STATE_ARG);
10914 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10918 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10922 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10923 pm_do_loop_stack_push(parser,
false);
10929 lex_state_set(parser, PM_LEX_STATE_END);
10930 pm_do_loop_stack_pop(parser);
10940 lex_state_set(parser, PM_LEX_STATE_BEG);
10942 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10944 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10945 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10948 lex_state_set(parser, PM_LEX_STATE_BEG);
10949 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10952 lex_state_set(parser, PM_LEX_STATE_BEG);
10955 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10960 pm_do_loop_stack_push(parser,
false);
10968 pm_do_loop_stack_pop(parser);
10971 lex_mode_pop(parser);
10976 lex_state_set(parser, PM_LEX_STATE_END);
10981 if (match(parser,
'*')) {
10982 if (match(parser,
'=')) {
10983 lex_state_set(parser, PM_LEX_STATE_BEG);
10989 if (lex_state_spcarg_p(parser, space_seen)) {
10990 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10992 }
else if (lex_state_beg_p(parser)) {
10994 }
else if (ambiguous_operator_p(parser, space_seen)) {
10995 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10998 if (lex_state_operator_p(parser)) {
10999 lex_state_set(parser, PM_LEX_STATE_ARG);
11001 lex_state_set(parser, PM_LEX_STATE_BEG);
11007 if (match(parser,
'=')) {
11008 lex_state_set(parser, PM_LEX_STATE_BEG);
11014 if (lex_state_spcarg_p(parser, space_seen)) {
11015 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11017 }
else if (lex_state_beg_p(parser)) {
11019 }
else if (ambiguous_operator_p(parser, space_seen)) {
11020 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11023 if (lex_state_operator_p(parser)) {
11024 lex_state_set(parser, PM_LEX_STATE_ARG);
11026 lex_state_set(parser, PM_LEX_STATE_BEG);
11034 if (lex_state_operator_p(parser)) {
11035 lex_state_set(parser, PM_LEX_STATE_ARG);
11036 if (match(parser,
'@')) {
11040 lex_state_set(parser, PM_LEX_STATE_BEG);
11043 if (match(parser,
'=')) {
11047 if (match(parser,
'~')) {
11056 current_token_starts_line(parser) &&
11058 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11066 goto lex_next_token;
11069 if (lex_state_operator_p(parser)) {
11070 lex_state_set(parser, PM_LEX_STATE_ARG);
11072 lex_state_set(parser, PM_LEX_STATE_BEG);
11075 if (match(parser,
'>')) {
11079 if (match(parser,
'~')) {
11083 if (match(parser,
'=')) {
11091 if (match(parser,
'<')) {
11093 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11094 !lex_state_end_p(parser) &&
11095 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11097 const uint8_t *end = parser->
current.end;
11102 if (match(parser,
'-')) {
11103 indent = PM_HEREDOC_INDENT_DASH;
11105 else if (match(parser,
'~')) {
11106 indent = PM_HEREDOC_INDENT_TILDE;
11109 if (match(parser,
'`')) {
11110 quote = PM_HEREDOC_QUOTE_BACKTICK;
11112 else if (match(parser,
'"')) {
11113 quote = PM_HEREDOC_QUOTE_DOUBLE;
11115 else if (match(parser,
'\'')) {
11116 quote = PM_HEREDOC_QUOTE_SINGLE;
11119 const uint8_t *ident_start = parser->
current.end;
11124 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end)) == 0) {
11127 if (quote == PM_HEREDOC_QUOTE_NONE) {
11128 parser->
current.end += width;
11130 while ((parser->
current.end < parser->
end) && (width = char_is_identifier(parser, parser->
current.end))) {
11131 parser->
current.end += width;
11137 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11142 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11143 bool ident_error =
false;
11145 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11146 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11147 ident_error =
true;
11152 .mode = PM_LEX_HEREDOC,
11155 .ident_start = ident_start,
11156 .ident_length = ident_length,
11160 .next_start = parser->
current.end,
11162 .line_continuation =
false
11167 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11169 if (body_start == NULL) {
11174 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11175 body_start = parser->
end;
11192 if (match(parser,
'=')) {
11193 lex_state_set(parser, PM_LEX_STATE_BEG);
11197 if (ambiguous_operator_p(parser, space_seen)) {
11198 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11201 if (lex_state_operator_p(parser)) {
11202 lex_state_set(parser, PM_LEX_STATE_ARG);
11204 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11205 lex_state_set(parser, PM_LEX_STATE_BEG);
11211 if (lex_state_operator_p(parser)) {
11212 lex_state_set(parser, PM_LEX_STATE_ARG);
11214 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11215 lex_state_set(parser, PM_LEX_STATE_BEG);
11218 if (match(parser,
'=')) {
11219 if (match(parser,
'>')) {
11230 if (match(parser,
'>')) {
11231 if (lex_state_operator_p(parser)) {
11232 lex_state_set(parser, PM_LEX_STATE_ARG);
11234 lex_state_set(parser, PM_LEX_STATE_BEG);
11239 if (lex_state_operator_p(parser)) {
11240 lex_state_set(parser, PM_LEX_STATE_ARG);
11242 lex_state_set(parser, PM_LEX_STATE_BEG);
11249 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11250 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11256 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11257 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11261 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11262 if (previous_command_start) {
11263 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11265 lex_state_set(parser, PM_LEX_STATE_ARG);
11271 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11277 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11278 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11284 LEX(lex_question_mark(parser));
11288 if (match(parser,
'&')) {
11289 lex_state_set(parser, PM_LEX_STATE_BEG);
11291 if (match(parser,
'=')) {
11298 if (match(parser,
'=')) {
11299 lex_state_set(parser, PM_LEX_STATE_BEG);
11303 if (match(parser,
'.')) {
11304 lex_state_set(parser, PM_LEX_STATE_DOT);
11309 if (lex_state_spcarg_p(parser, space_seen)) {
11310 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11311 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11313 const uint8_t delim = peek_offset(parser, 1);
11315 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1)) {
11316 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11321 }
else if (lex_state_beg_p(parser)) {
11323 }
else if (ambiguous_operator_p(parser, space_seen)) {
11324 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11327 if (lex_state_operator_p(parser)) {
11328 lex_state_set(parser, PM_LEX_STATE_ARG);
11330 lex_state_set(parser, PM_LEX_STATE_BEG);
11338 if (match(parser,
'|')) {
11339 if (match(parser,
'=')) {
11340 lex_state_set(parser, PM_LEX_STATE_BEG);
11344 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11349 lex_state_set(parser, PM_LEX_STATE_BEG);
11353 if (match(parser,
'=')) {
11354 lex_state_set(parser, PM_LEX_STATE_BEG);
11358 if (lex_state_operator_p(parser)) {
11359 lex_state_set(parser, PM_LEX_STATE_ARG);
11361 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11368 if (lex_state_operator_p(parser)) {
11369 lex_state_set(parser, PM_LEX_STATE_ARG);
11371 if (match(parser,
'@')) {
11378 if (match(parser,
'=')) {
11379 lex_state_set(parser, PM_LEX_STATE_BEG);
11384 lex_state_beg_p(parser) ||
11385 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) :
false)
11387 lex_state_set(parser, PM_LEX_STATE_BEG);
11392 lex_state_set(parser, PM_LEX_STATE_END);
11399 if (ambiguous_operator_p(parser, space_seen)) {
11400 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11403 lex_state_set(parser, PM_LEX_STATE_BEG);
11409 if (lex_state_operator_p(parser)) {
11410 lex_state_set(parser, PM_LEX_STATE_ARG);
11412 if (match(parser,
'@')) {
11419 if (match(parser,
'=')) {
11420 lex_state_set(parser, PM_LEX_STATE_BEG);
11424 if (match(parser,
'>')) {
11425 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11429 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11430 bool is_beg = lex_state_beg_p(parser);
11431 if (!is_beg && spcarg) {
11432 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11435 if (is_beg || spcarg) {
11436 lex_state_set(parser, PM_LEX_STATE_BEG);
11440 if (ambiguous_operator_p(parser, space_seen)) {
11441 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11444 lex_state_set(parser, PM_LEX_STATE_BEG);
11450 bool beg_p = lex_state_beg_p(parser);
11452 if (match(parser,
'.')) {
11453 if (match(parser,
'.')) {
11456 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11457 lex_state_set(parser, PM_LEX_STATE_BEG);
11459 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11465 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11468 lex_state_set(parser, PM_LEX_STATE_BEG);
11472 lex_state_set(parser, PM_LEX_STATE_BEG);
11476 lex_state_set(parser, PM_LEX_STATE_DOT);
11492 lex_state_set(parser, PM_LEX_STATE_END);
11498 if (match(parser,
':')) {
11499 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)) {
11500 lex_state_set(parser, PM_LEX_STATE_BEG);
11504 lex_state_set(parser, PM_LEX_STATE_DOT);
11509 lex_state_set(parser, PM_LEX_STATE_BEG);
11513 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11514 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11518 lex_state_set(parser, PM_LEX_STATE_FNAME);
11523 if (lex_state_beg_p(parser)) {
11524 lex_mode_push_regexp(parser,
'\0',
'/');
11528 if (match(parser,
'=')) {
11529 lex_state_set(parser, PM_LEX_STATE_BEG);
11533 if (lex_state_spcarg_p(parser, space_seen)) {
11534 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11535 lex_mode_push_regexp(parser,
'\0',
'/');
11539 if (ambiguous_operator_p(parser, space_seen)) {
11540 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11543 if (lex_state_operator_p(parser)) {
11544 lex_state_set(parser, PM_LEX_STATE_ARG);
11546 lex_state_set(parser, PM_LEX_STATE_BEG);
11553 if (lex_state_operator_p(parser)) {
11554 lex_state_set(parser, PM_LEX_STATE_ARG);
11556 lex_state_set(parser, PM_LEX_STATE_BEG);
11562 if (lex_state_operator_p(parser)) {
11563 (void) match(parser,
'@');
11564 lex_state_set(parser, PM_LEX_STATE_ARG);
11566 lex_state_set(parser, PM_LEX_STATE_BEG);
11577 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11578 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11582 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11583 lex_state_set(parser, PM_LEX_STATE_BEG);
11586 lex_state_beg_p(parser) ||
11587 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11588 lex_state_spcarg_p(parser, space_seen)
11591 if (*parser->
current.end >= 0x80) {
11592 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11595 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11596 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11602 uint8_t delimiter = peek_offset(parser, 1);
11604 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11605 goto lex_next_token;
11608 switch (peek(parser)) {
11613 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11615 lex_mode_push_list_eof(parser);
11624 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11626 lex_mode_push_list_eof(parser);
11635 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11636 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11638 lex_mode_push_regexp(parser,
'\0',
'\0');
11647 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11648 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11650 lex_mode_push_string_eof(parser);
11659 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11660 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11662 lex_mode_push_string_eof(parser);
11671 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11672 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11673 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11675 lex_mode_push_string_eof(parser);
11684 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11686 lex_mode_push_list_eof(parser);
11695 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11697 lex_mode_push_list_eof(parser);
11706 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11707 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11709 lex_mode_push_string_eof(parser);
11719 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11720 goto lex_next_token;
11724 if (ambiguous_operator_p(parser, space_seen)) {
11725 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11728 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11739 lex_mode_pop(parser);
11742 lex_state_set(parser, PM_LEX_STATE_END);
11748 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11749 LEX(lex_at_variable(parser));
11752 if (*parser->
current.start !=
'_') {
11753 size_t width = char_is_identifier_start(parser, parser->
current.start);
11760 if (*parser->
current.start >= 0x80) {
11761 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11762 }
else if (*parser->
current.start ==
'\\') {
11763 switch (peek_at(parser, parser->
current.start + 1)) {
11766 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11770 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11774 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11778 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11781 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11783 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11788 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11791 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11792 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11794 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11797 goto lex_next_token;
11811 current_token_starts_line(parser) &&
11812 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11813 (parser->
current.end == parser->
end || match_eol(parser))
11818 const uint8_t *cursor = parser->
current.end;
11819 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11825 parser_lex_callback(parser);
11836 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11837 if (previous_command_start) {
11838 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11840 lex_state_set(parser, PM_LEX_STATE_ARG);
11842 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11843 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11845 lex_state_set(parser, PM_LEX_STATE_END);
11850 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11852 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11853 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11855 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11862 case PM_LEX_LIST: {
11877 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11884 if (whitespace > 0) {
11885 parser->
current.end += whitespace;
11886 if (peek_offset(parser, -1) ==
'\n') {
11888 parser_flush_heredoc_end(parser);
11902 const uint8_t *breakpoints = lex_mode->
as.list.breakpoints;
11909 while (breakpoint != NULL) {
11913 parser->
current.end = breakpoint;
11914 pm_token_buffer_flush(parser, &token_buffer);
11920 if (*breakpoint == lex_mode->
as.list.terminator) {
11923 if (lex_mode->
as.list.nesting > 0) {
11924 parser->
current.end = breakpoint + 1;
11926 lex_mode->
as.list.nesting--;
11932 if (breakpoint > parser->
current.start) {
11933 parser->
current.end = breakpoint;
11934 pm_token_buffer_flush(parser, &token_buffer);
11940 parser->
current.end = breakpoint + 1;
11941 lex_mode_pop(parser);
11942 lex_state_set(parser, PM_LEX_STATE_END);
11947 if (*breakpoint ==
'\0') {
11948 breakpoint =
pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11955 if (*breakpoint ==
'\\') {
11956 parser->
current.end = breakpoint + 1;
11965 pm_token_buffer_escape(parser, &token_buffer);
11966 uint8_t peeked = peek(parser);
11974 pm_token_buffer_push_byte(&token_buffer, peeked);
11979 if (peek(parser) !=
'\n') {
11980 pm_token_buffer_push_byte(&token_buffer,
'\r');
11985 pm_token_buffer_push_byte(&token_buffer,
'\n');
11991 parser_flush_heredoc_end(parser);
11992 pm_token_buffer_copy(parser, &token_buffer);
12002 if (peeked == lex_mode->
as.list.incrementor || peeked == lex_mode->
as.list.terminator) {
12003 pm_token_buffer_push_byte(&token_buffer, peeked);
12005 }
else if (lex_mode->
as.list.interpolation) {
12006 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12008 pm_token_buffer_push_byte(&token_buffer,
'\\');
12009 pm_token_buffer_push_escaped(&token_buffer, parser);
12021 if (*breakpoint ==
'#') {
12034 pm_token_buffer_flush(parser, &token_buffer);
12042 assert(*breakpoint == lex_mode->
as.list.incrementor);
12043 parser->
current.end = breakpoint + 1;
12045 lex_mode->
as.list.nesting++;
12050 pm_token_buffer_flush(parser, &token_buffer);
12057 pm_token_buffer_flush(parser, &token_buffer);
12060 case PM_LEX_REGEXP: {
12082 const uint8_t *breakpoints = lex_mode->
as.regexp.breakpoints;
12086 while (breakpoint != NULL) {
12089 if (*breakpoint == lex_mode->
as.regexp.terminator) {
12090 if (lex_mode->
as.regexp.nesting > 0) {
12091 parser->
current.end = breakpoint + 1;
12093 lex_mode->
as.regexp.nesting--;
12100 if (breakpoint > parser->
current.start) {
12101 parser->
current.end = breakpoint;
12102 pm_regexp_token_buffer_flush(parser, &token_buffer);
12107 size_t eol_length = match_eol_at(parser, breakpoint);
12109 parser->
current.end = breakpoint + eol_length;
12112 parser->
current.end = breakpoint + 1;
12119 lex_mode_pop(parser);
12120 lex_state_set(parser, PM_LEX_STATE_END);
12126 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.incrementor) {
12127 parser->
current.end = breakpoint + 1;
12129 lex_mode->
as.regexp.nesting++;
12133 switch (*breakpoint) {
12136 parser->
current.end = breakpoint + 1;
12140 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12141 parser->
current.end = breakpoint + 1;
12147 parser->
current.end = breakpoint;
12148 pm_regexp_token_buffer_escape(parser, &token_buffer);
12157 parser->
current.end = breakpoint + 1;
12162 parser->
current.end = breakpoint + 1;
12163 parser_flush_heredoc_end(parser);
12164 pm_regexp_token_buffer_flush(parser, &token_buffer);
12170 parser->
current.end = breakpoint + 1;
12179 pm_regexp_token_buffer_escape(parser, &token_buffer);
12180 uint8_t peeked = peek(parser);
12185 if (peek(parser) !=
'\n') {
12186 if (lex_mode->
as.regexp.terminator !=
'\r') {
12187 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12189 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12190 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12199 parser_flush_heredoc_end(parser);
12200 pm_regexp_token_buffer_copy(parser, &token_buffer);
12217 if (lex_mode->
as.regexp.terminator == peeked) {
12222 case '$':
case ')':
case '*':
case '+':
12223 case '.':
case '>':
case '?':
case ']':
12224 case '^':
case '|':
case '}':
12225 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12231 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12232 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12237 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12238 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12261 pm_regexp_token_buffer_flush(parser, &token_buffer);
12267 assert(
false &&
"unreachable");
12273 pm_regexp_token_buffer_flush(parser, &token_buffer);
12280 pm_regexp_token_buffer_flush(parser, &token_buffer);
12283 case PM_LEX_STRING: {
12302 const uint8_t *breakpoints = lex_mode->
as.string.breakpoints;
12309 while (breakpoint != NULL) {
12312 if (lex_mode->
as.string.incrementor !=
'\0' && *breakpoint == lex_mode->
as.string.incrementor) {
12313 lex_mode->
as.string.nesting++;
12314 parser->
current.end = breakpoint + 1;
12322 if (*breakpoint == lex_mode->
as.string.terminator) {
12325 if (lex_mode->
as.string.nesting > 0) {
12326 parser->
current.end = breakpoint + 1;
12328 lex_mode->
as.string.nesting--;
12334 if (breakpoint > parser->
current.start) {
12335 parser->
current.end = breakpoint;
12336 pm_token_buffer_flush(parser, &token_buffer);
12342 size_t eol_length = match_eol_at(parser, breakpoint);
12344 parser->
current.end = breakpoint + eol_length;
12347 parser->
current.end = breakpoint + 1;
12350 if (lex_mode->
as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12352 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12353 lex_mode_pop(parser);
12357 lex_state_set(parser, PM_LEX_STATE_END);
12358 lex_mode_pop(parser);
12362 switch (*breakpoint) {
12365 parser->
current.end = breakpoint + 1;
12369 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12370 parser->
current.end = breakpoint + 1;
12378 parser->
current.end = breakpoint;
12379 pm_token_buffer_escape(parser, &token_buffer);
12380 token_buffer.
cursor = breakpoint;
12390 parser->
current.end = breakpoint + 1;
12395 parser->
current.end = breakpoint + 1;
12396 parser_flush_heredoc_end(parser);
12397 pm_token_buffer_flush(parser, &token_buffer);
12401 parser->
current.end = breakpoint + 1;
12410 pm_token_buffer_escape(parser, &token_buffer);
12411 uint8_t peeked = peek(parser);
12415 pm_token_buffer_push_byte(&token_buffer,
'\\');
12420 if (peek(parser) !=
'\n') {
12421 if (!lex_mode->
as.string.interpolation) {
12422 pm_token_buffer_push_byte(&token_buffer,
'\\');
12424 pm_token_buffer_push_byte(&token_buffer,
'\r');
12429 if (!lex_mode->
as.string.interpolation) {
12430 pm_token_buffer_push_byte(&token_buffer,
'\\');
12431 pm_token_buffer_push_byte(&token_buffer,
'\n');
12438 parser_flush_heredoc_end(parser);
12439 pm_token_buffer_copy(parser, &token_buffer);
12449 if (lex_mode->
as.string.incrementor !=
'\0' && peeked == lex_mode->
as.string.incrementor) {
12450 pm_token_buffer_push_byte(&token_buffer, peeked);
12452 }
else if (lex_mode->
as.string.terminator !=
'\0' && peeked == lex_mode->
as.string.terminator) {
12453 pm_token_buffer_push_byte(&token_buffer, peeked);
12455 }
else if (lex_mode->
as.string.interpolation) {
12456 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12458 pm_token_buffer_push_byte(&token_buffer,
'\\');
12459 pm_token_buffer_push_escaped(&token_buffer, parser);
12482 pm_token_buffer_flush(parser, &token_buffer);
12488 assert(
false &&
"unreachable");
12493 pm_token_buffer_flush(parser, &token_buffer);
12500 pm_token_buffer_flush(parser, &token_buffer);
12503 case PM_LEX_HEREDOC: {
12519 bool line_continuation = lex_mode->
as.heredoc.line_continuation;
12520 lex_mode->
as.heredoc.line_continuation =
false;
12530 lex_state_set(parser, PM_LEX_STATE_END);
12531 lex_mode_pop(parser);
12535 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12540 if (current_token_starts_line(parser)) {
12541 const uint8_t *start = parser->
current.start;
12543 if (!line_continuation && (start + ident_length <= parser->end)) {
12544 const uint8_t *newline = next_newline(start, parser->
end - start);
12545 const uint8_t *ident_end = newline;
12546 const uint8_t *terminator_end = newline;
12548 if (newline == NULL) {
12549 terminator_end = parser->
end;
12550 ident_end = parser->
end;
12553 if (newline[-1] ==
'\r') {
12558 const uint8_t *terminator_start = ident_end - ident_length;
12559 const uint8_t *cursor = start;
12561 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12568 (cursor == terminator_start) &&
12569 (memcmp(terminator_start, ident_start, ident_length) == 0)
12571 if (newline != NULL) {
12575 parser->
current.end = terminator_end;
12576 if (*lex_mode->
as.heredoc.next_start ==
'\\') {
12583 lex_state_set(parser, PM_LEX_STATE_END);
12584 lex_mode_pop(parser);
12589 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12591 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12592 lex_mode->
as.heredoc.common_whitespace != NULL &&
12593 (*lex_mode->
as.heredoc.common_whitespace > whitespace) &&
12594 peek_at(parser, start) !=
'\n'
12596 *lex_mode->
as.heredoc.common_whitespace = whitespace;
12603 uint8_t breakpoints[] =
"\r\n\\#";
12606 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12607 breakpoints[3] =
'\0';
12612 bool was_line_continuation =
false;
12614 while (breakpoint != NULL) {
12615 switch (*breakpoint) {
12618 parser->
current.end = breakpoint + 1;
12622 parser->
current.end = breakpoint + 1;
12624 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12632 pm_token_buffer_escape(parser, &token_buffer);
12633 token_buffer.
cursor = breakpoint;
12638 parser_flush_heredoc_end(parser);
12639 parser->
current.end = breakpoint + 1;
12640 pm_token_buffer_flush(parser, &token_buffer);
12648 const uint8_t *start = breakpoint + 1;
12650 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12653 const uint8_t *newline = next_newline(start, parser->
end - start);
12655 if (newline == NULL) {
12656 newline = parser->
end;
12657 }
else if (newline[-1] ==
'\r') {
12662 const uint8_t *terminator_start = newline - ident_length;
12666 const uint8_t *cursor = start;
12668 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12675 cursor == terminator_start &&
12676 (memcmp(terminator_start, ident_start, ident_length) == 0)
12678 parser->
current.end = breakpoint + 1;
12679 pm_token_buffer_flush(parser, &token_buffer);
12684 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.base.indent);
12691 if (lex_mode->
as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12692 if ((lex_mode->
as.heredoc.common_whitespace != NULL) && (*lex_mode->
as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12693 *lex_mode->
as.heredoc.common_whitespace = whitespace;
12696 parser->
current.end = breakpoint + 1;
12697 pm_token_buffer_flush(parser, &token_buffer);
12703 parser->
current.end = breakpoint + 1;
12714 parser->
current.end = breakpoint + 1;
12723 pm_token_buffer_escape(parser, &token_buffer);
12724 uint8_t peeked = peek(parser);
12726 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12730 if (peek(parser) !=
'\n') {
12731 pm_token_buffer_push_byte(&token_buffer,
'\\');
12732 pm_token_buffer_push_byte(&token_buffer,
'\r');
12737 pm_token_buffer_push_byte(&token_buffer,
'\\');
12738 pm_token_buffer_push_byte(&token_buffer,
'\n');
12740 breakpoint = parser->
current.end;
12743 pm_token_buffer_push_byte(&token_buffer,
'\\');
12744 pm_token_buffer_push_escaped(&token_buffer, parser);
12751 if (peek(parser) !=
'\n') {
12752 pm_token_buffer_push_byte(&token_buffer,
'\r');
12760 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12761 const uint8_t *end = parser->
current.end;
12766 parser->
current.end = breakpoint;
12767 pm_token_buffer_flush(parser, &token_buffer);
12771 parser->
current.end = end + 1;
12772 lex_mode->
as.heredoc.line_continuation =
true;
12776 was_line_continuation =
true;
12778 breakpoint = parser->
current.end;
12781 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12804 pm_token_buffer_flush(parser, &token_buffer);
12810 assert(
false &&
"unreachable");
12813 was_line_continuation =
false;
12818 pm_token_buffer_flush(parser, &token_buffer);
12825 pm_token_buffer_flush(parser, &token_buffer);
12830 assert(
false &&
"unreachable");
12848 PM_BINDING_POWER_UNSET = 0,
12849 PM_BINDING_POWER_STATEMENT = 2,
12850 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12851 PM_BINDING_POWER_MODIFIER = 6,
12852 PM_BINDING_POWER_COMPOSITION = 8,
12853 PM_BINDING_POWER_NOT = 10,
12854 PM_BINDING_POWER_MATCH = 12,
12855 PM_BINDING_POWER_DEFINED = 14,
12856 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12857 PM_BINDING_POWER_ASSIGNMENT = 18,
12858 PM_BINDING_POWER_TERNARY = 20,
12859 PM_BINDING_POWER_RANGE = 22,
12860 PM_BINDING_POWER_LOGICAL_OR = 24,
12861 PM_BINDING_POWER_LOGICAL_AND = 26,
12862 PM_BINDING_POWER_EQUALITY = 28,
12863 PM_BINDING_POWER_COMPARISON = 30,
12864 PM_BINDING_POWER_BITWISE_OR = 32,
12865 PM_BINDING_POWER_BITWISE_AND = 34,
12866 PM_BINDING_POWER_SHIFT = 36,
12867 PM_BINDING_POWER_TERM = 38,
12868 PM_BINDING_POWER_FACTOR = 40,
12869 PM_BINDING_POWER_UMINUS = 42,
12870 PM_BINDING_POWER_EXPONENT = 44,
12871 PM_BINDING_POWER_UNARY = 46,
12872 PM_BINDING_POWER_INDEX = 48,
12873 PM_BINDING_POWER_CALL = 50,
12874 PM_BINDING_POWER_MAX = 52
12875 } pm_binding_power_t;
12898 #define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12899 #define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12900 #define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12901 #define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12902 #define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12964 [
PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12968 [
PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12969 [
PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12985 [
PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12986 [
PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12989 [
PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12997 [
PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12998 [
PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12999 [
PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13006 [
PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13010 #undef BINDING_POWER_ASSIGNMENT
13011 #undef LEFT_ASSOCIATIVE
13012 #undef RIGHT_ASSOCIATIVE
13013 #undef RIGHT_ASSOCIATIVE_UNARY
13028 return match1(parser, type1) || match1(parser, type2);
13036 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13044 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13052 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
13060 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13068 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);
13079 if (match1(parser,
type)) {
13080 parser_lex(parser);
13092 if (match2(parser, type1, type2)) {
13093 parser_lex(parser);
13105 if (match3(parser, type1, type2, type3)) {
13106 parser_lex(parser);
13125 if (accept1(parser,
type))
return;
13128 pm_parser_err(parser, location, location, diag_id);
13140 if (accept2(parser, type1, type2))
return;
13143 pm_parser_err(parser, location, location, diag_id);
13154 if (accept3(parser, type1, type2, type3))
return;
13157 pm_parser_err(parser, location, location, diag_id);
13168 expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13170 parser_lex(parser);
13172 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13179 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);
13186 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) {
13187 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13188 pm_assert_value_expression(parser, node);
13242 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13262 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13271 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) {
13274 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13275 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13278 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13292 size_t length = constant->
length;
13293 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13294 if (name == NULL)
return;
13296 memcpy(name, constant->
start, length);
13297 name[length] =
'=';
13314 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13315 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13316 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13317 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13318 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13319 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13320 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13340 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13341 if (implicit_parameters->
nodes[index] == node) {
13345 if (index != implicit_parameters->
size - 1) {
13346 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13349 implicit_parameters->
size--;
13377 return parse_unwriteable_target(parser, target);
13384 if (context_def_p(parser)) {
13385 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13393 if (context_def_p(parser)) {
13394 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13403 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13412 parse_target_implicit_parameter(parser, target);
13416 uint32_t name = cast->
name;
13417 uint32_t depth = cast->
depth;
13418 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13429 parse_target_implicit_parameter(parser, target);
13439 if (splat_parent) {
13442 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13467 (call->
block == NULL)
13484 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13489 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13492 parse_write_name(parser, &call->
name);
13493 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13501 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13509 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13520 pm_node_t *result = parse_target(parser, target, multiple,
false);
13529 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13543 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13544 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13567 if (context_def_p(parser)) {
13568 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13571 return parse_shareable_constant_write(parser, node);
13576 if (context_def_p(parser)) {
13577 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13581 return parse_shareable_constant_write(parser, node);
13585 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13598 uint32_t depth = local_read->
depth;
13599 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13602 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13604 parse_target_implicit_parameter(parser, target);
13607 pm_locals_unread(&scope->
locals, name);
13610 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13616 parse_target_implicit_parameter(parser, target);
13636 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13638 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13652 (call->
block == NULL)
13666 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13670 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13672 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13690 pm_arguments_node_arguments_append(arguments, value);
13693 parse_write_name(parser, &call->
name);
13705 call->
arguments = pm_arguments_node_create(parser);
13708 pm_arguments_node_arguments_append(call->
arguments, value);
13712 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13730 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13744 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13745 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13746 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13747 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13748 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13749 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13750 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13772 parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13776 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13784 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13790 if (token_begins_expression_p(parser->
current.type)) {
13791 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13792 name = parse_target(parser, name,
true,
true);
13795 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13796 pm_multi_target_node_targets_append(parser, result, splat);
13800 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13801 target = parse_target(parser, target,
true,
false);
13803 pm_multi_target_node_targets_append(parser, result, target);
13804 context_pop(parser);
13805 }
else if (token_begins_expression_p(parser->
current.type)) {
13806 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13807 target = parse_target(parser, target,
true,
false);
13809 pm_multi_target_node_targets_append(parser, result, target);
13814 pm_multi_target_node_targets_append(parser, result, rest);
13827 parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13828 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13833 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13849 if (context_terminator(context, &parser->
current))
return NULL;
13855 context_push(parser, context);
13858 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13859 pm_statements_node_body_append(parser, statements, node,
true);
13876 if (context_terminator(context, &parser->
current))
break;
13886 if (context_terminator(context, &parser->
current))
break;
13899 parser_lex(parser);
13902 if (context_terminator(context, &parser->
current))
break;
13913 context_pop(parser);
13914 bool last_value =
true;
13918 last_value =
false;
13923 pm_void_statements_check(parser, statements, last_value);
13936 if (duplicated != NULL) {
13944 PM_WARN_DUPLICATED_HASH_KEY,
13967 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13980 bool contains_keyword_splat =
false;
13985 switch (parser->
current.type) {
13987 parser_lex(parser);
13997 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13998 }
else if (token_begins_expression_p(parser->
current.type)) {
13999 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14001 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14004 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14005 contains_keyword_splat =
true;
14010 parser_lex(parser);
14013 pm_hash_key_static_literals_add(parser, literals, key);
14018 if (token_begins_expression_p(parser->
current.type)) {
14019 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14023 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14028 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14029 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14031 depth = pm_parser_local_depth(parser, &identifier);
14035 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14037 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14042 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14045 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14049 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14057 pm_hash_key_static_literals_add(parser, literals, key);
14060 if (pm_symbol_node_label_p(key)) {
14061 operator = not_provided(parser);
14067 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14068 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14088 if (token_begins_expression_p(parser->
current.type))
continue;
14094 return contains_keyword_splat;
14103 arguments->
arguments = pm_arguments_node_create(parser);
14106 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14114 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
14120 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14126 bool parsed_first_argument =
false;
14127 bool parsed_bare_hash =
false;
14128 bool parsed_block_argument =
false;
14129 bool parsed_forwarding_arguments =
false;
14132 if (parsed_block_argument) {
14133 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14135 if (parsed_forwarding_arguments) {
14136 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14141 switch (parser->
current.type) {
14144 if (parsed_bare_hash) {
14145 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14152 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14154 parse_arguments_append(parser, arguments, argument);
14161 parsed_bare_hash =
true;
14166 parser_lex(parser);
14170 if (token_begins_expression_p(parser->
current.type)) {
14171 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14173 pm_parser_scope_forwarding_block_check(parser, &
operator);
14176 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14177 if (parsed_block_argument) {
14178 parse_arguments_append(parser, arguments, argument);
14180 arguments->
block = argument;
14183 parsed_block_argument =
true;
14187 parser_lex(parser);
14191 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14192 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14193 if (parsed_bare_hash) {
14194 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14197 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14199 if (parsed_bare_hash) {
14200 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14203 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14206 parse_arguments_append(parser, arguments, argument);
14210 if (accepts_forwarding) {
14211 parser_lex(parser);
14213 if (token_begins_expression_p(parser->
current.type)) {
14218 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14225 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14228 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14230 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14231 if (parsed_first_argument && terminator ==
PM_TOKEN_EOF) {
14232 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14235 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14236 parse_arguments_append(parser, arguments, argument);
14239 parsed_forwarding_arguments =
true;
14246 if (argument == NULL) {
14247 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14250 bool contains_keywords =
false;
14251 bool contains_keyword_splat =
false;
14254 if (parsed_bare_hash) {
14255 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14262 operator = not_provided(parser);
14266 contains_keywords =
true;
14270 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14273 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14274 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14276 pm_keyword_hash_node_elements_append(bare_hash, argument);
14281 token_begins_expression_p(parser->
current.type) ||
14284 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14288 parsed_bare_hash =
true;
14291 parse_arguments_append(parser, arguments, argument);
14302 parsed_first_argument =
true;
14310 bool accepted_newline =
false;
14322 if (accepted_newline) {
14323 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14333 if (match1(parser, terminator))
break;
14348 parse_required_destructured_parameter(
pm_parser_t *parser) {
14352 pm_multi_target_node_opening_set(node, &parser->
previous);
14363 pm_multi_target_node_targets_append(parser, node, param);
14364 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14369 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14376 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14377 if (pm_parser_parameter_name_check(parser, &name)) {
14378 pm_node_flag_set_repeated_parameter(value);
14380 pm_parser_local_add_token(parser, &name, 1);
14383 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14388 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14389 if (pm_parser_parameter_name_check(parser, &name)) {
14390 pm_node_flag_set_repeated_parameter(param);
14392 pm_parser_local_add_token(parser, &name, 1);
14395 pm_multi_target_node_targets_append(parser, node, param);
14400 pm_multi_target_node_closing_set(node, &parser->
previous);
14410 PM_PARAMETERS_NO_CHANGE = 0,
14411 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14412 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14413 PM_PARAMETERS_ORDER_KEYWORDS,
14414 PM_PARAMETERS_ORDER_REST,
14415 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14416 PM_PARAMETERS_ORDER_OPTIONAL,
14417 PM_PARAMETERS_ORDER_NAMED,
14418 PM_PARAMETERS_ORDER_NONE,
14419 } pm_parameters_order_t;
14425 [0] = PM_PARAMETERS_NO_CHANGE,
14448 pm_parameters_order_t state = parameters_ordering[token->type];
14449 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14453 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14454 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14456 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14460 if (token->type ==
PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14461 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14463 }
else if (token->type ==
PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14464 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14466 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14468 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14472 if (state < *current) *current = state;
14482 pm_binding_power_t binding_power,
14483 bool uses_parentheses,
14484 bool allows_trailing_comma,
14485 bool allows_forwarding_parameters,
14486 bool accepts_blocks_in_defaults,
14489 pm_do_loop_stack_push(parser,
false);
14492 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14495 bool parsing =
true;
14497 switch (parser->
current.type) {
14499 update_parameter_state(parser, &parser->
current, &order);
14502 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14503 pm_parameters_node_requireds_append(params, param);
14505 pm_parameters_node_posts_append(params, param);
14511 update_parameter_state(parser, &parser->
current, &order);
14512 parser_lex(parser);
14517 bool repeated =
false;
14520 repeated = pm_parser_parameter_name_check(parser, &name);
14521 pm_parser_local_add_token(parser, &name, 1);
14523 name = not_provided(parser);
14529 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14531 if (params->
block == NULL) {
14532 pm_parameters_node_block_set(params, param);
14534 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14535 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14541 if (!allows_forwarding_parameters) {
14542 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14545 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14546 parser_lex(parser);
14555 pm_parameters_node_posts_append(params, keyword_rest);
14556 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14560 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14569 parser_lex(parser);
14572 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14575 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14578 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14581 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14584 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14590 update_parameter_state(parser, &parser->
current, &order);
14592 update_parameter_state(parser, &parser->
previous, &order);
14596 bool repeated = pm_parser_parameter_name_check(parser, &name);
14597 pm_parser_local_add_token(parser, &name, 1);
14602 parser_lex(parser);
14607 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14608 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14609 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14614 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14616 pm_parameters_node_optionals_append(params, param);
14622 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14625 context_pop(parser);
14634 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14637 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14639 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14643 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14645 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14652 update_parameter_state(parser, &parser->
current, &order);
14655 parser_lex(parser);
14662 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14663 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14664 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14667 bool repeated = pm_parser_parameter_name_check(parser, &local);
14668 pm_parser_local_add_token(parser, &local, 1);
14670 switch (parser->
current.type) {
14674 context_pop(parser);
14676 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14678 pm_node_flag_set_repeated_parameter(param);
14681 pm_parameters_node_keywords_append(params, param);
14686 context_pop(parser);
14688 if (uses_parentheses) {
14693 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14695 pm_node_flag_set_repeated_parameter(param);
14698 pm_parameters_node_keywords_append(params, param);
14704 if (token_begins_expression_p(parser->
current.type)) {
14708 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14709 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14710 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14713 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14716 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14719 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14723 pm_node_flag_set_repeated_parameter(param);
14726 context_pop(parser);
14727 pm_parameters_node_keywords_append(params, param);
14744 update_parameter_state(parser, &parser->
current, &order);
14745 parser_lex(parser);
14749 bool repeated =
false;
14753 repeated = pm_parser_parameter_name_check(parser, &name);
14754 pm_parser_local_add_token(parser, &name, 1);
14756 name = not_provided(parser);
14760 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14762 pm_node_flag_set_repeated_parameter(param);
14765 if (params->
rest == NULL) {
14766 pm_parameters_node_rest_set(params, param);
14768 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14769 pm_parameters_node_posts_append(params, param);
14776 pm_parameters_order_t previous_order = order;
14777 update_parameter_state(parser, &parser->
current, &order);
14778 parser_lex(parser);
14784 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14785 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14788 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14792 bool repeated =
false;
14795 repeated = pm_parser_parameter_name_check(parser, &name);
14796 pm_parser_local_add_token(parser, &name, 1);
14798 name = not_provided(parser);
14802 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14804 pm_node_flag_set_repeated_parameter(param);
14809 pm_parameters_node_keyword_rest_set(params, param);
14811 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14812 pm_parameters_node_posts_append(params, param);
14819 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14824 if (params->
rest == NULL) {
14825 pm_parameters_node_rest_set(params, param);
14827 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14828 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14831 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14842 if (!parsing)
break;
14844 bool accepted_newline =
false;
14845 if (uses_parentheses) {
14852 if (accepted_newline) {
14853 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14861 pm_do_loop_stack_pop(parser);
14897 token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14899 const uint8_t *end = token->start;
14903 newline_index == 0 &&
14904 parser->
start[0] == 0xef &&
14905 parser->
start[1] == 0xbb &&
14906 parser->
start[2] == 0xbf
14909 int64_t column = 0;
14910 for (; cursor < end; cursor++) {
14913 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14920 if (break_on_non_space)
return -1;
14933 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) {
14938 size_t closing_newline_index = token_newline_index(parser);
14939 if (opening_newline_index == closing_newline_index)
return;
14944 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14945 if (!if_after_else && (opening_column == -1))
return;
14952 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14953 if ((closing_column == -1) || (opening_column == closing_column))
return;
14957 if (allow_indent && (closing_column > opening_column))
return;
14960 PM_PARSER_WARN_FORMAT(
14962 closing_token->
start,
14963 closing_token->
end,
14964 PM_WARN_INDENTATION_MISMATCH,
14965 (
int) (closing_token->
end - closing_token->
start),
14966 (
const char *) closing_token->
start,
14967 (
int) (opening_token->
end - opening_token->
start),
14968 (
const char *) opening_token->
start,
14969 ((int32_t) opening_newline_index) + parser->
start_line
14974 PM_RESCUES_BEGIN = 1,
14981 } pm_rescues_type_t;
14992 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14993 parser_lex(parser);
14997 switch (parser->
current.type) {
15002 parser_lex(parser);
15003 pm_rescue_node_operator_set(rescue, &parser->
previous);
15005 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15006 reference = parse_target(parser, reference,
false,
false);
15008 pm_rescue_node_reference_set(rescue, reference);
15023 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15024 pm_rescue_node_exceptions_append(rescue, expression);
15033 pm_rescue_node_operator_set(rescue, &parser->
previous);
15035 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15036 reference = parse_target(parser, reference,
false,
false);
15038 pm_rescue_node_reference_set(rescue, reference);
15053 pm_accepts_block_stack_push(parser,
true);
15068 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15070 pm_accepts_block_stack_pop(parser);
15074 if (current == NULL) {
15075 pm_begin_node_rescue_clause_set(parent_node, rescue);
15077 pm_rescue_node_subsequent_set(current, rescue);
15086 if (current != NULL) {
15090 while (clause != NULL) {
15098 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15099 opening_newline_index = token_newline_index(parser);
15101 else_keyword = parser->
current;
15102 opening = &else_keyword;
15104 parser_lex(parser);
15109 pm_accepts_block_stack_push(parser,
true);
15123 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15124 pm_accepts_block_stack_pop(parser);
15129 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15130 pm_begin_node_else_clause_set(parent_node, else_clause);
15134 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15138 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15141 parser_lex(parser);
15146 pm_accepts_block_stack_push(parser,
true);
15160 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15161 pm_accepts_block_stack_pop(parser);
15166 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15167 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15171 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15172 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15175 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15185 pm_token_t begin_keyword = not_provided(parser);
15186 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15188 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15198 parse_block_parameters(
15200 bool allows_trailing_comma,
15202 bool is_lambda_literal,
15203 bool accepts_blocks_in_defaults,
15208 parameters = parse_parameters(
15210 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15212 allows_trailing_comma,
15214 accepts_blocks_in_defaults,
15215 (uint16_t) (depth + 1)
15225 switch (parser->
current.type) {
15227 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15228 parser_lex(parser);
15231 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15232 parser_lex(parser);
15235 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15236 parser_lex(parser);
15239 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15240 parser_lex(parser);
15247 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15248 pm_parser_local_add_token(parser, &parser->
previous, 1);
15251 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15253 pm_block_parameters_node_append_local(block_parameters, local);
15258 return block_parameters;
15266 outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15268 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15279 static const char *
const pm_numbered_parameter_names[] = {
15280 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15294 if (parameters != NULL) {
15296 if (implicit_parameters->
size > 0) {
15300 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15302 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15304 assert(
false &&
"unreachable");
15313 if (implicit_parameters->
size == 0) {
15320 uint8_t numbered_parameter = 0;
15321 bool it_parameter =
false;
15323 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15327 if (it_parameter) {
15328 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15329 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15330 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15332 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15334 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15336 assert(
false &&
"unreachable");
15339 if (numbered_parameter > 0) {
15340 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15342 it_parameter =
true;
15347 if (numbered_parameter > 0) {
15351 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15355 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15358 if (it_parameter) {
15359 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15369 parse_block(
pm_parser_t *parser, uint16_t depth) {
15373 pm_accepts_block_stack_push(parser,
true);
15374 pm_parser_scope_push(parser,
false);
15381 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15383 parser_lex(parser);
15385 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15388 expect1(parser,
PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15391 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15406 pm_accepts_block_stack_push(parser,
true);
15408 pm_accepts_block_stack_pop(parser);
15413 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));
15421 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15424 pm_parser_scope_pop(parser);
15425 pm_accepts_block_stack_pop(parser);
15427 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15436 parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15437 bool found =
false;
15446 pm_accepts_block_stack_push(parser,
true);
15455 pm_accepts_block_stack_pop(parser);
15460 pm_accepts_block_stack_push(parser,
false);
15465 parse_arguments(parser, arguments, accepts_block,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
15474 pm_accepts_block_stack_pop(parser);
15480 if (accepts_block) {
15485 block = parse_block(parser, (uint16_t) (depth + 1));
15486 pm_arguments_validate_block(parser, arguments, block);
15489 block = parse_block(parser, (uint16_t) (depth + 1));
15492 if (block != NULL) {
15496 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15498 if (arguments->
block != NULL) {
15500 arguments->
arguments = pm_arguments_node_create(parser);
15502 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15518 bool in_sclass =
false;
15520 switch (context_node->
context) {
15565 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15587 assert(
false &&
"unreachable");
15592 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15603 switch (context_node->
context) {
15677 assert(
false &&
"unreachable");
15691 return previous_block_exits;
15709 default: assert(
false &&
"unreachable");
type =
"";
break;
15712 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15729 }
else if (previous_block_exits != NULL) {
15741 flush_block_exits(parser, previous_block_exits);
15749 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15755 predicate_closed =
true;
15759 if (!predicate_closed) {
15760 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15763 context_pop(parser);
15768 parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15770 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15773 pm_token_t then_keyword = not_provided(parser);
15775 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15779 pm_accepts_block_stack_push(parser,
true);
15780 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15781 pm_accepts_block_stack_pop(parser);
15785 pm_token_t end_keyword = not_provided(parser);
15790 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15793 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15796 assert(
false &&
"unreachable");
15806 if (parser_end_of_line_p(parser)) {
15807 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15810 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15812 parser_lex(parser);
15814 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15815 pm_accepts_block_stack_push(parser,
true);
15818 pm_accepts_block_stack_pop(parser);
15821 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15828 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15829 opening_newline_index = token_newline_index(parser);
15831 parser_lex(parser);
15834 pm_accepts_block_stack_push(parser,
true);
15836 pm_accepts_block_stack_pop(parser);
15839 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15842 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15852 assert(
false &&
"unreachable");
15856 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15864 bool recursing =
true;
15866 while (recursing) {
15871 recursing = current != NULL;
15889 assert(
false &&
"unreachable");
15893 pop_block_exits(parser, previous_block_exits);
15903 #define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15904 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15905 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15906 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15907 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15908 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15909 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15910 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15911 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15912 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15913 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15919 #define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15920 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15921 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15922 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15923 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15924 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15925 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15926 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15933 #define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15934 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15935 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15936 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15937 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15938 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15939 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15940 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15941 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15947 #define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15948 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15949 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15950 case PM_TOKEN_CLASS_VARIABLE
15956 #define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15957 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15958 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15959 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15970 parse_unescaped_encoding(
const pm_parser_t *parser) {
15992 parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15993 switch (parser->
current.type) {
16005 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16007 parser_lex(parser);
16025 lex_state_set(parser, PM_LEX_STATE_BEG);
16026 parser_lex(parser);
16032 pm_accepts_block_stack_push(parser,
true);
16034 pm_accepts_block_stack_pop(parser);
16038 lex_state_set(parser, state);
16046 if (statements != NULL && statements->
body.
size == 1) {
16050 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16064 lex_state_set(parser, PM_LEX_STATE_BEG);
16065 parser_lex(parser);
16070 switch (parser->
current.type) {
16074 parser_lex(parser);
16075 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16080 parser_lex(parser);
16081 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16086 parser_lex(parser);
16087 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16092 parser_lex(parser);
16093 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16098 parser_lex(parser);
16099 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16110 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16113 parser_lex(parser);
16114 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16124 static const uint8_t *
16125 parse_operator_symbol_name(
const pm_token_t *name) {
16126 switch (name->type) {
16129 if (name->end[-1] ==
'@')
return name->end - 1;
16141 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16143 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16144 parser_lex(parser);
16161 if (lex_mode->
mode != PM_LEX_STRING) {
16162 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16164 switch (parser->
current.type) {
16165 case PM_CASE_OPERATOR:
16166 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16175 case PM_CASE_KEYWORD:
16176 parser_lex(parser);
16187 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16192 if (lex_mode->
as.string.interpolation) {
16195 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16196 parser_lex(parser);
16200 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16204 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16209 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16216 if (part) pm_interpolated_symbol_node_append(symbol, part);
16219 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16220 pm_interpolated_symbol_node_append(symbol, part);
16224 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16226 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16231 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16241 parser_lex(parser);
16256 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16257 pm_interpolated_symbol_node_append(symbol, part);
16260 pm_interpolated_symbol_node_append(symbol, part);
16262 if (next_state != PM_LEX_STATE_NONE) {
16263 lex_state_set(parser, next_state);
16266 parser_lex(parser);
16269 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16277 if (next_state != PM_LEX_STATE_NONE) {
16278 lex_state_set(parser, next_state);
16282 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16287 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16295 parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16296 switch (parser->
current.type) {
16297 case PM_CASE_OPERATOR: {
16298 const pm_token_t opening = not_provided(parser);
16299 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16301 case PM_CASE_KEYWORD:
16305 parser_lex(parser);
16312 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16318 parser_lex(parser);
16320 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16323 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16335 parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16336 switch (parser->
current.type) {
16337 case PM_CASE_OPERATOR: {
16338 const pm_token_t opening = not_provided(parser);
16339 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16341 case PM_CASE_KEYWORD:
16345 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16346 parser_lex(parser);
16353 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16359 parser_lex(parser);
16361 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16364 parser_lex(parser);
16365 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16367 parser_lex(parser);
16368 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16370 parser_lex(parser);
16371 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16373 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16387 if ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1) {
16388 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16392 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16398 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16399 for (uint8_t number = 1; number <= maximum; number++) {
16400 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16407 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16430 pm_node_t *node = parse_variable(parser);
16431 if (node != NULL)
return node;
16436 pm_node_flag_set((
pm_node_t *)node, flags);
16447 parse_method_definition_name(
pm_parser_t *parser) {
16448 switch (parser->
current.type) {
16449 case PM_CASE_KEYWORD:
16452 parser_lex(parser);
16455 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16456 parser_lex(parser);
16458 case PM_CASE_OPERATOR:
16459 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16460 parser_lex(parser);
16469 parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16478 const uint8_t *source_cursor = (uint8_t *) string->
source;
16479 const uint8_t *source_end = source_cursor + dest_length;
16484 size_t trimmed_whitespace = 0;
16491 if (*source_cursor ==
'\t') {
16492 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16493 if (trimmed_whitespace > common_whitespace)
break;
16495 trimmed_whitespace++;
16502 memmove((uint8_t *) string->
source, source_cursor, (
size_t) (source_end - source_cursor));
16503 string->length = dest_length;
16513 bool dedent_next =
true;
16518 size_t write_index = 0;
16526 nodes->
nodes[write_index++] = node;
16527 dedent_next =
false;
16533 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16539 nodes->
nodes[write_index++] = node;
16543 dedent_next =
true;
16546 nodes->
size = write_index;
16553 parse_strings_empty_content(
const uint8_t *location) {
16563 bool concating =
false;
16571 assert(lex_mode->
mode == PM_LEX_STRING);
16572 bool lex_interpolation = lex_mode->
as.string.interpolation;
16573 bool label_allowed = lex_mode->
as.string.label_allowed && accepts_label;
16576 parser_lex(parser);
16598 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16599 }
else if (!lex_interpolation) {
16607 content = not_provided(parser);
16628 pm_token_t delimiters = not_provided(parser);
16629 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16633 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16635 parser_lex(parser);
16639 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16643 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16644 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16646 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16647 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16649 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16654 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16663 parser_lex(parser);
16666 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16667 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16675 if (location > parser->
start && location[-1] ==
'\n') location--;
16676 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16682 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16683 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16688 pm_token_t string_opening = not_provided(parser);
16689 pm_token_t string_closing = not_provided(parser);
16691 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16692 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16696 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16702 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16703 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16705 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16706 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16709 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16722 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16728 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16729 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16731 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16732 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16735 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16741 if (current == NULL) {
16757 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16767 pm_interpolated_string_node_append(container, current);
16778 #define PM_PARSE_PATTERN_SINGLE 0
16779 #define PM_PARSE_PATTERN_TOP 1
16780 #define PM_PARSE_PATTERN_MULTI 2
16793 if (*location->
start ==
'_')
return;
16796 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16812 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16831 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16838 parser_lex(parser);
16843 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16854 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16870 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16871 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16886 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16887 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16902 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16903 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16917 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16918 pm_array_pattern_node_requireds_append(pattern_node, inner);
16936 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16939 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16940 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16943 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16944 name = (
pm_node_t *) pm_local_variable_target_node_create(
16946 &PM_LOCATION_TOKEN_VALUE(&identifier),
16948 (uint32_t) (depth == -1 ? 0 : depth)
16953 return pm_splat_node_create(parser, &
operator, name);
16962 parser_lex(parser);
16968 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
16975 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16979 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16980 value = (
pm_node_t *) pm_local_variable_target_node_create(
16982 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16984 (uint32_t) (depth == -1 ? 0 : depth)
16988 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
16996 pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16997 ptrdiff_t length = end - start;
16998 if (length == 0)
return false;
17001 size_t width = char_is_identifier_start(parser, start);
17002 if (width == 0)
return false;
17013 const uint8_t *cursor = start + width;
17014 while ((cursor < end) && (width = char_is_identifier(parser, cursor))) cursor += width;
17015 return cursor == end;
17029 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17030 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17032 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17034 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17035 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);
17040 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17043 parse_pattern_capture(parser, captures, constant_id, value_loc);
17048 (uint32_t) (depth == -1 ? 0 : depth)
17061 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17080 if (pm_symbol_node_label_p(first_node)) {
17081 parse_pattern_hash_key(parser, &keys, first_node);
17087 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17091 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17095 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17107 pm_parser_err_node(parser, first_node, diag_id);
17111 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17123 if (rest != NULL) {
17124 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17131 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17133 if (rest == NULL) {
17136 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17143 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17146 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17147 }
else if (!pm_symbol_node_label_p(key)) {
17148 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17151 expect1(parser,
PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17155 parse_pattern_hash_key(parser, &keys, key);
17159 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17161 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17165 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17167 if (rest != NULL) {
17168 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17187 switch (parser->
current.type) {
17190 parser_lex(parser);
17194 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17198 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17199 return (
pm_node_t *) pm_local_variable_target_node_create(
17201 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17203 (uint32_t) (depth == -1 ? 0 : depth)
17208 parser_lex(parser);
17213 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17218 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17231 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17232 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17245 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17246 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17258 pm_array_pattern_node_requireds_append(node, inner);
17267 parser_lex(parser);
17272 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17276 switch (parser->
current.type) {
17278 parser_lex(parser);
17279 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17282 first_node = parse_pattern_keyword_rest(parser, captures);
17285 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17289 parser_lex(parser);
17296 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17305 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17306 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17315 parser_lex(parser);
17319 switch (parser->
current.type) {
17320 case PM_CASE_PRIMITIVE: {
17321 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17322 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17325 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17326 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17327 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17331 case PM_CASE_PRIMITIVE: {
17332 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17335 if (pm_symbol_node_label_p(node))
return node;
17344 switch (parser->
current.type) {
17345 case PM_CASE_PRIMITIVE: {
17346 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17347 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17350 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17357 parser_lex(parser);
17362 switch (parser->
current.type) {
17364 parser_lex(parser);
17367 if (variable == NULL) {
17368 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17369 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17372 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17375 parser_lex(parser);
17378 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17381 parser_lex(parser);
17384 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17387 parser_lex(parser);
17390 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17393 parser_lex(parser);
17396 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17399 parser_lex(parser);
17402 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17409 parser_lex(parser);
17411 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17416 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17421 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17422 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17423 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17429 parser_lex(parser);
17434 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17438 parser_lex(parser);
17441 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17444 pm_parser_err_current(parser, diag_id);
17460 switch (parser->
current.type) {
17469 case PM_CASE_PRIMITIVE: {
17470 if (node == NULL) {
17471 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17473 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17474 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17482 parser_lex(parser);
17484 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17489 if (node == NULL) {
17492 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17498 pm_parser_err_current(parser, diag_id);
17501 if (node == NULL) {
17504 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17521 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17525 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17528 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17530 (uint32_t) (depth == -1 ? 0 : depth)
17533 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17546 bool leading_rest =
false;
17547 bool trailing_rest =
false;
17549 switch (parser->
current.type) {
17551 parser_lex(parser);
17553 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17555 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17556 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17562 node = parse_pattern_keyword_rest(parser, captures);
17563 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17565 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17566 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17574 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17576 if (pm_symbol_node_label_p(node)) {
17577 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17579 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17580 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17586 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17590 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17591 parser_lex(parser);
17592 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17593 leading_rest =
true;
17599 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17605 if (pm_symbol_node_label_p(node)) {
17606 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17609 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser,
PM_TOKEN_COMMA)) {
17622 trailing_rest =
true;
17627 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17632 if (trailing_rest) {
17633 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17636 trailing_rest =
true;
17638 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17649 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17651 if (nodes.
size == 2) {
17652 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17655 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17657 if (leading_rest && trailing_rest) {
17658 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17663 }
else if (leading_rest) {
17666 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17678 parse_negative_numeric(
pm_node_t *node) {
17703 assert(
false &&
"unreachable");
17716 case PM_ERR_HASH_KEY: {
17720 case PM_ERR_HASH_VALUE:
17721 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17725 case PM_ERR_UNARY_RECEIVER: {
17730 case PM_ERR_UNARY_DISALLOWED:
17731 case PM_ERR_EXPECT_ARGUMENT: {
17736 pm_parser_err_previous(parser, diag_id);
17746 #define CONTEXT_NONE 0
17747 #define CONTEXT_THROUGH_ENSURE 1
17748 #define CONTEXT_THROUGH_ELSE 2
17751 int context = CONTEXT_NONE;
17753 while (context_node != NULL) {
17754 switch (context_node->
context) {
17775 if (context == CONTEXT_NONE) {
17776 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17777 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17778 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17779 }
else if (context == CONTEXT_THROUGH_ELSE) {
17780 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17792 context = CONTEXT_THROUGH_ELSE;
17803 context = CONTEXT_THROUGH_ENSURE;
17807 assert(
false &&
"unreachable");
17837 context_node = context_node->
prev;
17840 #undef CONTEXT_NONE
17841 #undef CONTEXT_ENSURE
17842 #undef CONTEXT_ELSE
17852 while (context_node != NULL) {
17853 switch (context_node->
context) {
17878 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17882 assert(
false &&
"unreachable");
17923 context_node = context_node->
prev;
17955 parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17959 if (callback_data->
shared) {
17965 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
17978 .shared = unescaped->
type == PM_STRING_SHARED
17988 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) {
17989 switch (parser->
current.type) {
17991 parser_lex(parser);
17994 pm_accepts_block_stack_push(parser,
true);
17995 bool parsed_bare_hash =
false;
18011 if (accepted_newline) {
18012 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18037 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18039 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18042 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18044 if (parsed_bare_hash) {
18045 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18048 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18052 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18056 parsed_bare_hash =
true;
18058 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18061 if (parsed_bare_hash) {
18062 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18067 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18073 operator = not_provided(parser);
18076 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18077 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18078 pm_keyword_hash_node_elements_append(hash, assoc);
18082 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18086 parsed_bare_hash =
true;
18090 pm_array_node_elements_append(array, element);
18102 pm_array_node_close_set(array, &parser->
previous);
18103 pm_accepts_block_stack_pop(parser);
18112 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18114 parser_lex(parser);
18122 pop_block_exits(parser, previous_block_exits);
18125 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous);
18130 pm_accepts_block_stack_push(parser,
true);
18132 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18133 context_pop(parser);
18139 if (terminator_found) {
18148 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18151 parser_lex(parser);
18152 pm_accepts_block_stack_pop(parser);
18154 pop_block_exits(parser, previous_block_exits);
18166 multi_target = pm_multi_target_node_create(parser);
18167 pm_multi_target_node_targets_append(parser, multi_target, statement);
18170 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18179 if (match1(parser,
PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18180 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18192 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18195 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18200 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18210 pm_statements_node_body_append(parser, statements, statement,
true);
18220 pm_statements_node_body_append(parser, statements, statement,
true);
18224 if (!terminator_found && !match1(parser,
PM_TOKEN_EOF)) {
18230 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18231 pm_statements_node_body_append(parser, statements, node,
true);
18260 context_pop(parser);
18261 pm_accepts_block_stack_pop(parser);
18273 pm_multi_target_node_targets_append(parser, multi_target, statement);
18275 statement = (
pm_node_t *) multi_target;
18287 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18291 pop_block_exits(parser, previous_block_exits);
18294 pm_void_statements_check(parser, statements,
true);
18308 pm_accepts_block_stack_push(parser,
true);
18309 parser_lex(parser);
18314 if (current_hash_keys != NULL) {
18315 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18318 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18325 pm_accepts_block_stack_pop(parser);
18327 pm_hash_node_closing_loc_set(node, &parser->
previous);
18332 parser_lex(parser);
18343 pm_node_t *node = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18344 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18349 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18355 parser_lex(parser);
18358 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18359 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18365 parser_lex(parser);
18377 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18378 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18383 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18386 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18392 parser_lex(parser);
18398 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18399 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18407 parser_lex(parser);
18409 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));
18416 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18419 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18422 parser_lex(parser);
18425 parser_lex(parser);
18426 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18428 parser_lex(parser);
18431 parser_lex(parser);
18432 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18434 parser_lex(parser);
18437 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18438 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18444 parser_lex(parser);
18447 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18448 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18454 parser_lex(parser);
18457 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18458 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18465 parser_lex(parser);
18467 pm_node_t *node = parse_variable_call(parser);
18477 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18487 if (arguments.
block != NULL) {
18509 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18510 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18516 parse_target_implicit_parameter(parser, node);
18524 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18525 parse_target_implicit_parameter(parser, node);
18528 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18537 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18538 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18549 size_t common_whitespace = (size_t) -1;
18552 parser_lex(parser);
18564 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18571 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18584 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18587 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18591 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18596 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18597 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18610 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18617 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18619 cast->
parts = parts;
18622 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18631 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18639 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18641 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18647 parse_heredoc_dedent(parser, nodes, common_whitespace);
18652 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18658 parser_lex(parser);
18661 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18662 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18669 parser_lex(parser);
18674 parser_lex(parser);
18675 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18679 parser_lex(parser);
18680 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18684 parser_lex(parser);
18685 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18688 parser_lex(parser);
18689 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18691 parser_lex(parser);
18694 parser_lex(parser);
18697 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18698 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18701 parser_lex(parser);
18704 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18705 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18713 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18716 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18719 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18724 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18729 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18733 size_t opening_newline_index = token_newline_index(parser);
18734 parser_lex(parser);
18740 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18747 }
else if (!token_begins_expression_p(parser->
current.type)) {
18750 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18755 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18756 parser_lex(parser);
18758 pop_block_exits(parser, previous_block_exits);
18761 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18762 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18767 pm_token_t end_keyword = not_provided(parser);
18771 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18778 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18779 parser_lex(parser);
18782 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18787 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18789 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18790 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18794 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18795 pm_when_node_conditions_append(when_node, condition);
18806 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18809 pm_when_clause_static_literals_add(parser, &literals, condition);
18815 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18819 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18824 if (statements != NULL) {
18825 pm_when_node_statements_set(when_node, statements);
18829 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18835 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18841 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18845 if (predicate == NULL) {
18846 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18853 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18858 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18860 parser_lex(parser);
18865 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));
18875 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18876 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
18879 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18880 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
18891 then_keyword = not_provided(parser);
18909 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
18910 pm_case_match_node_condition_append(case_node, condition);
18916 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18928 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18930 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18934 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18940 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18949 pop_block_exits(parser, previous_block_exits);
18955 size_t opening_newline_index = token_newline_index(parser);
18956 parser_lex(parser);
18962 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18966 pm_accepts_block_stack_push(parser,
true);
18967 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18968 pm_accepts_block_stack_pop(parser);
18972 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18973 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18977 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
18979 pop_block_exits(parser, previous_block_exits);
18986 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18988 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18989 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18992 parser_lex(parser);
19002 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19005 flush_block_exits(parser, previous_block_exits);
19008 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19013 parser_lex(parser);
19019 token_begins_expression_p(parser->
current.type) ||
19022 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19024 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19025 parse_arguments(parser, &arguments,
false,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
19029 switch (keyword.
type) {
19042 parse_return(parser, node);
19046 assert(
false &&
"unreachable");
19051 parser_lex(parser);
19055 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19062 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19065 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19068 parser_lex(parser);
19072 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19078 if (arguments.
block != NULL) {
19079 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19081 arguments.
block = NULL;
19090 size_t opening_newline_index = token_newline_index(parser);
19091 parser_lex(parser);
19094 pm_do_loop_stack_push(parser,
false);
19097 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19101 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));
19103 pm_parser_scope_push(parser,
true);
19110 pm_accepts_block_stack_push(parser,
true);
19112 pm_accepts_block_stack_pop(parser);
19117 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));
19119 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19127 pm_parser_scope_pop(parser);
19128 pm_do_loop_stack_pop(parser);
19130 flush_block_exits(parser, previous_block_exits);
19133 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19136 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19139 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19146 inheritance_operator = parser->
current;
19147 lex_state_set(parser, PM_LEX_STATE_BEG);
19150 parser_lex(parser);
19152 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19154 inheritance_operator = not_provided(parser);
19158 pm_parser_scope_push(parser,
true);
19168 pm_accepts_block_stack_push(parser,
true);
19170 pm_accepts_block_stack_pop(parser);
19175 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));
19177 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19182 if (context_def_p(parser)) {
19183 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19189 pm_parser_scope_pop(parser);
19190 pm_do_loop_stack_pop(parser);
19193 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19196 pop_block_exits(parser, previous_block_exits);
19199 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19203 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19206 size_t opening_newline_index = token_newline_index(parser);
19216 parser_lex(parser);
19220 bool valid_name =
true;
19222 switch (parser->
current.type) {
19223 case PM_CASE_OPERATOR:
19224 pm_parser_scope_push(parser,
true);
19225 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19226 parser_lex(parser);
19231 parser_lex(parser);
19234 receiver = parse_variable_call(parser);
19236 pm_parser_scope_push(parser,
true);
19237 lex_state_set(parser, PM_LEX_STATE_FNAME);
19238 parser_lex(parser);
19241 name = parse_method_definition_name(parser);
19244 pm_parser_scope_push(parser,
true);
19254 valid_name =
false;
19264 pm_parser_scope_push(parser,
true);
19265 parser_lex(parser);
19270 lex_state_set(parser, PM_LEX_STATE_FNAME);
19271 parser_lex(parser);
19274 switch (identifier.
type) {
19276 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19279 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19282 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19285 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19288 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19291 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19294 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19297 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19300 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19303 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19306 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19312 name = parse_method_definition_name(parser);
19327 context_pop(parser);
19328 parser_lex(parser);
19331 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19337 lex_state_set(parser, PM_LEX_STATE_FNAME);
19341 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
19345 pm_parser_scope_push(parser,
true);
19347 name = parse_method_definition_name(parser);
19351 pm_parser_scope_push(parser,
true);
19352 name = parse_method_definition_name(parser);
19360 switch (parser->
current.type) {
19362 parser_lex(parser);
19368 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true, (uint16_t) (depth + 1));
19371 lex_state_set(parser, PM_LEX_STATE_BEG);
19374 context_pop(parser);
19384 case PM_CASE_PARAMETER: {
19388 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19391 lparen = not_provided(parser);
19392 rparen = not_provided(parser);
19393 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true, (uint16_t) (depth + 1));
19395 context_pop(parser);
19399 lparen = not_provided(parser);
19400 rparen = not_provided(parser);
19403 context_pop(parser);
19413 if (token_is_setter_name(&name)) {
19414 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19419 pm_do_loop_stack_push(parser,
false);
19420 statements = (
pm_node_t *) pm_statements_node_create(parser);
19422 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));
19428 pm_node_t *value = parse_expression(parser, binding_power,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
19429 context_pop(parser);
19431 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19434 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19435 pm_do_loop_stack_pop(parser);
19436 context_pop(parser);
19437 end_keyword = not_provided(parser);
19439 equal = not_provided(parser);
19442 lex_state_set(parser, PM_LEX_STATE_BEG);
19449 pm_accepts_block_stack_push(parser,
true);
19450 pm_do_loop_stack_push(parser,
false);
19453 pm_accepts_block_stack_push(parser,
true);
19455 pm_accepts_block_stack_pop(parser);
19460 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));
19462 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19465 pm_accepts_block_stack_pop(parser);
19466 pm_do_loop_stack_pop(parser);
19474 pm_parser_scope_pop(parser);
19481 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
19483 flush_block_exits(parser, previous_block_exits);
19486 return (
pm_node_t *) pm_def_node_create(
19503 parser_lex(parser);
19513 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19516 rparen = not_provided(parser);
19523 lparen = not_provided(parser);
19524 rparen = not_provided(parser);
19525 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19528 context_pop(parser);
19529 return (
pm_node_t *) pm_defined_node_create(
19534 &PM_LOCATION_TOKEN_VALUE(&keyword)
19538 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19539 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19542 parser_lex(parser);
19545 if (context_def_p(parser)) {
19546 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19554 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19557 parser_lex(parser);
19560 size_t opening_newline_index = token_newline_index(parser);
19561 parser_lex(parser);
19573 if (token_begins_expression_p(parser->
current.type)) {
19574 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19577 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19578 }
else if (token_begins_expression_p(parser->
current.type)) {
19579 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19581 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19582 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19587 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19589 index = parse_target(parser, index,
false,
false);
19592 context_pop(parser);
19593 pm_do_loop_stack_push(parser,
true);
19598 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19599 pm_do_loop_stack_pop(parser);
19605 do_keyword = not_provided(parser);
19613 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19616 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19619 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19622 if (parser_end_of_line_p(parser)) {
19623 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19626 size_t opening_newline_index = token_newline_index(parser);
19628 parser_lex(parser);
19630 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19632 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19633 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19636 parser_lex(parser);
19638 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19643 pm_undef_node_append(undef, name);
19646 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19647 parser_lex(parser);
19648 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19655 pm_undef_node_append(undef, name);
19662 parser_lex(parser);
19676 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19685 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19688 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19691 size_t opening_newline_index = token_newline_index(parser);
19692 parser_lex(parser);
19694 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19698 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19700 size_t opening_newline_index = token_newline_index(parser);
19701 parser_lex(parser);
19704 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19710 pop_block_exits(parser, previous_block_exits);
19714 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19721 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19729 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19732 pm_parser_scope_push(parser,
true);
19737 pm_accepts_block_stack_push(parser,
true);
19739 pm_accepts_block_stack_pop(parser);
19744 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));
19746 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19752 pm_parser_scope_pop(parser);
19755 if (context_def_p(parser)) {
19756 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19759 pop_block_exits(parser, previous_block_exits);
19762 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19765 parser_lex(parser);
19768 parser_lex(parser);
19776 parser_lex(parser);
19779 parse_retry(parser, node);
19784 parser_lex(parser);
19787 parser_lex(parser);
19790 size_t opening_newline_index = token_newline_index(parser);
19793 pm_do_loop_stack_push(parser,
true);
19795 parser_lex(parser);
19797 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19799 pm_do_loop_stack_pop(parser);
19800 context_pop(parser);
19806 pm_accepts_block_stack_push(parser,
true);
19807 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19808 pm_accepts_block_stack_pop(parser);
19812 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19815 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &parser->
previous, predicate, statements, 0);
19818 size_t opening_newline_index = token_newline_index(parser);
19821 pm_do_loop_stack_push(parser,
true);
19823 parser_lex(parser);
19825 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19827 pm_do_loop_stack_pop(parser);
19828 context_pop(parser);
19834 pm_accepts_block_stack_push(parser,
true);
19835 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19836 pm_accepts_block_stack_pop(parser);
19840 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19843 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &parser->
previous, predicate, statements, 0);
19846 parser_lex(parser);
19857 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19865 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19870 pm_array_node_close_set(array, &closing);
19875 parser_lex(parser);
19884 switch (parser->
current.type) {
19886 if (current == NULL) {
19892 pm_array_node_elements_append(array, current);
19896 parser_lex(parser);
19903 if (current == NULL) {
19907 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
19908 parser_lex(parser);
19914 parser_lex(parser);
19926 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
19927 parser_lex(parser);
19930 pm_interpolated_symbol_node_append(interpolated, first_string);
19931 pm_interpolated_symbol_node_append(interpolated, second_string);
19936 assert(
false &&
"unreachable");
19942 bool start_location_set =
false;
19943 if (current == NULL) {
19949 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19959 pm_interpolated_symbol_node_append(interpolated, current);
19961 start_location_set =
true;
19968 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19970 if (!start_location_set) {
19976 bool start_location_set =
false;
19977 if (current == NULL) {
19983 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19994 pm_interpolated_symbol_node_append(interpolated, current);
19996 start_location_set =
true;
20002 assert(
false &&
"unreachable");
20005 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20007 if (!start_location_set) {
20014 parser_lex(parser);
20021 pm_array_node_elements_append(array, current);
20026 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20031 pm_array_node_close_set(array, &closing);
20036 parser_lex(parser);
20052 pm_array_node_elements_append(array,
string);
20060 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20066 pm_array_node_close_set(array, &closing);
20070 parser_lex(parser);
20079 switch (parser->
current.type) {
20085 if (current == NULL) {
20092 pm_array_node_elements_append(array, current);
20096 parser_lex(parser);
20104 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20105 parser_lex(parser);
20107 if (current == NULL) {
20124 pm_interpolated_string_node_append(interpolated, current);
20125 pm_interpolated_string_node_append(interpolated,
string);
20128 assert(
false &&
"unreachable");
20134 if (current == NULL) {
20141 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20150 pm_interpolated_string_node_append(interpolated, current);
20158 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20163 if (current == NULL) {
20170 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20179 pm_interpolated_string_node_append(interpolated, current);
20186 assert(
false &&
"unreachable");
20189 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20195 parser_lex(parser);
20202 pm_array_node_elements_append(array, current);
20207 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20213 pm_array_node_close_set(array, &closing);
20218 parser_lex(parser);
20230 parser_lex(parser);
20248 parser_lex(parser);
20261 parse_regular_expression_errors(parser, node);
20264 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20270 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20283 pm_interpolated_regular_expression_node_append(interpolated, part);
20288 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20295 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20296 pm_interpolated_regular_expression_node_append(interpolated, part);
20302 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20308 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20313 parser_lex(parser);
20330 parser_lex(parser);
20331 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20343 parser_lex(parser);
20346 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20347 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20348 parser_lex(parser);
20354 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20360 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20362 pm_interpolated_xstring_node_append(node, part);
20367 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20372 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20373 pm_interpolated_xstring_node_append(node, part);
20379 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20384 pm_interpolated_xstring_node_closing_set(node, &closing);
20389 parser_lex(parser);
20394 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20395 pm_parser_err_prefix(parser, diag_id);
20402 if (token_begins_expression_p(parser->
current.type)) {
20403 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20409 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20411 return parse_target_validate(parser, splat,
true);
20415 if (binding_power > PM_BINDING_POWER_UNARY) {
20416 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20419 parser_lex(parser);
20422 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));
20423 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20425 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20429 if (binding_power > PM_BINDING_POWER_UNARY) {
20430 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20432 parser_lex(parser);
20435 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20436 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20441 if (binding_power > PM_BINDING_POWER_UNARY) {
20442 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20444 parser_lex(parser);
20447 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20448 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20453 parser_lex(parser);
20456 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20460 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20461 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20462 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20469 parse_negative_numeric(node);
20472 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20483 size_t opening_newline_index = token_newline_index(parser);
20484 pm_accepts_block_stack_push(parser,
true);
20485 parser_lex(parser);
20488 pm_parser_scope_push(parser,
false);
20492 switch (parser->
current.type) {
20495 parser_lex(parser);
20498 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20500 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20506 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20509 case PM_CASE_PARAMETER: {
20510 pm_accepts_block_stack_push(parser,
false);
20512 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20513 pm_accepts_block_stack_pop(parser);
20517 block_parameters = NULL;
20533 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20540 pm_accepts_block_stack_push(parser,
true);
20542 pm_accepts_block_stack_pop(parser);
20547 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));
20549 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20556 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20559 pm_parser_scope_pop(parser);
20560 pm_accepts_block_stack_pop(parser);
20562 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20565 if (binding_power > PM_BINDING_POWER_UNARY) {
20566 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20568 parser_lex(parser);
20571 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20572 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20577 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20580 parser_lex(parser);
20582 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20593 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20594 pm_parser_err_prefix(parser, diag_id);
20600 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20601 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20607 pm_parser_err_prefix(parser, diag_id);
20625 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) {
20626 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));
20634 parser_lex(parser);
20636 pm_node_t *right = parse_expression(parser, binding_power,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20637 context_pop(parser);
20639 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20659 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20664 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20672 parse_assignment_value_local(parser, statement);
20694 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) {
20695 bool permitted =
true;
20696 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_USTAR)) permitted =
false;
20698 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));
20699 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20701 parse_assignment_value_local(parser, value);
20702 bool single_value =
true;
20705 single_value =
false;
20710 pm_array_node_elements_append(array, value);
20714 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20716 pm_array_node_elements_append(array, element);
20719 parse_assignment_value_local(parser, element);
20729 parser_lex(parser);
20731 bool accepts_command_call_inner =
false;
20738 accepts_command_call_inner =
true;
20742 pm_node_t *right = parse_expression(parser, binding_power, accepts_command_call_inner,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20743 context_pop(parser);
20745 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20761 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20766 if (call_node->
block != NULL) {
20767 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20769 call_node->
block = NULL;
20803 parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20818 if (!pm_slice_is_valid_local(parser, source, source + length))
return;
20820 if (callback_data->
shared) {
20824 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20830 void *memory =
xmalloc(length);
20831 if (memory == NULL) abort();
20833 memcpy(memory, source, length);
20834 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20843 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20846 if (pm_local_is_keyword((
const char *) source, length))
return;
20850 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20855 if (callback_data->
match == NULL) {
20856 callback_data->
match = pm_match_write_node_create(parser, call);
20861 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
20876 .shared = content->
type == PM_STRING_SHARED
20883 .shared = content->
type == PM_STRING_SHARED
20889 if (callback_data.
match != NULL) {
20897 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) {
20900 switch (token.type) {
20914 case PM_CASE_WRITABLE: {
20915 parser_lex(parser);
20916 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));
20919 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20922 return parse_write(parser, node, &token, value);
20926 pm_multi_target_node_targets_append(parser, multi_target, node);
20928 parser_lex(parser);
20929 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));
20930 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
20941 parser_lex(parser);
20942 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));
20943 return parse_unwriteable_write(parser, node, &token, value);
20949 parser_lex(parser);
20950 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20958 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20961 parser_lex(parser);
20963 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));
20964 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
20970 parser_lex(parser);
20972 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));
20979 parser_lex(parser);
20981 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));
20984 return parse_shareable_constant_write(parser, write);
20987 parser_lex(parser);
20989 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));
20993 return parse_shareable_constant_write(parser, write);
20996 parser_lex(parser);
20998 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));
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));
21022 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
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));
21028 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21036 parser_lex(parser);
21042 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));
21043 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21047 if (pm_call_node_writable_p(parser, cast)) {
21048 parse_write_name(parser, &cast->
name);
21050 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21053 parse_call_operator_write(parser, cast, &token);
21054 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));
21055 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21058 parser_lex(parser);
21059 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21063 parser_lex(parser);
21068 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21076 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21079 parser_lex(parser);
21081 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));
21082 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21088 parser_lex(parser);
21090 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));
21097 parser_lex(parser);
21099 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));
21102 return parse_shareable_constant_write(parser, write);
21105 parser_lex(parser);
21107 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));
21111 return parse_shareable_constant_write(parser, write);
21114 parser_lex(parser);
21116 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));
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));
21140 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
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));
21146 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21154 parser_lex(parser);
21160 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));
21161 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21165 if (pm_call_node_writable_p(parser, cast)) {
21166 parse_write_name(parser, &cast->
name);
21168 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21171 parse_call_operator_write(parser, cast, &token);
21172 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));
21173 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21176 parser_lex(parser);
21177 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21181 parser_lex(parser);
21186 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21204 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21207 parser_lex(parser);
21209 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));
21210 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21216 parser_lex(parser);
21218 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));
21225 parser_lex(parser);
21227 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));
21230 return parse_shareable_constant_write(parser, write);
21233 parser_lex(parser);
21235 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));
21239 return parse_shareable_constant_write(parser, write);
21242 parser_lex(parser);
21244 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));
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));
21255 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21261 parser_lex(parser);
21269 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21272 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));
21273 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21283 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));
21284 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21288 if (pm_call_node_writable_p(parser, cast)) {
21289 parse_write_name(parser, &cast->
name);
21291 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21294 parse_call_operator_write(parser, cast, &token);
21295 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));
21296 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21299 parser_lex(parser);
21300 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21304 parser_lex(parser);
21315 parser_lex(parser);
21318 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21322 parser_lex(parser);
21325 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21335 parser_lex(parser);
21336 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21339 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21352 bool interpolated =
false;
21353 size_t total_length = 0;
21360 interpolated =
true;
21365 if (!interpolated && total_length > 0) {
21366 void *memory =
xmalloc(total_length);
21367 if (!memory) abort();
21369 uint8_t *cursor = memory;
21414 parser_lex(parser);
21415 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21416 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21423 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21426 parser_lex(parser);
21427 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21428 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21432 parser_lex(parser);
21438 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21439 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21444 switch (parser->
current.type) {
21445 case PM_CASE_OPERATOR:
21446 case PM_CASE_KEYWORD:
21450 parser_lex(parser);
21460 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21461 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21464 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21469 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21476 parser_lex(parser);
21479 if (token_begins_expression_p(parser->
current.type)) {
21480 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21483 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21487 parser_lex(parser);
21489 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21490 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21494 parser_lex(parser);
21496 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21497 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21500 parser_lex(parser);
21502 pm_statements_node_body_append(parser, statements, node,
true);
21504 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21508 parser_lex(parser);
21510 pm_statements_node_body_append(parser, statements, node,
true);
21512 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21518 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21521 parser_lex(parser);
21523 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21535 context_pop(parser);
21536 pop_block_exits(parser, previous_block_exits);
21539 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21546 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21548 context_pop(parser);
21549 pop_block_exits(parser, previous_block_exits);
21552 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21555 parser_lex(parser);
21558 switch (parser->
current.type) {
21560 parser_lex(parser);
21576 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21577 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21580 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21584 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21585 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21590 case PM_CASE_OPERATOR:
21591 case PM_CASE_KEYWORD:
21594 parser_lex(parser);
21600 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21601 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21604 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21605 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21614 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21616 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
21620 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21626 parser_lex(parser);
21629 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21630 context_pop(parser);
21632 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
21635 parser_lex(parser);
21641 pm_accepts_block_stack_push(parser,
true);
21643 pm_accepts_block_stack_pop(parser);
21651 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21652 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21653 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21661 block = parse_block(parser, (uint16_t) (depth + 1));
21662 pm_arguments_validate_block(parser, &arguments, block);
21664 block = parse_block(parser, (uint16_t) (depth + 1));
21667 if (block != NULL) {
21668 if (arguments.
block != NULL) {
21669 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
21671 arguments.
arguments = pm_arguments_node_create(parser);
21673 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21679 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
21687 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21688 parser_lex(parser);
21691 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));
21696 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
21704 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21705 parser_lex(parser);
21708 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));
21713 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
21716 assert(
false &&
"unreachable");
21721 #undef PM_PARSE_PATTERN_SINGLE
21722 #undef PM_PARSE_PATTERN_TOP
21723 #undef PM_PARSE_PATTERN_MULTI
21747 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) {
21749 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21753 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21768 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21778 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21786 if (pm_symbol_node_label_p(node)) {
21799 current_token_type = parser->
current.type,
21800 current_binding_powers = pm_binding_powers[current_token_type],
21801 binding_power <= current_binding_powers.
left &&
21802 current_binding_powers.
binary
21804 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21810 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21822 if (
PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21830 if (
PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21840 if (current_binding_powers.
nonassoc) {
21843 if (match1(parser, current_token_type)) {
21861 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21864 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21869 if (accepts_command_call) {
21878 switch (node->
type) {
21893 cast->
block == NULL &&
21906 accepts_command_call =
false;
21914 accepts_command_call =
false;
21929 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21931 pm_arguments_node_arguments_append(
21933 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
21936 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
21939 pm_parser_constant_id_constant(parser,
"print", 5)
21943 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21944 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21946 pm_arguments_node_arguments_append(
21948 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
21951 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21952 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
21956 pm_parser_constant_id_constant(parser,
"$F", 2),
21960 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
21964 pm_arguments_node_arguments_append(
21966 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
21969 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21971 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
21973 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
21975 (
pm_node_t *) pm_true_node_synthesized_create(parser)
21978 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
21983 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
21985 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
21989 statements = wrapped_statements;
22004 pm_parser_scope_push(parser,
true);
22008 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22010 parser_lex(parser);
22013 if (statements == NULL) {
22014 statements = pm_statements_node_create(parser);
22019 assert(statements->
body.
size > 0);
22020 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22025 pm_parser_scope_pop(parser);
22030 if (pm_statements_node_body_length(statements) == 0) {
22031 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22037 statements = wrap_statements(parser, statements);
22039 flush_block_exits(parser, previous_block_exits);
22043 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22059 static const char *
22060 pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22061 size_t little_length = strlen(little);
22063 for (
const char *big_end = big + big_length; big < big_end; big++) {
22064 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22071 #define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22079 pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22080 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22081 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22091 pm_parser_init_shebang(
pm_parser_t *parser,
const pm_options_t *options,
const char *engine,
size_t length) {
22092 const char *switches = pm_strnstr(engine,
" -", length);
22093 if (switches == NULL)
return;
22098 (
const uint8_t *) (switches + 1),
22099 length - ((
size_t) (switches - engine)) - 1,
22103 size_t encoding_length;
22106 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22118 assert(source != NULL);
22122 .lex_state = PM_LEX_STATE_BEG,
22123 .enclosure_nesting = 0,
22124 .lambda_enclosure_nesting = -1,
22125 .brace_nesting = 0,
22126 .do_loop_stack = 0,
22127 .accepts_block_stack = 0,
22130 .stack = {{ .mode = PM_LEX_DEFAULT }},
22134 .end = source + size,
22135 .previous = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22136 .current = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22137 .next_start = NULL,
22138 .heredoc_end = NULL,
22139 .data_loc = { .start = NULL, .end = NULL },
22140 .comment_list = { 0 },
22141 .magic_comment_list = { 0 },
22142 .warning_list = { 0 },
22143 .error_list = { 0 },
22144 .current_scope = NULL,
22145 .current_context = NULL,
22147 .encoding_changed_callback = NULL,
22148 .encoding_comment_start = source,
22149 .lex_callback = NULL,
22151 .constant_pool = { 0 },
22152 .newline_list = { 0 },
22156 .explicit_encoding = NULL,
22158 .parsing_eval =
false,
22159 .partial_script =
false,
22160 .command_start =
true,
22161 .recovering =
false,
22162 .encoding_locked =
false,
22163 .encoding_changed =
false,
22164 .pattern_matching_newlines =
false,
22165 .in_keyword_arg =
false,
22166 .current_block_exits = NULL,
22167 .semantic_token_seen =
false,
22169 .current_regular_expression_ascii_only =
false,
22170 .warn_mismatched_indentation =
true
22187 uint32_t constant_size = ((uint32_t) size) / 95;
22193 size_t newline_size = size / 22;
22197 if (options != NULL) {
22206 if (encoding_length > 0) {
22208 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22230 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22232 pm_parser_scope_push(parser, scope_index == 0);
22238 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22244 void *allocated =
xmalloc(length);
22245 if (allocated == NULL)
continue;
22247 memcpy(allocated, source, length);
22248 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22253 pm_accepts_block_stack_push(parser,
true);
22256 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22269 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22286 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22287 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22289 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22290 const char *engine;
22292 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22293 if (newline != NULL) {
22297 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22302 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22305 search_shebang =
false;
22307 search_shebang =
true;
22313 if (search_shebang) {
22316 bool found_shebang =
false;
22320 const uint8_t *cursor = parser->
start;
22324 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22326 while (newline != NULL) {
22329 cursor = newline + 1;
22330 newline = next_newline(cursor, parser->
end - cursor);
22332 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22333 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22334 const char *engine;
22335 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22336 found_shebang =
true;
22338 if (newline != NULL) {
22339 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22344 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22352 if (found_shebang) {
22356 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22380 pm_comment_list_free(
pm_list_t *list) {
22383 for (node = list->
head; node != NULL; node = next) {
22395 pm_magic_comment_list_free(
pm_list_t *list) {
22398 for (node = list->
head; node != NULL; node = next) {
22424 pm_parser_scope_pop(parser);
22428 lex_mode_pop(parser);
22437 return parse_program(parser);
22447 #define LINE_SIZE 4096
22448 char line[LINE_SIZE];
22450 while (memset(line,
'\n', LINE_SIZE), fgets(line, LINE_SIZE, stream) != NULL) {
22451 size_t length = LINE_SIZE;
22452 while (length > 0 && line[length - 1] ==
'\n') length--;
22454 if (length == LINE_SIZE) {
22473 if (strncmp(line,
"__END__", 7) == 0)
return false;
22476 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22479 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22498 pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22502 if (diagnostic->
diag_id == PM_ERR_HEREDOC_TERM) {
22520 bool eof = pm_parse_stream_read(buffer, stream, fgets);
22526 eof = pm_parse_stream_read(buffer, stream, fgets);
22557 #undef PM_CASE_KEYWORD
22558 #undef PM_CASE_OPERATOR
22559 #undef PM_CASE_WRITABLE
22560 #undef PM_STRING_EMPTY
22561 #undef PM_LOCATION_NODE_BASE_VALUE
22562 #undef PM_LOCATION_NODE_VALUE
22563 #undef PM_LOCATION_NULL_VALUE
22564 #undef PM_LOCATION_TOKEN_VALUE
22569 #ifndef PRISM_EXCLUDE_SERIALIZATION
22585 pm_serialize_header(buffer);
22604 pm_serialize_header(buffer);
22625 pm_serialize_header(buffer);
22647 pm_serialize_header(buffer);
22666 PM_SLICE_TYPE_ERROR = -1,
22669 PM_SLICE_TYPE_NONE,
22672 PM_SLICE_TYPE_LOCAL,
22675 PM_SLICE_TYPE_CONSTANT,
22678 PM_SLICE_TYPE_METHOD_NAME
22685 pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22687 const pm_encoding_t *encoding =
pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22688 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22691 if (length == 0)
return PM_SLICE_TYPE_NONE;
22694 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22696 }
else if (*source ==
'_') {
22699 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22703 return PM_SLICE_TYPE_NONE;
22707 const uint8_t *end = source + length;
22708 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22714 while (source < end) {
22715 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22718 }
else if (*source ==
'_') {
22721 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22731 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22733 result = PM_SLICE_TYPE_METHOD_NAME;
22737 return source == end ? result : PM_SLICE_TYPE_NONE;
22745 switch (pm_slice_type(source, length, encoding_name)) {
22746 case PM_SLICE_TYPE_ERROR:
22748 case PM_SLICE_TYPE_NONE:
22749 case PM_SLICE_TYPE_CONSTANT:
22750 case PM_SLICE_TYPE_METHOD_NAME:
22752 case PM_SLICE_TYPE_LOCAL:
22756 assert(
false &&
"unreachable");
22765 switch (pm_slice_type(source, length, encoding_name)) {
22766 case PM_SLICE_TYPE_ERROR:
22768 case PM_SLICE_TYPE_NONE:
22769 case PM_SLICE_TYPE_LOCAL:
22770 case PM_SLICE_TYPE_METHOD_NAME:
22772 case PM_SLICE_TYPE_CONSTANT:
22776 assert(
false &&
"unreachable");
22785 #define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22786 #define C1(c) (*source == c)
22787 #define C2(s) (memcmp(source, s, 2) == 0)
22788 #define C3(s) (memcmp(source, s, 3) == 0)
22790 switch (pm_slice_type(source, length, encoding_name)) {
22791 case PM_SLICE_TYPE_ERROR:
22793 case PM_SLICE_TYPE_NONE:
22795 case PM_SLICE_TYPE_LOCAL:
22798 case PM_SLICE_TYPE_CONSTANT:
22800 case PM_SLICE_TYPE_METHOD_NAME:
22807 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22809 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22811 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_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_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.