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);
14194 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14196 if (parsed_bare_hash) {
14197 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14200 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14203 parse_arguments_append(parser, arguments, argument);
14207 if (accepts_forwarding) {
14208 parser_lex(parser);
14210 if (token_begins_expression_p(parser->
current.type)) {
14215 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14222 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14225 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14227 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14228 if (parsed_first_argument && terminator ==
PM_TOKEN_EOF) {
14229 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14232 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14233 parse_arguments_append(parser, arguments, argument);
14236 parsed_forwarding_arguments =
true;
14243 if (argument == NULL) {
14244 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14247 bool contains_keywords =
false;
14248 bool contains_keyword_splat =
false;
14251 if (parsed_bare_hash) {
14252 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14259 operator = not_provided(parser);
14263 contains_keywords =
true;
14267 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14270 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14271 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14273 pm_keyword_hash_node_elements_append(bare_hash, argument);
14278 token_begins_expression_p(parser->
current.type) ||
14281 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14285 parsed_bare_hash =
true;
14288 parse_arguments_append(parser, arguments, argument);
14299 parsed_first_argument =
true;
14307 bool accepted_newline =
false;
14319 if (accepted_newline) {
14320 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14330 if (match1(parser, terminator))
break;
14345 parse_required_destructured_parameter(
pm_parser_t *parser) {
14349 pm_multi_target_node_opening_set(node, &parser->
previous);
14360 pm_multi_target_node_targets_append(parser, node, param);
14361 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14366 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14373 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14374 if (pm_parser_parameter_name_check(parser, &name)) {
14375 pm_node_flag_set_repeated_parameter(value);
14377 pm_parser_local_add_token(parser, &name, 1);
14380 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14385 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14386 if (pm_parser_parameter_name_check(parser, &name)) {
14387 pm_node_flag_set_repeated_parameter(param);
14389 pm_parser_local_add_token(parser, &name, 1);
14392 pm_multi_target_node_targets_append(parser, node, param);
14397 pm_multi_target_node_closing_set(node, &parser->
previous);
14407 PM_PARAMETERS_NO_CHANGE = 0,
14408 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14409 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14410 PM_PARAMETERS_ORDER_KEYWORDS,
14411 PM_PARAMETERS_ORDER_REST,
14412 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14413 PM_PARAMETERS_ORDER_OPTIONAL,
14414 PM_PARAMETERS_ORDER_NAMED,
14415 PM_PARAMETERS_ORDER_NONE,
14416 } pm_parameters_order_t;
14422 [0] = PM_PARAMETERS_NO_CHANGE,
14445 pm_parameters_order_t state = parameters_ordering[token->type];
14446 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14450 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14451 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14453 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14457 if (token->type ==
PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14458 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14460 }
else if (token->type ==
PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14461 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14463 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14465 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14469 if (state < *current) *current = state;
14479 pm_binding_power_t binding_power,
14480 bool uses_parentheses,
14481 bool allows_trailing_comma,
14482 bool allows_forwarding_parameters,
14483 bool accepts_blocks_in_defaults,
14486 pm_do_loop_stack_push(parser,
false);
14489 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14492 bool parsing =
true;
14494 switch (parser->
current.type) {
14496 update_parameter_state(parser, &parser->
current, &order);
14499 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14500 pm_parameters_node_requireds_append(params, param);
14502 pm_parameters_node_posts_append(params, param);
14508 update_parameter_state(parser, &parser->
current, &order);
14509 parser_lex(parser);
14514 bool repeated =
false;
14517 repeated = pm_parser_parameter_name_check(parser, &name);
14518 pm_parser_local_add_token(parser, &name, 1);
14520 name = not_provided(parser);
14526 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14528 if (params->
block == NULL) {
14529 pm_parameters_node_block_set(params, param);
14531 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14532 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14538 if (!allows_forwarding_parameters) {
14539 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14542 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14543 parser_lex(parser);
14552 pm_parameters_node_posts_append(params, keyword_rest);
14553 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14557 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14566 parser_lex(parser);
14569 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14572 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14575 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14578 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14581 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14587 update_parameter_state(parser, &parser->
current, &order);
14589 update_parameter_state(parser, &parser->
previous, &order);
14593 bool repeated = pm_parser_parameter_name_check(parser, &name);
14594 pm_parser_local_add_token(parser, &name, 1);
14599 parser_lex(parser);
14604 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14605 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14606 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14611 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14613 pm_parameters_node_optionals_append(params, param);
14619 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14622 context_pop(parser);
14631 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14634 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14636 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14640 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14642 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14649 update_parameter_state(parser, &parser->
current, &order);
14652 parser_lex(parser);
14659 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14660 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14661 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14664 bool repeated = pm_parser_parameter_name_check(parser, &local);
14665 pm_parser_local_add_token(parser, &local, 1);
14667 switch (parser->
current.type) {
14671 context_pop(parser);
14673 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14675 pm_node_flag_set_repeated_parameter(param);
14678 pm_parameters_node_keywords_append(params, param);
14683 context_pop(parser);
14685 if (uses_parentheses) {
14690 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14692 pm_node_flag_set_repeated_parameter(param);
14695 pm_parameters_node_keywords_append(params, param);
14701 if (token_begins_expression_p(parser->
current.type)) {
14705 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14706 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14707 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14710 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14713 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14716 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14720 pm_node_flag_set_repeated_parameter(param);
14723 context_pop(parser);
14724 pm_parameters_node_keywords_append(params, param);
14741 update_parameter_state(parser, &parser->
current, &order);
14742 parser_lex(parser);
14746 bool repeated =
false;
14750 repeated = pm_parser_parameter_name_check(parser, &name);
14751 pm_parser_local_add_token(parser, &name, 1);
14753 name = not_provided(parser);
14757 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14759 pm_node_flag_set_repeated_parameter(param);
14762 if (params->
rest == NULL) {
14763 pm_parameters_node_rest_set(params, param);
14765 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14766 pm_parameters_node_posts_append(params, param);
14773 pm_parameters_order_t previous_order = order;
14774 update_parameter_state(parser, &parser->
current, &order);
14775 parser_lex(parser);
14781 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14782 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14785 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14789 bool repeated =
false;
14792 repeated = pm_parser_parameter_name_check(parser, &name);
14793 pm_parser_local_add_token(parser, &name, 1);
14795 name = not_provided(parser);
14799 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14801 pm_node_flag_set_repeated_parameter(param);
14806 pm_parameters_node_keyword_rest_set(params, param);
14808 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14809 pm_parameters_node_posts_append(params, param);
14816 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14821 if (params->
rest == NULL) {
14822 pm_parameters_node_rest_set(params, param);
14824 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14825 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14828 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14839 if (!parsing)
break;
14841 bool accepted_newline =
false;
14842 if (uses_parentheses) {
14849 if (accepted_newline) {
14850 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14858 pm_do_loop_stack_pop(parser);
14894 token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14896 const uint8_t *end = token->start;
14900 newline_index == 0 &&
14901 parser->
start[0] == 0xef &&
14902 parser->
start[1] == 0xbb &&
14903 parser->
start[2] == 0xbf
14906 int64_t column = 0;
14907 for (; cursor < end; cursor++) {
14910 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14917 if (break_on_non_space)
return -1;
14930 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) {
14935 size_t closing_newline_index = token_newline_index(parser);
14936 if (opening_newline_index == closing_newline_index)
return;
14941 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14942 if (!if_after_else && (opening_column == -1))
return;
14949 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14950 if ((closing_column == -1) || (opening_column == closing_column))
return;
14954 if (allow_indent && (closing_column > opening_column))
return;
14957 PM_PARSER_WARN_FORMAT(
14959 closing_token->
start,
14960 closing_token->
end,
14961 PM_WARN_INDENTATION_MISMATCH,
14962 (
int) (closing_token->
end - closing_token->
start),
14963 (
const char *) closing_token->
start,
14964 (
int) (opening_token->
end - opening_token->
start),
14965 (
const char *) opening_token->
start,
14966 ((int32_t) opening_newline_index) + parser->
start_line
14971 PM_RESCUES_BEGIN = 1,
14978 } pm_rescues_type_t;
14989 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14990 parser_lex(parser);
14994 switch (parser->
current.type) {
14999 parser_lex(parser);
15000 pm_rescue_node_operator_set(rescue, &parser->
previous);
15002 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15003 reference = parse_target(parser, reference,
false,
false);
15005 pm_rescue_node_reference_set(rescue, reference);
15020 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15021 pm_rescue_node_exceptions_append(rescue, expression);
15030 pm_rescue_node_operator_set(rescue, &parser->
previous);
15032 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15033 reference = parse_target(parser, reference,
false,
false);
15035 pm_rescue_node_reference_set(rescue, reference);
15050 pm_accepts_block_stack_push(parser,
true);
15065 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15067 pm_accepts_block_stack_pop(parser);
15071 if (current == NULL) {
15072 pm_begin_node_rescue_clause_set(parent_node, rescue);
15074 pm_rescue_node_subsequent_set(current, rescue);
15083 if (current != NULL) {
15087 while (clause != NULL) {
15095 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15096 opening_newline_index = token_newline_index(parser);
15098 else_keyword = parser->
current;
15099 opening = &else_keyword;
15101 parser_lex(parser);
15106 pm_accepts_block_stack_push(parser,
true);
15120 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15121 pm_accepts_block_stack_pop(parser);
15126 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15127 pm_begin_node_else_clause_set(parent_node, else_clause);
15131 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15135 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15138 parser_lex(parser);
15143 pm_accepts_block_stack_push(parser,
true);
15157 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15158 pm_accepts_block_stack_pop(parser);
15163 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15164 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15168 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15169 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15172 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15182 pm_token_t begin_keyword = not_provided(parser);
15183 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15185 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15195 parse_block_parameters(
15197 bool allows_trailing_comma,
15199 bool is_lambda_literal,
15200 bool accepts_blocks_in_defaults,
15205 parameters = parse_parameters(
15207 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15209 allows_trailing_comma,
15211 accepts_blocks_in_defaults,
15212 (uint16_t) (depth + 1)
15222 switch (parser->
current.type) {
15224 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15225 parser_lex(parser);
15228 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15229 parser_lex(parser);
15232 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15233 parser_lex(parser);
15236 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15237 parser_lex(parser);
15244 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15245 pm_parser_local_add_token(parser, &parser->
previous, 1);
15248 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15250 pm_block_parameters_node_append_local(block_parameters, local);
15255 return block_parameters;
15263 outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15265 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15276 static const char *
const pm_numbered_parameter_names[] = {
15277 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15291 if (parameters != NULL) {
15293 if (implicit_parameters->
size > 0) {
15297 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15299 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15301 assert(
false &&
"unreachable");
15310 if (implicit_parameters->
size == 0) {
15317 uint8_t numbered_parameter = 0;
15318 bool it_parameter =
false;
15320 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15324 if (it_parameter) {
15325 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15326 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15327 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15329 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15331 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15333 assert(
false &&
"unreachable");
15336 if (numbered_parameter > 0) {
15337 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15339 it_parameter =
true;
15344 if (numbered_parameter > 0) {
15348 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15352 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15355 if (it_parameter) {
15356 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15366 parse_block(
pm_parser_t *parser, uint16_t depth) {
15370 pm_accepts_block_stack_push(parser,
true);
15371 pm_parser_scope_push(parser,
false);
15378 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15380 parser_lex(parser);
15382 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15385 expect1(parser,
PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15388 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15403 pm_accepts_block_stack_push(parser,
true);
15405 pm_accepts_block_stack_pop(parser);
15410 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));
15418 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15421 pm_parser_scope_pop(parser);
15422 pm_accepts_block_stack_pop(parser);
15424 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15433 parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15434 bool found =
false;
15443 pm_accepts_block_stack_push(parser,
true);
15452 pm_accepts_block_stack_pop(parser);
15457 pm_accepts_block_stack_push(parser,
false);
15462 parse_arguments(parser, arguments, accepts_block,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
15471 pm_accepts_block_stack_pop(parser);
15477 if (accepts_block) {
15482 block = parse_block(parser, (uint16_t) (depth + 1));
15483 pm_arguments_validate_block(parser, arguments, block);
15486 block = parse_block(parser, (uint16_t) (depth + 1));
15489 if (block != NULL) {
15493 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15495 if (arguments->
block != NULL) {
15497 arguments->
arguments = pm_arguments_node_create(parser);
15499 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15515 bool in_sclass =
false;
15517 switch (context_node->
context) {
15562 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15584 assert(
false &&
"unreachable");
15589 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15600 switch (context_node->
context) {
15674 assert(
false &&
"unreachable");
15688 return previous_block_exits;
15706 default: assert(
false &&
"unreachable");
type =
"";
break;
15709 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15726 }
else if (previous_block_exits != NULL) {
15738 flush_block_exits(parser, previous_block_exits);
15746 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15752 predicate_closed =
true;
15756 if (!predicate_closed) {
15757 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15760 context_pop(parser);
15765 parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15767 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15770 pm_token_t then_keyword = not_provided(parser);
15772 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15776 pm_accepts_block_stack_push(parser,
true);
15777 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15778 pm_accepts_block_stack_pop(parser);
15782 pm_token_t end_keyword = not_provided(parser);
15787 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15790 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15793 assert(
false &&
"unreachable");
15803 if (parser_end_of_line_p(parser)) {
15804 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15807 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15809 parser_lex(parser);
15811 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15812 pm_accepts_block_stack_push(parser,
true);
15815 pm_accepts_block_stack_pop(parser);
15818 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15825 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15826 opening_newline_index = token_newline_index(parser);
15828 parser_lex(parser);
15831 pm_accepts_block_stack_push(parser,
true);
15833 pm_accepts_block_stack_pop(parser);
15836 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15839 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15849 assert(
false &&
"unreachable");
15853 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15861 bool recursing =
true;
15863 while (recursing) {
15868 recursing = current != NULL;
15886 assert(
false &&
"unreachable");
15890 pop_block_exits(parser, previous_block_exits);
15900 #define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15901 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15902 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15903 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15904 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15905 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15906 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15907 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15908 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15909 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15910 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15916 #define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15917 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15918 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15919 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15920 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15921 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15922 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15923 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15930 #define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15931 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15932 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15933 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15934 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15935 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15936 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15937 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15938 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15944 #define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15945 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15946 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15947 case PM_TOKEN_CLASS_VARIABLE
15953 #define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15954 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15955 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15956 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15967 parse_unescaped_encoding(
const pm_parser_t *parser) {
15989 parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15990 switch (parser->
current.type) {
16002 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16004 parser_lex(parser);
16022 lex_state_set(parser, PM_LEX_STATE_BEG);
16023 parser_lex(parser);
16029 pm_accepts_block_stack_push(parser,
true);
16031 pm_accepts_block_stack_pop(parser);
16035 lex_state_set(parser, state);
16043 if (statements != NULL && statements->
body.
size == 1) {
16047 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16061 lex_state_set(parser, PM_LEX_STATE_BEG);
16062 parser_lex(parser);
16067 switch (parser->
current.type) {
16071 parser_lex(parser);
16072 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16077 parser_lex(parser);
16078 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16083 parser_lex(parser);
16084 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16089 parser_lex(parser);
16090 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16095 parser_lex(parser);
16096 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16107 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16110 parser_lex(parser);
16111 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16121 static const uint8_t *
16122 parse_operator_symbol_name(
const pm_token_t *name) {
16123 switch (name->type) {
16126 if (name->end[-1] ==
'@')
return name->end - 1;
16138 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16140 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16141 parser_lex(parser);
16158 if (lex_mode->
mode != PM_LEX_STRING) {
16159 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16161 switch (parser->
current.type) {
16162 case PM_CASE_OPERATOR:
16163 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16172 case PM_CASE_KEYWORD:
16173 parser_lex(parser);
16184 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16189 if (lex_mode->
as.string.interpolation) {
16192 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16193 parser_lex(parser);
16197 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16201 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16206 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16213 if (part) pm_interpolated_symbol_node_append(symbol, part);
16216 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16217 pm_interpolated_symbol_node_append(symbol, part);
16221 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16223 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16228 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16238 parser_lex(parser);
16253 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16254 pm_interpolated_symbol_node_append(symbol, part);
16257 pm_interpolated_symbol_node_append(symbol, part);
16259 if (next_state != PM_LEX_STATE_NONE) {
16260 lex_state_set(parser, next_state);
16263 parser_lex(parser);
16266 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16274 if (next_state != PM_LEX_STATE_NONE) {
16275 lex_state_set(parser, next_state);
16279 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16284 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16292 parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16293 switch (parser->
current.type) {
16294 case PM_CASE_OPERATOR: {
16295 const pm_token_t opening = not_provided(parser);
16296 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16298 case PM_CASE_KEYWORD:
16302 parser_lex(parser);
16309 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16315 parser_lex(parser);
16317 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16320 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16332 parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16333 switch (parser->
current.type) {
16334 case PM_CASE_OPERATOR: {
16335 const pm_token_t opening = not_provided(parser);
16336 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16338 case PM_CASE_KEYWORD:
16342 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16343 parser_lex(parser);
16350 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16356 parser_lex(parser);
16358 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16361 parser_lex(parser);
16362 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16364 parser_lex(parser);
16365 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16367 parser_lex(parser);
16368 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16370 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16384 if ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1) {
16385 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16389 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16395 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16396 for (uint8_t number = 1; number <= maximum; number++) {
16397 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16404 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16427 pm_node_t *node = parse_variable(parser);
16428 if (node != NULL)
return node;
16433 pm_node_flag_set((
pm_node_t *)node, flags);
16444 parse_method_definition_name(
pm_parser_t *parser) {
16445 switch (parser->
current.type) {
16446 case PM_CASE_KEYWORD:
16449 parser_lex(parser);
16452 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16453 parser_lex(parser);
16455 case PM_CASE_OPERATOR:
16456 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16457 parser_lex(parser);
16466 parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16475 const uint8_t *source_cursor = (uint8_t *) string->
source;
16476 const uint8_t *source_end = source_cursor + dest_length;
16481 size_t trimmed_whitespace = 0;
16488 if (*source_cursor ==
'\t') {
16489 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16490 if (trimmed_whitespace > common_whitespace)
break;
16492 trimmed_whitespace++;
16499 memmove((uint8_t *) string->
source, source_cursor, (
size_t) (source_end - source_cursor));
16500 string->length = dest_length;
16510 bool dedent_next =
true;
16515 size_t write_index = 0;
16523 nodes->
nodes[write_index++] = node;
16524 dedent_next =
false;
16530 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16536 nodes->
nodes[write_index++] = node;
16540 dedent_next =
true;
16543 nodes->
size = write_index;
16550 parse_strings_empty_content(
const uint8_t *location) {
16560 bool concating =
false;
16568 assert(lex_mode->
mode == PM_LEX_STRING);
16569 bool lex_interpolation = lex_mode->
as.string.interpolation;
16570 bool label_allowed = lex_mode->
as.string.label_allowed && accepts_label;
16573 parser_lex(parser);
16595 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16596 }
else if (!lex_interpolation) {
16604 content = not_provided(parser);
16625 pm_token_t delimiters = not_provided(parser);
16626 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16630 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16632 parser_lex(parser);
16636 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16640 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16641 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16643 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16644 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16646 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16651 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16660 parser_lex(parser);
16663 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16664 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16672 if (location > parser->
start && location[-1] ==
'\n') location--;
16673 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16679 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16680 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16685 pm_token_t string_opening = not_provided(parser);
16686 pm_token_t string_closing = not_provided(parser);
16688 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16689 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16693 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16699 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16700 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16702 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16703 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16706 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16719 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16725 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16726 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16728 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16729 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16732 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16738 if (current == NULL) {
16754 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16764 pm_interpolated_string_node_append(container, current);
16775 #define PM_PARSE_PATTERN_SINGLE 0
16776 #define PM_PARSE_PATTERN_TOP 1
16777 #define PM_PARSE_PATTERN_MULTI 2
16790 if (*location->
start ==
'_')
return;
16793 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16809 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16828 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16835 parser_lex(parser);
16840 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16851 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16867 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16868 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16883 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16884 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16899 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16900 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16914 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16915 pm_array_pattern_node_requireds_append(pattern_node, inner);
16933 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16936 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16937 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16940 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16941 name = (
pm_node_t *) pm_local_variable_target_node_create(
16943 &PM_LOCATION_TOKEN_VALUE(&identifier),
16945 (uint32_t) (depth == -1 ? 0 : depth)
16950 return pm_splat_node_create(parser, &
operator, name);
16959 parser_lex(parser);
16965 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
16972 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16976 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16977 value = (
pm_node_t *) pm_local_variable_target_node_create(
16979 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16981 (uint32_t) (depth == -1 ? 0 : depth)
16985 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
16993 pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16994 ptrdiff_t length = end - start;
16995 if (length == 0)
return false;
16998 size_t width = char_is_identifier_start(parser, start);
16999 if (width == 0)
return false;
17010 const uint8_t *cursor = start + width;
17011 while ((cursor < end) && (width = char_is_identifier(parser, cursor))) cursor += width;
17012 return cursor == end;
17026 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17027 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17029 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17031 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17032 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);
17037 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17040 parse_pattern_capture(parser, captures, constant_id, value_loc);
17045 (uint32_t) (depth == -1 ? 0 : depth)
17058 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17077 if (pm_symbol_node_label_p(first_node)) {
17078 parse_pattern_hash_key(parser, &keys, first_node);
17084 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17088 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17092 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17104 pm_parser_err_node(parser, first_node, diag_id);
17108 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17120 if (rest != NULL) {
17121 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17128 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17130 if (rest == NULL) {
17133 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17140 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17143 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17144 }
else if (!pm_symbol_node_label_p(key)) {
17145 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17148 expect1(parser,
PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17152 parse_pattern_hash_key(parser, &keys, key);
17156 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17158 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17162 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17164 if (rest != NULL) {
17165 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17184 switch (parser->
current.type) {
17187 parser_lex(parser);
17191 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17195 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17196 return (
pm_node_t *) pm_local_variable_target_node_create(
17198 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17200 (uint32_t) (depth == -1 ? 0 : depth)
17205 parser_lex(parser);
17210 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17215 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17228 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17229 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17242 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17243 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17255 pm_array_pattern_node_requireds_append(node, inner);
17264 parser_lex(parser);
17269 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17273 switch (parser->
current.type) {
17275 parser_lex(parser);
17276 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17279 first_node = parse_pattern_keyword_rest(parser, captures);
17282 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17286 parser_lex(parser);
17293 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17302 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17303 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17312 parser_lex(parser);
17316 switch (parser->
current.type) {
17317 case PM_CASE_PRIMITIVE: {
17318 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17319 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17322 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17323 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17324 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17328 case PM_CASE_PRIMITIVE: {
17329 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17332 if (pm_symbol_node_label_p(node))
return node;
17341 switch (parser->
current.type) {
17342 case PM_CASE_PRIMITIVE: {
17343 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17344 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17347 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17354 parser_lex(parser);
17359 switch (parser->
current.type) {
17361 parser_lex(parser);
17364 if (variable == NULL) {
17365 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17366 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17369 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17372 parser_lex(parser);
17375 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17378 parser_lex(parser);
17381 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17384 parser_lex(parser);
17387 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17390 parser_lex(parser);
17393 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17396 parser_lex(parser);
17399 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17406 parser_lex(parser);
17408 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17413 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17418 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17419 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17420 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17426 parser_lex(parser);
17431 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17435 parser_lex(parser);
17438 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17441 pm_parser_err_current(parser, diag_id);
17457 switch (parser->
current.type) {
17466 case PM_CASE_PRIMITIVE: {
17467 if (node == NULL) {
17468 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17470 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17471 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17479 parser_lex(parser);
17481 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17486 if (node == NULL) {
17489 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17495 pm_parser_err_current(parser, diag_id);
17498 if (node == NULL) {
17501 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17518 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17522 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17525 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17527 (uint32_t) (depth == -1 ? 0 : depth)
17530 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17543 bool leading_rest =
false;
17544 bool trailing_rest =
false;
17546 switch (parser->
current.type) {
17548 parser_lex(parser);
17550 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17552 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17553 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17559 node = parse_pattern_keyword_rest(parser, captures);
17560 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17562 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17563 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17571 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17573 if (pm_symbol_node_label_p(node)) {
17574 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17576 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17577 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17583 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17587 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17588 parser_lex(parser);
17589 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17590 leading_rest =
true;
17596 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17602 if (pm_symbol_node_label_p(node)) {
17603 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17606 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser,
PM_TOKEN_COMMA)) {
17619 trailing_rest =
true;
17624 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17629 if (trailing_rest) {
17630 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17633 trailing_rest =
true;
17635 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17646 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17648 if (nodes.
size == 2) {
17649 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17652 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17654 if (leading_rest && trailing_rest) {
17655 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17660 }
else if (leading_rest) {
17663 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17675 parse_negative_numeric(
pm_node_t *node) {
17700 assert(
false &&
"unreachable");
17713 case PM_ERR_HASH_KEY: {
17717 case PM_ERR_HASH_VALUE:
17718 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17722 case PM_ERR_UNARY_RECEIVER: {
17727 case PM_ERR_UNARY_DISALLOWED:
17728 case PM_ERR_EXPECT_ARGUMENT: {
17733 pm_parser_err_previous(parser, diag_id);
17743 #define CONTEXT_NONE 0
17744 #define CONTEXT_THROUGH_ENSURE 1
17745 #define CONTEXT_THROUGH_ELSE 2
17748 int context = CONTEXT_NONE;
17750 while (context_node != NULL) {
17751 switch (context_node->
context) {
17772 if (context == CONTEXT_NONE) {
17773 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17774 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17775 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17776 }
else if (context == CONTEXT_THROUGH_ELSE) {
17777 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17789 context = CONTEXT_THROUGH_ELSE;
17800 context = CONTEXT_THROUGH_ENSURE;
17804 assert(
false &&
"unreachable");
17834 context_node = context_node->
prev;
17837 #undef CONTEXT_NONE
17838 #undef CONTEXT_ENSURE
17839 #undef CONTEXT_ELSE
17849 while (context_node != NULL) {
17850 switch (context_node->
context) {
17875 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17879 assert(
false &&
"unreachable");
17920 context_node = context_node->
prev;
17952 parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17956 if (callback_data->
shared) {
17962 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
17975 .shared = unescaped->
type == PM_STRING_SHARED
17985 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) {
17986 switch (parser->
current.type) {
17988 parser_lex(parser);
17991 pm_accepts_block_stack_push(parser,
true);
17992 bool parsed_bare_hash =
false;
18008 if (accepted_newline) {
18009 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18034 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18036 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18039 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18041 if (parsed_bare_hash) {
18042 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18045 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18049 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18053 parsed_bare_hash =
true;
18055 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18058 if (parsed_bare_hash) {
18059 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18064 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18070 operator = not_provided(parser);
18073 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18074 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18075 pm_keyword_hash_node_elements_append(hash, assoc);
18079 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18083 parsed_bare_hash =
true;
18087 pm_array_node_elements_append(array, element);
18099 pm_array_node_close_set(array, &parser->
previous);
18100 pm_accepts_block_stack_pop(parser);
18109 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18111 parser_lex(parser);
18119 pop_block_exits(parser, previous_block_exits);
18122 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous);
18127 pm_accepts_block_stack_push(parser,
true);
18129 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18130 context_pop(parser);
18136 if (terminator_found) {
18145 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18148 parser_lex(parser);
18149 pm_accepts_block_stack_pop(parser);
18151 pop_block_exits(parser, previous_block_exits);
18163 multi_target = pm_multi_target_node_create(parser);
18164 pm_multi_target_node_targets_append(parser, multi_target, statement);
18167 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18176 if (match1(parser,
PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18177 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18189 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18192 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18197 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18207 pm_statements_node_body_append(parser, statements, statement,
true);
18217 pm_statements_node_body_append(parser, statements, statement,
true);
18221 if (!terminator_found && !match1(parser,
PM_TOKEN_EOF)) {
18227 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18228 pm_statements_node_body_append(parser, statements, node,
true);
18257 context_pop(parser);
18258 pm_accepts_block_stack_pop(parser);
18270 pm_multi_target_node_targets_append(parser, multi_target, statement);
18272 statement = (
pm_node_t *) multi_target;
18284 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18288 pop_block_exits(parser, previous_block_exits);
18291 pm_void_statements_check(parser, statements,
true);
18305 pm_accepts_block_stack_push(parser,
true);
18306 parser_lex(parser);
18311 if (current_hash_keys != NULL) {
18312 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18315 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18322 pm_accepts_block_stack_pop(parser);
18324 pm_hash_node_closing_loc_set(node, &parser->
previous);
18329 parser_lex(parser);
18340 pm_node_t *node = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18341 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18346 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18352 parser_lex(parser);
18355 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18356 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18362 parser_lex(parser);
18374 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18375 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18380 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18383 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18389 parser_lex(parser);
18395 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18396 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18404 parser_lex(parser);
18406 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));
18413 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18416 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18419 parser_lex(parser);
18422 parser_lex(parser);
18423 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18425 parser_lex(parser);
18428 parser_lex(parser);
18429 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18431 parser_lex(parser);
18434 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18435 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18441 parser_lex(parser);
18444 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18445 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18451 parser_lex(parser);
18454 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18455 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18462 parser_lex(parser);
18464 pm_node_t *node = parse_variable_call(parser);
18474 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18484 if (arguments.
block != NULL) {
18506 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18507 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18513 parse_target_implicit_parameter(parser, node);
18521 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18522 parse_target_implicit_parameter(parser, node);
18525 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18534 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18535 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18546 size_t common_whitespace = (size_t) -1;
18549 parser_lex(parser);
18561 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18568 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18581 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18584 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18588 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18593 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18594 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18607 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18614 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18616 cast->
parts = parts;
18619 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18628 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18636 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18638 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18644 parse_heredoc_dedent(parser, nodes, common_whitespace);
18649 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18655 parser_lex(parser);
18658 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18659 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18666 parser_lex(parser);
18671 parser_lex(parser);
18672 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18676 parser_lex(parser);
18677 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18681 parser_lex(parser);
18682 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18685 parser_lex(parser);
18686 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18688 parser_lex(parser);
18691 parser_lex(parser);
18694 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18695 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18698 parser_lex(parser);
18701 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18702 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18710 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18713 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18716 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18721 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18726 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18730 size_t opening_newline_index = token_newline_index(parser);
18731 parser_lex(parser);
18737 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18744 }
else if (!token_begins_expression_p(parser->
current.type)) {
18747 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18752 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18753 parser_lex(parser);
18755 pop_block_exits(parser, previous_block_exits);
18758 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18759 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18764 pm_token_t end_keyword = not_provided(parser);
18768 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18775 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18776 parser_lex(parser);
18779 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18784 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18786 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18787 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18791 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18792 pm_when_node_conditions_append(when_node, condition);
18803 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18806 pm_when_clause_static_literals_add(parser, &literals, condition);
18812 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18816 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18821 if (statements != NULL) {
18822 pm_when_node_statements_set(when_node, statements);
18826 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18832 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18838 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18842 if (predicate == NULL) {
18843 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18850 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18855 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18857 parser_lex(parser);
18862 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));
18872 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18873 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
18876 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18877 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
18888 then_keyword = not_provided(parser);
18906 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
18907 pm_case_match_node_condition_append(case_node, condition);
18913 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18925 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18927 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18931 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18937 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18946 pop_block_exits(parser, previous_block_exits);
18952 size_t opening_newline_index = token_newline_index(parser);
18953 parser_lex(parser);
18959 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18963 pm_accepts_block_stack_push(parser,
true);
18964 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18965 pm_accepts_block_stack_pop(parser);
18969 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18970 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18974 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
18976 pop_block_exits(parser, previous_block_exits);
18983 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18985 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18986 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18989 parser_lex(parser);
18999 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19002 flush_block_exits(parser, previous_block_exits);
19005 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19010 parser_lex(parser);
19016 token_begins_expression_p(parser->
current.type) ||
19019 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19021 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19022 parse_arguments(parser, &arguments,
false,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
19026 switch (keyword.
type) {
19039 parse_return(parser, node);
19043 assert(
false &&
"unreachable");
19048 parser_lex(parser);
19052 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19059 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19062 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19065 parser_lex(parser);
19069 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19075 if (arguments.
block != NULL) {
19076 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19078 arguments.
block = NULL;
19087 size_t opening_newline_index = token_newline_index(parser);
19088 parser_lex(parser);
19091 pm_do_loop_stack_push(parser,
false);
19094 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19098 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));
19100 pm_parser_scope_push(parser,
true);
19107 pm_accepts_block_stack_push(parser,
true);
19109 pm_accepts_block_stack_pop(parser);
19114 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));
19116 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19124 pm_parser_scope_pop(parser);
19125 pm_do_loop_stack_pop(parser);
19127 flush_block_exits(parser, previous_block_exits);
19130 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19133 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19136 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19143 inheritance_operator = parser->
current;
19144 lex_state_set(parser, PM_LEX_STATE_BEG);
19147 parser_lex(parser);
19149 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19151 inheritance_operator = not_provided(parser);
19155 pm_parser_scope_push(parser,
true);
19165 pm_accepts_block_stack_push(parser,
true);
19167 pm_accepts_block_stack_pop(parser);
19172 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));
19174 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19179 if (context_def_p(parser)) {
19180 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19186 pm_parser_scope_pop(parser);
19187 pm_do_loop_stack_pop(parser);
19190 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19193 pop_block_exits(parser, previous_block_exits);
19196 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19200 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19203 size_t opening_newline_index = token_newline_index(parser);
19213 parser_lex(parser);
19217 bool valid_name =
true;
19219 switch (parser->
current.type) {
19220 case PM_CASE_OPERATOR:
19221 pm_parser_scope_push(parser,
true);
19222 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19223 parser_lex(parser);
19228 parser_lex(parser);
19231 receiver = parse_variable_call(parser);
19233 pm_parser_scope_push(parser,
true);
19234 lex_state_set(parser, PM_LEX_STATE_FNAME);
19235 parser_lex(parser);
19238 name = parse_method_definition_name(parser);
19241 pm_parser_scope_push(parser,
true);
19251 valid_name =
false;
19261 pm_parser_scope_push(parser,
true);
19262 parser_lex(parser);
19267 lex_state_set(parser, PM_LEX_STATE_FNAME);
19268 parser_lex(parser);
19271 switch (identifier.
type) {
19273 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19276 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19279 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19282 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19285 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19288 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19291 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19294 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19297 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19300 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19303 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19309 name = parse_method_definition_name(parser);
19324 context_pop(parser);
19325 parser_lex(parser);
19328 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19334 lex_state_set(parser, PM_LEX_STATE_FNAME);
19338 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
19342 pm_parser_scope_push(parser,
true);
19344 name = parse_method_definition_name(parser);
19348 pm_parser_scope_push(parser,
true);
19349 name = parse_method_definition_name(parser);
19357 switch (parser->
current.type) {
19359 parser_lex(parser);
19365 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true, (uint16_t) (depth + 1));
19368 lex_state_set(parser, PM_LEX_STATE_BEG);
19371 context_pop(parser);
19381 case PM_CASE_PARAMETER: {
19385 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19388 lparen = not_provided(parser);
19389 rparen = not_provided(parser);
19390 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true, (uint16_t) (depth + 1));
19392 context_pop(parser);
19396 lparen = not_provided(parser);
19397 rparen = not_provided(parser);
19400 context_pop(parser);
19410 if (token_is_setter_name(&name)) {
19411 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19416 pm_do_loop_stack_push(parser,
false);
19417 statements = (
pm_node_t *) pm_statements_node_create(parser);
19419 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));
19425 pm_node_t *value = parse_expression(parser, binding_power,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
19426 context_pop(parser);
19428 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19431 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19432 pm_do_loop_stack_pop(parser);
19433 context_pop(parser);
19434 end_keyword = not_provided(parser);
19436 equal = not_provided(parser);
19439 lex_state_set(parser, PM_LEX_STATE_BEG);
19446 pm_accepts_block_stack_push(parser,
true);
19447 pm_do_loop_stack_push(parser,
false);
19450 pm_accepts_block_stack_push(parser,
true);
19452 pm_accepts_block_stack_pop(parser);
19457 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));
19459 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19462 pm_accepts_block_stack_pop(parser);
19463 pm_do_loop_stack_pop(parser);
19471 pm_parser_scope_pop(parser);
19478 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
19480 flush_block_exits(parser, previous_block_exits);
19483 return (
pm_node_t *) pm_def_node_create(
19500 parser_lex(parser);
19510 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19513 rparen = not_provided(parser);
19520 lparen = not_provided(parser);
19521 rparen = not_provided(parser);
19522 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19525 context_pop(parser);
19526 return (
pm_node_t *) pm_defined_node_create(
19531 &PM_LOCATION_TOKEN_VALUE(&keyword)
19535 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19536 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19539 parser_lex(parser);
19542 if (context_def_p(parser)) {
19543 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19551 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19554 parser_lex(parser);
19557 size_t opening_newline_index = token_newline_index(parser);
19558 parser_lex(parser);
19570 if (token_begins_expression_p(parser->
current.type)) {
19571 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19574 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19575 }
else if (token_begins_expression_p(parser->
current.type)) {
19576 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19578 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19579 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19584 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19586 index = parse_target(parser, index,
false,
false);
19589 context_pop(parser);
19590 pm_do_loop_stack_push(parser,
true);
19595 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19596 pm_do_loop_stack_pop(parser);
19602 do_keyword = not_provided(parser);
19610 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19613 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19616 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19619 if (parser_end_of_line_p(parser)) {
19620 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19623 size_t opening_newline_index = token_newline_index(parser);
19625 parser_lex(parser);
19627 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19629 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19630 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19633 parser_lex(parser);
19635 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19640 pm_undef_node_append(undef, name);
19643 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19644 parser_lex(parser);
19645 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19652 pm_undef_node_append(undef, name);
19659 parser_lex(parser);
19673 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19682 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19685 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19688 size_t opening_newline_index = token_newline_index(parser);
19689 parser_lex(parser);
19691 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19695 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19697 size_t opening_newline_index = token_newline_index(parser);
19698 parser_lex(parser);
19701 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19707 pop_block_exits(parser, previous_block_exits);
19711 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19718 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19726 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19729 pm_parser_scope_push(parser,
true);
19734 pm_accepts_block_stack_push(parser,
true);
19736 pm_accepts_block_stack_pop(parser);
19741 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));
19743 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19749 pm_parser_scope_pop(parser);
19752 if (context_def_p(parser)) {
19753 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19756 pop_block_exits(parser, previous_block_exits);
19759 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19762 parser_lex(parser);
19765 parser_lex(parser);
19773 parser_lex(parser);
19776 parse_retry(parser, node);
19781 parser_lex(parser);
19784 parser_lex(parser);
19787 size_t opening_newline_index = token_newline_index(parser);
19790 pm_do_loop_stack_push(parser,
true);
19792 parser_lex(parser);
19794 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19796 pm_do_loop_stack_pop(parser);
19797 context_pop(parser);
19803 pm_accepts_block_stack_push(parser,
true);
19804 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19805 pm_accepts_block_stack_pop(parser);
19809 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19812 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &parser->
previous, predicate, statements, 0);
19815 size_t opening_newline_index = token_newline_index(parser);
19818 pm_do_loop_stack_push(parser,
true);
19820 parser_lex(parser);
19822 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19824 pm_do_loop_stack_pop(parser);
19825 context_pop(parser);
19831 pm_accepts_block_stack_push(parser,
true);
19832 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19833 pm_accepts_block_stack_pop(parser);
19837 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19840 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &parser->
previous, predicate, statements, 0);
19843 parser_lex(parser);
19854 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19862 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19867 pm_array_node_close_set(array, &closing);
19872 parser_lex(parser);
19881 switch (parser->
current.type) {
19883 if (current == NULL) {
19889 pm_array_node_elements_append(array, current);
19893 parser_lex(parser);
19900 if (current == NULL) {
19904 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
19905 parser_lex(parser);
19911 parser_lex(parser);
19923 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
19924 parser_lex(parser);
19927 pm_interpolated_symbol_node_append(interpolated, first_string);
19928 pm_interpolated_symbol_node_append(interpolated, second_string);
19933 assert(
false &&
"unreachable");
19939 bool start_location_set =
false;
19940 if (current == NULL) {
19946 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19956 pm_interpolated_symbol_node_append(interpolated, current);
19958 start_location_set =
true;
19965 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19967 if (!start_location_set) {
19973 bool start_location_set =
false;
19974 if (current == NULL) {
19980 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19991 pm_interpolated_symbol_node_append(interpolated, current);
19993 start_location_set =
true;
19999 assert(
false &&
"unreachable");
20002 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20004 if (!start_location_set) {
20011 parser_lex(parser);
20018 pm_array_node_elements_append(array, current);
20023 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20028 pm_array_node_close_set(array, &closing);
20033 parser_lex(parser);
20049 pm_array_node_elements_append(array,
string);
20057 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20063 pm_array_node_close_set(array, &closing);
20067 parser_lex(parser);
20076 switch (parser->
current.type) {
20082 if (current == NULL) {
20089 pm_array_node_elements_append(array, current);
20093 parser_lex(parser);
20101 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20102 parser_lex(parser);
20104 if (current == NULL) {
20121 pm_interpolated_string_node_append(interpolated, current);
20122 pm_interpolated_string_node_append(interpolated,
string);
20125 assert(
false &&
"unreachable");
20131 if (current == NULL) {
20138 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20147 pm_interpolated_string_node_append(interpolated, current);
20155 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20160 if (current == NULL) {
20167 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20176 pm_interpolated_string_node_append(interpolated, current);
20183 assert(
false &&
"unreachable");
20186 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20192 parser_lex(parser);
20199 pm_array_node_elements_append(array, current);
20204 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20210 pm_array_node_close_set(array, &closing);
20215 parser_lex(parser);
20227 parser_lex(parser);
20245 parser_lex(parser);
20258 parse_regular_expression_errors(parser, node);
20261 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20267 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20280 pm_interpolated_regular_expression_node_append(interpolated, part);
20285 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20292 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20293 pm_interpolated_regular_expression_node_append(interpolated, part);
20299 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20305 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20310 parser_lex(parser);
20327 parser_lex(parser);
20328 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20340 parser_lex(parser);
20343 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20344 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20345 parser_lex(parser);
20351 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20357 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20359 pm_interpolated_xstring_node_append(node, part);
20364 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20369 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20370 pm_interpolated_xstring_node_append(node, part);
20376 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20381 pm_interpolated_xstring_node_closing_set(node, &closing);
20386 parser_lex(parser);
20391 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20392 pm_parser_err_prefix(parser, diag_id);
20399 if (token_begins_expression_p(parser->
current.type)) {
20400 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20406 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20408 return parse_target_validate(parser, splat,
true);
20412 if (binding_power > PM_BINDING_POWER_UNARY) {
20413 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20416 parser_lex(parser);
20419 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));
20420 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20422 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20426 if (binding_power > PM_BINDING_POWER_UNARY) {
20427 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20429 parser_lex(parser);
20432 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20433 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20438 if (binding_power > PM_BINDING_POWER_UNARY) {
20439 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20441 parser_lex(parser);
20444 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20445 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20450 parser_lex(parser);
20453 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20457 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20458 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20459 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20466 parse_negative_numeric(node);
20469 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20480 size_t opening_newline_index = token_newline_index(parser);
20481 pm_accepts_block_stack_push(parser,
true);
20482 parser_lex(parser);
20485 pm_parser_scope_push(parser,
false);
20489 switch (parser->
current.type) {
20492 parser_lex(parser);
20495 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20497 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20503 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20506 case PM_CASE_PARAMETER: {
20507 pm_accepts_block_stack_push(parser,
false);
20509 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20510 pm_accepts_block_stack_pop(parser);
20514 block_parameters = NULL;
20530 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20537 pm_accepts_block_stack_push(parser,
true);
20539 pm_accepts_block_stack_pop(parser);
20544 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));
20546 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20553 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20556 pm_parser_scope_pop(parser);
20557 pm_accepts_block_stack_pop(parser);
20559 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20562 if (binding_power > PM_BINDING_POWER_UNARY) {
20563 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20565 parser_lex(parser);
20568 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20569 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20574 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20577 parser_lex(parser);
20579 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20590 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20591 pm_parser_err_prefix(parser, diag_id);
20597 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20598 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20604 pm_parser_err_prefix(parser, diag_id);
20622 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) {
20623 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));
20631 parser_lex(parser);
20633 pm_node_t *right = parse_expression(parser, binding_power,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20634 context_pop(parser);
20636 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20656 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20661 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20669 parse_assignment_value_local(parser, statement);
20691 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) {
20692 bool permitted =
true;
20693 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_USTAR)) permitted =
false;
20695 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));
20696 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20698 parse_assignment_value_local(parser, value);
20699 bool single_value =
true;
20702 single_value =
false;
20707 pm_array_node_elements_append(array, value);
20711 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20713 pm_array_node_elements_append(array, element);
20716 parse_assignment_value_local(parser, element);
20726 parser_lex(parser);
20728 bool accepts_command_call_inner =
false;
20735 accepts_command_call_inner =
true;
20739 pm_node_t *right = parse_expression(parser, binding_power, accepts_command_call_inner,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20740 context_pop(parser);
20742 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20758 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20763 if (call_node->
block != NULL) {
20764 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20766 call_node->
block = NULL;
20800 parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20815 if (!pm_slice_is_valid_local(parser, source, source + length))
return;
20817 if (callback_data->
shared) {
20821 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20827 void *memory =
xmalloc(length);
20828 if (memory == NULL) abort();
20830 memcpy(memory, source, length);
20831 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20840 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20843 if (pm_local_is_keyword((
const char *) source, length))
return;
20847 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20852 if (callback_data->
match == NULL) {
20853 callback_data->
match = pm_match_write_node_create(parser, call);
20858 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
20873 .shared = content->
type == PM_STRING_SHARED
20880 .shared = content->
type == PM_STRING_SHARED
20886 if (callback_data.
match != NULL) {
20894 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) {
20897 switch (token.type) {
20911 case PM_CASE_WRITABLE: {
20912 parser_lex(parser);
20913 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));
20916 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20919 return parse_write(parser, node, &token, value);
20923 pm_multi_target_node_targets_append(parser, multi_target, node);
20925 parser_lex(parser);
20926 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));
20927 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
20938 parser_lex(parser);
20939 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));
20940 return parse_unwriteable_write(parser, node, &token, value);
20946 parser_lex(parser);
20947 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20955 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20958 parser_lex(parser);
20960 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));
20961 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
20967 parser_lex(parser);
20969 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));
20976 parser_lex(parser);
20978 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));
20981 return parse_shareable_constant_write(parser, write);
20984 parser_lex(parser);
20986 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));
20990 return parse_shareable_constant_write(parser, write);
20993 parser_lex(parser);
20995 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21003 parser_lex(parser);
21005 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));
21019 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21022 parser_lex(parser);
21024 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21025 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21033 parser_lex(parser);
21039 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));
21040 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21044 if (pm_call_node_writable_p(parser, cast)) {
21045 parse_write_name(parser, &cast->
name);
21047 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21050 parse_call_operator_write(parser, cast, &token);
21051 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));
21052 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21055 parser_lex(parser);
21056 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21060 parser_lex(parser);
21065 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21073 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21076 parser_lex(parser);
21078 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));
21079 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21085 parser_lex(parser);
21087 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21094 parser_lex(parser);
21096 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));
21099 return parse_shareable_constant_write(parser, write);
21102 parser_lex(parser);
21104 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));
21108 return parse_shareable_constant_write(parser, write);
21111 parser_lex(parser);
21113 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21121 parser_lex(parser);
21123 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));
21137 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21140 parser_lex(parser);
21142 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21143 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21151 parser_lex(parser);
21157 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));
21158 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21162 if (pm_call_node_writable_p(parser, cast)) {
21163 parse_write_name(parser, &cast->
name);
21165 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21168 parse_call_operator_write(parser, cast, &token);
21169 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));
21170 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21173 parser_lex(parser);
21174 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21178 parser_lex(parser);
21183 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21201 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21204 parser_lex(parser);
21206 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));
21207 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21213 parser_lex(parser);
21215 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));
21222 parser_lex(parser);
21224 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));
21227 return parse_shareable_constant_write(parser, write);
21230 parser_lex(parser);
21232 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));
21236 return parse_shareable_constant_write(parser, write);
21239 parser_lex(parser);
21241 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21249 parser_lex(parser);
21251 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 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21258 parser_lex(parser);
21266 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21269 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));
21270 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21280 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));
21281 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21285 if (pm_call_node_writable_p(parser, cast)) {
21286 parse_write_name(parser, &cast->
name);
21288 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21291 parse_call_operator_write(parser, cast, &token);
21292 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));
21293 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21296 parser_lex(parser);
21297 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21301 parser_lex(parser);
21312 parser_lex(parser);
21315 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21319 parser_lex(parser);
21322 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21332 parser_lex(parser);
21333 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21336 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21349 bool interpolated =
false;
21350 size_t total_length = 0;
21357 interpolated =
true;
21362 if (!interpolated && total_length > 0) {
21363 void *memory =
xmalloc(total_length);
21364 if (!memory) abort();
21366 uint8_t *cursor = memory;
21411 parser_lex(parser);
21412 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21413 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21420 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21423 parser_lex(parser);
21424 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21425 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21429 parser_lex(parser);
21435 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21436 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21441 switch (parser->
current.type) {
21442 case PM_CASE_OPERATOR:
21443 case PM_CASE_KEYWORD:
21447 parser_lex(parser);
21457 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21458 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21461 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21466 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21473 parser_lex(parser);
21476 if (token_begins_expression_p(parser->
current.type)) {
21477 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21480 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21484 parser_lex(parser);
21486 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21487 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21491 parser_lex(parser);
21493 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21494 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21497 parser_lex(parser);
21499 pm_statements_node_body_append(parser, statements, node,
true);
21501 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21505 parser_lex(parser);
21507 pm_statements_node_body_append(parser, statements, node,
true);
21509 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21515 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21518 parser_lex(parser);
21520 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21532 context_pop(parser);
21533 pop_block_exits(parser, previous_block_exits);
21536 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21543 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21545 context_pop(parser);
21546 pop_block_exits(parser, previous_block_exits);
21549 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21552 parser_lex(parser);
21555 switch (parser->
current.type) {
21557 parser_lex(parser);
21573 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21574 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21577 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21581 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21582 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21587 case PM_CASE_OPERATOR:
21588 case PM_CASE_KEYWORD:
21591 parser_lex(parser);
21597 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21598 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21601 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21602 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21611 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21613 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
21617 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21623 parser_lex(parser);
21626 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21627 context_pop(parser);
21629 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
21632 parser_lex(parser);
21638 pm_accepts_block_stack_push(parser,
true);
21640 pm_accepts_block_stack_pop(parser);
21648 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21649 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21650 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21658 block = parse_block(parser, (uint16_t) (depth + 1));
21659 pm_arguments_validate_block(parser, &arguments, block);
21661 block = parse_block(parser, (uint16_t) (depth + 1));
21664 if (block != NULL) {
21665 if (arguments.
block != NULL) {
21666 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
21668 arguments.
arguments = pm_arguments_node_create(parser);
21670 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21676 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
21684 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21685 parser_lex(parser);
21688 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));
21693 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
21701 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21702 parser_lex(parser);
21705 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));
21710 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
21713 assert(
false &&
"unreachable");
21718 #undef PM_PARSE_PATTERN_SINGLE
21719 #undef PM_PARSE_PATTERN_TOP
21720 #undef PM_PARSE_PATTERN_MULTI
21744 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) {
21746 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21750 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21765 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21775 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21783 if (pm_symbol_node_label_p(node)) {
21796 current_token_type = parser->
current.type,
21797 current_binding_powers = pm_binding_powers[current_token_type],
21798 binding_power <= current_binding_powers.
left &&
21799 current_binding_powers.
binary
21801 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21807 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21819 if (
PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21827 if (
PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21837 if (current_binding_powers.
nonassoc) {
21840 if (match1(parser, current_token_type)) {
21858 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21861 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21866 if (accepts_command_call) {
21875 switch (node->
type) {
21890 cast->
block == NULL &&
21903 accepts_command_call =
false;
21911 accepts_command_call =
false;
21926 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21928 pm_arguments_node_arguments_append(
21930 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
21933 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
21936 pm_parser_constant_id_constant(parser,
"print", 5)
21940 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21941 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21943 pm_arguments_node_arguments_append(
21945 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
21948 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21949 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
21953 pm_parser_constant_id_constant(parser,
"$F", 2),
21957 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
21961 pm_arguments_node_arguments_append(
21963 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
21966 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21968 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
21970 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
21972 (
pm_node_t *) pm_true_node_synthesized_create(parser)
21975 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
21980 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
21982 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
21986 statements = wrapped_statements;
22001 pm_parser_scope_push(parser,
true);
22005 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22007 parser_lex(parser);
22010 if (statements == NULL) {
22011 statements = pm_statements_node_create(parser);
22016 assert(statements->
body.
size > 0);
22017 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22022 pm_parser_scope_pop(parser);
22027 if (pm_statements_node_body_length(statements) == 0) {
22028 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22034 statements = wrap_statements(parser, statements);
22036 flush_block_exits(parser, previous_block_exits);
22040 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22056 static const char *
22057 pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22058 size_t little_length = strlen(little);
22060 for (
const char *big_end = big + big_length; big < big_end; big++) {
22061 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22068 #define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22076 pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22077 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22078 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22088 pm_parser_init_shebang(
pm_parser_t *parser,
const pm_options_t *options,
const char *engine,
size_t length) {
22089 const char *switches = pm_strnstr(engine,
" -", length);
22090 if (switches == NULL)
return;
22095 (
const uint8_t *) (switches + 1),
22096 length - ((
size_t) (switches - engine)) - 1,
22100 size_t encoding_length;
22103 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22115 assert(source != NULL);
22119 .lex_state = PM_LEX_STATE_BEG,
22120 .enclosure_nesting = 0,
22121 .lambda_enclosure_nesting = -1,
22122 .brace_nesting = 0,
22123 .do_loop_stack = 0,
22124 .accepts_block_stack = 0,
22127 .stack = {{ .mode = PM_LEX_DEFAULT }},
22131 .end = source + size,
22132 .previous = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22133 .current = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22134 .next_start = NULL,
22135 .heredoc_end = NULL,
22136 .data_loc = { .start = NULL, .end = NULL },
22137 .comment_list = { 0 },
22138 .magic_comment_list = { 0 },
22139 .warning_list = { 0 },
22140 .error_list = { 0 },
22141 .current_scope = NULL,
22142 .current_context = NULL,
22144 .encoding_changed_callback = NULL,
22145 .encoding_comment_start = source,
22146 .lex_callback = NULL,
22148 .constant_pool = { 0 },
22149 .newline_list = { 0 },
22153 .explicit_encoding = NULL,
22155 .parsing_eval =
false,
22156 .partial_script =
false,
22157 .command_start =
true,
22158 .recovering =
false,
22159 .encoding_locked =
false,
22160 .encoding_changed =
false,
22161 .pattern_matching_newlines =
false,
22162 .in_keyword_arg =
false,
22163 .current_block_exits = NULL,
22164 .semantic_token_seen =
false,
22166 .current_regular_expression_ascii_only =
false,
22167 .warn_mismatched_indentation =
true
22184 uint32_t constant_size = ((uint32_t) size) / 95;
22190 size_t newline_size = size / 22;
22194 if (options != NULL) {
22203 if (encoding_length > 0) {
22205 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22227 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22229 pm_parser_scope_push(parser, scope_index == 0);
22235 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22241 void *allocated =
xmalloc(length);
22242 if (allocated == NULL)
continue;
22244 memcpy(allocated, source, length);
22245 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22250 pm_accepts_block_stack_push(parser,
true);
22253 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22266 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22283 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22284 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22286 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22287 const char *engine;
22289 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22290 if (newline != NULL) {
22294 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22299 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22302 search_shebang =
false;
22304 search_shebang =
true;
22310 if (search_shebang) {
22313 bool found_shebang =
false;
22317 const uint8_t *cursor = parser->
start;
22321 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22323 while (newline != NULL) {
22326 cursor = newline + 1;
22327 newline = next_newline(cursor, parser->
end - cursor);
22329 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22330 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22331 const char *engine;
22332 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22333 found_shebang =
true;
22335 if (newline != NULL) {
22336 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22341 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22349 if (found_shebang) {
22353 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22377 pm_comment_list_free(
pm_list_t *list) {
22380 for (node = list->
head; node != NULL; node = next) {
22392 pm_magic_comment_list_free(
pm_list_t *list) {
22395 for (node = list->
head; node != NULL; node = next) {
22421 pm_parser_scope_pop(parser);
22425 lex_mode_pop(parser);
22434 return parse_program(parser);
22444 #define LINE_SIZE 4096
22445 char line[LINE_SIZE];
22447 while (memset(line,
'\n', LINE_SIZE), fgets(line, LINE_SIZE, stream) != NULL) {
22448 size_t length = LINE_SIZE;
22449 while (length > 0 && line[length - 1] ==
'\n') length--;
22451 if (length == LINE_SIZE) {
22470 if (strncmp(line,
"__END__", 7) == 0)
return false;
22473 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22476 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22495 pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22499 if (diagnostic->
diag_id == PM_ERR_HEREDOC_TERM) {
22517 bool eof = pm_parse_stream_read(buffer, stream, fgets);
22523 eof = pm_parse_stream_read(buffer, stream, fgets);
22554 #undef PM_CASE_KEYWORD
22555 #undef PM_CASE_OPERATOR
22556 #undef PM_CASE_WRITABLE
22557 #undef PM_STRING_EMPTY
22558 #undef PM_LOCATION_NODE_BASE_VALUE
22559 #undef PM_LOCATION_NODE_VALUE
22560 #undef PM_LOCATION_NULL_VALUE
22561 #undef PM_LOCATION_TOKEN_VALUE
22566 #ifndef PRISM_EXCLUDE_SERIALIZATION
22582 pm_serialize_header(buffer);
22601 pm_serialize_header(buffer);
22622 pm_serialize_header(buffer);
22644 pm_serialize_header(buffer);
22663 PM_SLICE_TYPE_ERROR = -1,
22666 PM_SLICE_TYPE_NONE,
22669 PM_SLICE_TYPE_LOCAL,
22672 PM_SLICE_TYPE_CONSTANT,
22675 PM_SLICE_TYPE_METHOD_NAME
22682 pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22684 const pm_encoding_t *encoding =
pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22685 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22688 if (length == 0)
return PM_SLICE_TYPE_NONE;
22691 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22693 }
else if (*source ==
'_') {
22696 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22700 return PM_SLICE_TYPE_NONE;
22704 const uint8_t *end = source + length;
22705 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22711 while (source < end) {
22712 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22715 }
else if (*source ==
'_') {
22718 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22728 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22730 result = PM_SLICE_TYPE_METHOD_NAME;
22734 return source == end ? result : PM_SLICE_TYPE_NONE;
22742 switch (pm_slice_type(source, length, encoding_name)) {
22743 case PM_SLICE_TYPE_ERROR:
22745 case PM_SLICE_TYPE_NONE:
22746 case PM_SLICE_TYPE_CONSTANT:
22747 case PM_SLICE_TYPE_METHOD_NAME:
22749 case PM_SLICE_TYPE_LOCAL:
22753 assert(
false &&
"unreachable");
22762 switch (pm_slice_type(source, length, encoding_name)) {
22763 case PM_SLICE_TYPE_ERROR:
22765 case PM_SLICE_TYPE_NONE:
22766 case PM_SLICE_TYPE_LOCAL:
22767 case PM_SLICE_TYPE_METHOD_NAME:
22769 case PM_SLICE_TYPE_CONSTANT:
22773 assert(
false &&
"unreachable");
22782 #define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22783 #define C1(c) (*source == c)
22784 #define C2(s) (memcmp(source, s, 2) == 0)
22785 #define C3(s) (memcmp(source, s, 3) == 0)
22787 switch (pm_slice_type(source, length, encoding_name)) {
22788 case PM_SLICE_TYPE_ERROR:
22790 case PM_SLICE_TYPE_NONE:
22792 case PM_SLICE_TYPE_LOCAL:
22795 case PM_SLICE_TYPE_CONSTANT:
22797 case PM_SLICE_TYPE_METHOD_NAME:
22804 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22806 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22808 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...
union pm_lex_mode::@88 as
The data associated with this type of lex mode.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
enum pm_lex_mode::@87 mode
The type of this 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.
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.
struct pm_parser::@93 lex_modes
A stack of lex modes.
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.
enum pm_string_t::@94 type
The type of the string.
size_t length
The length of the string in bytes of memory.
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.