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))
30lex_mode_incrementor(
const uint8_t start) {
47lex_mode_terminator(
const uint8_t start) {
89lex_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
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');
144lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
146 .
mode = PM_LEX_REGEXP,
149 .incrementor = incrementor,
150 .terminator = terminator
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);
179lex_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
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;
263static 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);
287lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
291 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
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)
408 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
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)
493 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
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__)
547pm_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
566pm_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");
604pm_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;
621static pm_scope_forwarding_param_check_result_t
622pm_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);
712pm_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);
947 pm_constant_id_list_init_capacity(list, locals->
size);
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++) {
962 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
964 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
965 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
967 if (constant->
length >= 1 && *constant->
start !=
'_') {
968 PM_PARSER_WARN_FORMAT(
972 PM_WARN_UNUSED_LOCAL_VARIABLE,
974 (
const char *) constant->
start
990pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
991 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
998pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
999 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1006pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1007 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, 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:
1360pm_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);
1448 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
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))
1595static inline const uint8_t *
1597 if (arguments->
block != NULL) {
1638 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1652char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1653 if (n <= 0)
return 0;
1660 }
else if (*b ==
'_') {
1662 }
else if (*b >= 0x80) {
1667 }
else if (*b < 0x80) {
1670 return pm_encoding_utf_8_char_width(b, n);
1679char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1682 }
else if (*b < 0x80) {
1685 return pm_encoding_utf_8_char_width(b, n);
1695char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1703 }
else if (*b ==
'_') {
1705 }
else if (*b >= 0x80) {
1711 return char_is_identifier_utf8(b, n);
1718#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1719#define PUNCT(idx) ( \
1720 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1721 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1722 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1723 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1724 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1727const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1733char_is_global_name_punctuation(const uint8_t b) {
1734 const unsigned int i = (const unsigned int) b;
1735 if (i <= 0x20 || 0x7e < i) return false;
1737 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1741token_is_setter_name(pm_token_t *token) {
1743 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1744 ((token->type == PM_TOKEN_IDENTIFIER) &&
1745 (token->end - token->start >= 2) &&
1746 (token->end[-1] == '='))
1754pm_local_is_keyword(const char *source, size_t length) {
1755#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1759 switch (source[0]) {
1760 case 'd': KEYWORD("do"); return false;
1761 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1762 case 'o': KEYWORD("or"); return false;
1763 default: return false;
1766 switch (source[0]) {
1767 case 'a': KEYWORD("and"); return false;
1768 case 'd': KEYWORD("def"); return false;
1769 case 'e': KEYWORD("end"); return false;
1770 case 'f': KEYWORD("for"); return false;
1771 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1772 default: return false;
1775 switch (source[0]) {
1776 case 'c': KEYWORD("case"); return false;
1777 case 'e': KEYWORD("else"); return false;
1778 case 'n': KEYWORD("next"); return false;
1779 case 'r': KEYWORD("redo"); return false;
1780 case 's': KEYWORD("self"); return false;
1781 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1782 case 'w': KEYWORD("when"); return false;
1783 default: return false;
1786 switch (source[0]) {
1787 case 'a': KEYWORD("alias"); return false;
1788 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1789 case 'c': KEYWORD("class"); return false;
1790 case 'e': KEYWORD("elsif"); return false;
1791 case 'f': KEYWORD("false"); return false;
1792 case 'r': KEYWORD("retry"); return false;
1793 case 's': KEYWORD("super"); return false;
1794 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1795 case 'w': KEYWORD("while"); return false;
1796 case 'y': KEYWORD("yield"); return false;
1797 default: return false;
1800 switch (source[0]) {
1801 case 'e': KEYWORD("ensure"); return false;
1802 case 'm': KEYWORD("module"); return false;
1803 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1804 case 'u': KEYWORD("unless"); return false;
1805 default: return false;
1808 KEYWORD("__LINE__");
1809 KEYWORD("__FILE__");
1812 KEYWORD("__ENCODING__");
1821/******************************************************************************/
1822/* Node flag handling functions */
1823/******************************************************************************/
1829pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1830 node->flags |= flag;
1837pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1838 node->flags &= (pm_node_flags_t) ~flag;
1845pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1846 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1847 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1848 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1849 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1850 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1851 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1852 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1853 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1855 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1858/******************************************************************************/
1859/* Node creation functions */
1860/******************************************************************************/
1867#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)
1872static inline pm_node_flags_t
1873pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1874 pm_node_flags_t flags = 0;
1876 if (closing->type == PM_TOKEN_REGEXP_END) {
1877 pm_buffer_t unknown_flags = { 0 };
1879 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1881 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1882 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1883 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1884 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1886 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1887 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1888 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1889 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1891 default: pm_buffer_append_byte(&unknown_flags, *flag);
1895 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1896 if (unknown_flags_length != 0) {
1897 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1898 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1900 pm_buffer_free(&unknown_flags);
1906#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1908static pm_statements_node_t *
1909pm_statements_node_create(pm_parser_t *parser);
1912pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1915pm_statements_node_body_length(pm_statements_node_t *node);
1922pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1923 void *memory = xcalloc(1, size);
1924 if (memory == NULL) {
1925 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1931#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
1932#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
1937static pm_missing_node_t *
1938pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1939 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1941 *node = (pm_missing_node_t) {{
1942 .type = PM_MISSING_NODE,
1943 .node_id = PM_NODE_IDENTIFY(parser),
1944 .location = { .start = start, .end = end }
1953static pm_alias_global_variable_node_t *
1954pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1955 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1956 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1958 *node = (pm_alias_global_variable_node_t) {
1960 .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
1961 .node_id = PM_NODE_IDENTIFY(parser),
1963 .start = keyword->start,
1964 .end = old_name->location.end
1967 .new_name = new_name,
1968 .old_name = old_name,
1969 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1978static pm_alias_method_node_t *
1979pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1980 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1981 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
1983 *node = (pm_alias_method_node_t) {
1985 .type = PM_ALIAS_METHOD_NODE,
1986 .node_id = PM_NODE_IDENTIFY(parser),
1988 .start = keyword->start,
1989 .end = old_name->location.end
1992 .new_name = new_name,
1993 .old_name = old_name,
1994 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2003static pm_alternation_pattern_node_t *
2004pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2005 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2007 *node = (pm_alternation_pattern_node_t) {
2009 .type = PM_ALTERNATION_PATTERN_NODE,
2010 .node_id = PM_NODE_IDENTIFY(parser),
2012 .start = left->location.start,
2013 .end = right->location.end
2018 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2027static pm_and_node_t *
2028pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2029 pm_assert_value_expression(parser, left);
2031 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2033 *node = (pm_and_node_t) {
2035 .type = PM_AND_NODE,
2036 .node_id = PM_NODE_IDENTIFY(parser),
2038 .start = left->location.start,
2039 .end = right->location.end
2043 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2053static pm_arguments_node_t *
2054pm_arguments_node_create(pm_parser_t *parser) {
2055 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2057 *node = (pm_arguments_node_t) {
2059 .type = PM_ARGUMENTS_NODE,
2060 .node_id = PM_NODE_IDENTIFY(parser),
2061 .location = PM_LOCATION_NULL_VALUE(parser)
2073pm_arguments_node_size(pm_arguments_node_t *node) {
2074 return node->arguments.size;
2081pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2082 if (pm_arguments_node_size(node) == 0) {
2083 node->base.location.start = argument->location.start;
2086 node->base.location.end = argument->location.end;
2087 pm_node_list_append(&node->arguments, argument);
2089 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2090 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2091 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2093 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2101static pm_array_node_t *
2102pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2103 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2105 *node = (pm_array_node_t) {
2107 .type = PM_ARRAY_NODE,
2108 .flags = PM_NODE_FLAG_STATIC_LITERAL,
2109 .node_id = PM_NODE_IDENTIFY(parser),
2110 .location = PM_LOCATION_TOKEN_VALUE(opening)
2112 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2113 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2124pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2125 if (!node->elements.size && !node->opening_loc.start) {
2126 node->base.location.start = element->location.start;
2129 pm_node_list_append(&node->elements, element);
2130 node->base.location.end = element->location.end;
2132 // If the element is not a static literal, then the array is not a static
2133 // literal. Turn that flag off.
2134 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)) {
2135 pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
2138 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2139 pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2147pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2148 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2149 node->base.location.end = closing->end;
2150 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2157static pm_array_pattern_node_t *
2158pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2159 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2161 *node = (pm_array_pattern_node_t) {
2163 .type = PM_ARRAY_PATTERN_NODE,
2164 .node_id = PM_NODE_IDENTIFY(parser),
2166 .start = nodes->nodes[0]->location.start,
2167 .end = nodes->nodes[nodes->size - 1]->location.end
2174 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2175 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2178 // For now we're going to just copy over each pointer manually. This could be
2179 // much more efficient, as we could instead resize the node list.
2180 bool found_rest = false;
2183 PM_NODE_LIST_FOREACH(nodes, index, child) {
2184 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2187 } else if (found_rest) {
2188 pm_node_list_append(&node->posts, child);
2190 pm_node_list_append(&node->requireds, child);
2200static pm_array_pattern_node_t *
2201pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2202 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2204 *node = (pm_array_pattern_node_t) {
2206 .type = PM_ARRAY_PATTERN_NODE,
2207 .node_id = PM_NODE_IDENTIFY(parser),
2208 .location = rest->location,
2214 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2215 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2227 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2229 *node = (pm_array_pattern_node_t) {
2231 .type = PM_ARRAY_PATTERN_NODE,
2232 .node_id = PM_NODE_IDENTIFY(parser),
2234 .start = constant->location.start,
2238 .constant = constant,
2240 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2241 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2253static pm_array_pattern_node_t *
2254pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2255 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2257 *node = (pm_array_pattern_node_t) {
2259 .type = PM_ARRAY_PATTERN_NODE,
2260 .node_id = PM_NODE_IDENTIFY(parser),
2262 .start = opening->start,
2268 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2269 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2278pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2279 pm_node_list_append(&node->requireds, inner);
2285static pm_assoc_node_t *
2286pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2287 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2290 if (value != NULL && value->location.end > key->location.end) {
2291 end = value->location.end;
2292 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2293 end = operator->end;
2295 end = key->location.end;
2298 // Hash string keys will be frozen, so we can mark them as frozen here so
2299 // that the compiler picks them up and also when we check for static literal
2300 // on the keys it gets factored in.
2301 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2302 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2305 // If the key and value of this assoc node are both static literals, then
2306 // we can mark this node as a static literal.
2307 pm_node_flags_t flags = 0;
2309 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2310 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)
2312 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2315 *node = (pm_assoc_node_t) {
2317 .type = PM_ASSOC_NODE,
2319 .node_id = PM_NODE_IDENTIFY(parser),
2321 .start = key->location.start,
2326 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2336static pm_assoc_splat_node_t *
2337pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2338 assert(operator->type == PM_TOKEN_USTAR_STAR);
2339 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2341 *node = (pm_assoc_splat_node_t) {
2343 .type = PM_ASSOC_SPLAT_NODE,
2344 .node_id = PM_NODE_IDENTIFY(parser),
2346 .start = operator->start,
2347 .end = value == NULL ? operator->end : value->location.end
2351 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2360static pm_back_reference_read_node_t *
2361pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2362 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2363 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2365 *node = (pm_back_reference_read_node_t) {
2367 .type = PM_BACK_REFERENCE_READ_NODE,
2368 .node_id = PM_NODE_IDENTIFY(parser),
2369 .location = PM_LOCATION_TOKEN_VALUE(name),
2371 .name = pm_parser_constant_id_token(parser, name)
2380static pm_begin_node_t *
2381pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2382 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2384 *node = (pm_begin_node_t) {
2386 .type = PM_BEGIN_NODE,
2387 .node_id = PM_NODE_IDENTIFY(parser),
2389 .start = begin_keyword->start,
2390 .end = statements == NULL ? begin_keyword->end : statements->base.location.end
2393 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2394 .statements = statements,
2395 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2405pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2406 // If the begin keyword doesn't exist, we set the start on the begin_node
2407 if (!node->begin_keyword_loc.start) {
2408 node->base.location.start = rescue_clause->base.location.start;
2410 node->base.location.end = rescue_clause->base.location.end;
2411 node->rescue_clause = rescue_clause;
2418pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2419 node->base.location.end = else_clause->base.location.end;
2420 node->else_clause = else_clause;
2427pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2428 node->base.location.end = ensure_clause->base.location.end;
2429 node->ensure_clause = ensure_clause;
2436pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2437 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2439 node->base.location.end = end_keyword->end;
2440 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2446static pm_block_argument_node_t *
2447pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2448 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2450 *node = (pm_block_argument_node_t) {
2452 .type = PM_BLOCK_ARGUMENT_NODE,
2453 .node_id = PM_NODE_IDENTIFY(parser),
2455 .start = operator->start,
2456 .end = expression == NULL ? operator->end : expression->location.end
2459 .expression = expression,
2460 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2469static pm_block_node_t *
2470pm_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) {
2471 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2473 *node = (pm_block_node_t) {
2475 .type = PM_BLOCK_NODE,
2476 .node_id = PM_NODE_IDENTIFY(parser),
2477 .location = { .start = opening->start, .end = closing->end },
2480 .parameters = parameters,
2482 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2483 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2492static pm_block_parameter_node_t *
2493pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2494 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2495 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2497 *node = (pm_block_parameter_node_t) {
2499 .type = PM_BLOCK_PARAMETER_NODE,
2500 .node_id = PM_NODE_IDENTIFY(parser),
2502 .start = operator->start,
2503 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
2506 .name = pm_parser_optional_constant_id_token(parser, name),
2507 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2508 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2517static pm_block_parameters_node_t *
2518pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2519 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2521 const uint8_t *start;
2522 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2523 start = opening->start;
2524 } else if (parameters != NULL) {
2525 start = parameters->base.location.start;
2531 if (parameters != NULL) {
2532 end = parameters->base.location.end;
2533 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2539 *node = (pm_block_parameters_node_t) {
2541 .type = PM_BLOCK_PARAMETERS_NODE,
2542 .node_id = PM_NODE_IDENTIFY(parser),
2548 .parameters = parameters,
2549 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2550 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2561pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2562 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2564 node->base.location.end = closing->end;
2565 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2571static pm_block_local_variable_node_t *
2572pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2573 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2575 *node = (pm_block_local_variable_node_t) {
2577 .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
2578 .node_id = PM_NODE_IDENTIFY(parser),
2579 .location = PM_LOCATION_TOKEN_VALUE(name),
2581 .name = pm_parser_constant_id_token(parser, name)
2591pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2592 pm_node_list_append(&node->locals, (pm_node_t *) local);
2594 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2595 node->base.location.end = local->base.location.end;
2601static pm_break_node_t *
2602pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2603 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2604 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2606 *node = (pm_break_node_t) {
2608 .type = PM_BREAK_NODE,
2609 .node_id = PM_NODE_IDENTIFY(parser),
2611 .start = keyword->start,
2612 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
2615 .arguments = arguments,
2616 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2622// There are certain flags that we want to use internally but don't want to
2623// expose because they are not relevant beyond parsing. Therefore we'll define
2624// them here and not define them in config.yml/a header file.
2625static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
2626static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
2627static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
2628static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
2635static pm_call_node_t *
2636pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2637 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2639 *node = (pm_call_node_t) {
2641 .type = PM_CALL_NODE,
2643 .node_id = PM_NODE_IDENTIFY(parser),
2644 .location = PM_LOCATION_NULL_VALUE(parser),
2647 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2648 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2649 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2651 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2663static inline pm_node_flags_t
2664pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2665 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2672static pm_call_node_t *
2673pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2674 pm_assert_value_expression(parser, receiver);
2676 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2677 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2678 flags |= PM_CALL_NODE_FLAGS_INDEX;
2681 pm_call_node_t *node = pm_call_node_create(parser, flags);
2683 node->base.location.start = receiver->location.start;
2684 node->base.location.end = pm_arguments_end(arguments);
2686 node->receiver = receiver;
2687 node->message_loc.start = arguments->opening_loc.start;
2688 node->message_loc.end = arguments->closing_loc.end;
2690 node->opening_loc = arguments->opening_loc;
2691 node->arguments = arguments->arguments;
2692 node->closing_loc = arguments->closing_loc;
2693 node->block = arguments->block;
2695 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2702static pm_call_node_t *
2703pm_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) {
2704 pm_assert_value_expression(parser, receiver);
2705 pm_assert_value_expression(parser, argument);
2707 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2709 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2710 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2712 node->receiver = receiver;
2713 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2715 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2716 pm_arguments_node_arguments_append(arguments, argument);
2717 node->arguments = arguments;
2719 node->name = pm_parser_constant_id_token(parser, operator);
2726static pm_call_node_t *
2727pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2728 pm_assert_value_expression(parser, receiver);
2730 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2732 node->base.location.start = receiver->location.start;
2733 const uint8_t *end = pm_arguments_end(arguments);
2737 node->base.location.end = end;
2739 node->receiver = receiver;
2740 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2741 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2742 node->opening_loc = arguments->opening_loc;
2743 node->arguments = arguments->arguments;
2744 node->closing_loc = arguments->closing_loc;
2745 node->block = arguments->block;
2747 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2748 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2751 node->name = pm_parser_constant_id_token(parser, message);
2758static pm_call_node_t *
2759pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2760 pm_call_node_t *node = pm_call_node_create(parser, 0);
2761 node->base.location.start = parser->start;
2762 node->base.location.end = parser->end;
2764 node->receiver = receiver;
2765 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2766 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2767 node->arguments = arguments;
2769 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2777static pm_call_node_t *
2778pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2779 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2781 node->base.location.start = message->start;
2782 node->base.location.end = pm_arguments_end(arguments);
2784 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2785 node->opening_loc = arguments->opening_loc;
2786 node->arguments = arguments->arguments;
2787 node->closing_loc = arguments->closing_loc;
2788 node->block = arguments->block;
2790 node->name = pm_parser_constant_id_token(parser, message);
2798static pm_call_node_t *
2799pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2800 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2802 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2803 node->arguments = arguments;
2812static pm_call_node_t *
2813pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2814 pm_assert_value_expression(parser, receiver);
2815 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2817 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2819 node->base.location.start = message->start;
2820 if (arguments->closing_loc.start != NULL) {
2821 node->base.location.end = arguments->closing_loc.end;
2823 assert(receiver != NULL);
2824 node->base.location.end = receiver->location.end;
2827 node->receiver = receiver;
2828 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2829 node->opening_loc = arguments->opening_loc;
2830 node->arguments = arguments->arguments;
2831 node->closing_loc = arguments->closing_loc;
2833 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2840static pm_call_node_t *
2841pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2842 pm_assert_value_expression(parser, receiver);
2844 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2846 node->base.location.start = receiver->location.start;
2847 node->base.location.end = pm_arguments_end(arguments);
2849 node->receiver = receiver;
2850 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2851 node->opening_loc = arguments->opening_loc;
2852 node->arguments = arguments->arguments;
2853 node->closing_loc = arguments->closing_loc;
2854 node->block = arguments->block;
2856 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2857 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2860 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2867static pm_call_node_t *
2868pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2869 pm_assert_value_expression(parser, receiver);
2871 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2873 node->base.location.start = operator->start;
2874 node->base.location.end = receiver->location.end;
2876 node->receiver = receiver;
2877 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2879 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2887static pm_call_node_t *
2888pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2889 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2891 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2892 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2894 node->name = pm_parser_constant_id_token(parser, message);
2903pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2905 (node->message_loc.start != NULL) &&
2906 (node->message_loc.end[-1] != '!') &&
2907 (node->message_loc.end[-1] != '?') &&
2908 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2909 (node->opening_loc.start == NULL) &&
2910 (node->arguments == NULL) &&
2911 (node->block == NULL)
2919pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2920 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2922 if (write_constant->length > 0) {
2923 size_t length = write_constant->length - 1;
2925 void *memory = xmalloc(length);
2926 memcpy(memory, write_constant->start, length);
2928 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2930 // We can get here if the message was missing because of a syntax error.
2931 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2938static pm_call_and_write_node_t *
2939pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2940 assert(target->block == NULL);
2941 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2942 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2944 *node = (pm_call_and_write_node_t) {
2946 .type = PM_CALL_AND_WRITE_NODE,
2947 .flags = target->base.flags,
2948 .node_id = PM_NODE_IDENTIFY(parser),
2950 .start = target->base.location.start,
2951 .end = value->location.end
2954 .receiver = target->receiver,
2955 .call_operator_loc = target->call_operator_loc,
2956 .message_loc = target->message_loc,
2958 .write_name = target->name,
2959 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2963 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2965 // Here we're going to free the target, since it is no longer necessary.
2966 // However, we don't want to call `pm_node_destroy` because we want to keep
2967 // around all of its children since we just reused them.
2978pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2979 if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
2980 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2982 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2983 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2984 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2990 if (block != NULL) {
2991 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2999static pm_index_and_write_node_t *
3000pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3001 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3002 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
3004 pm_index_arguments_check(parser, target->arguments, target->block);
3006 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3007 *node = (pm_index_and_write_node_t) {
3009 .type = PM_INDEX_AND_WRITE_NODE,
3010 .flags = target->base.flags,
3011 .node_id = PM_NODE_IDENTIFY(parser),
3013 .start = target->base.location.start,
3014 .end = value->location.end
3017 .receiver = target->receiver,
3018 .call_operator_loc = target->call_operator_loc,
3019 .opening_loc = target->opening_loc,
3020 .arguments = target->arguments,
3021 .closing_loc = target->closing_loc,
3022 .block = (pm_block_argument_node_t *) target->block,
3023 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3027 // Here we're going to free the target, since it is no longer necessary.
3028 // However, we don't want to call `pm_node_destroy` because we want to keep
3029 // around all of its children since we just reused them.
3038static pm_call_operator_write_node_t *
3039pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3040 assert(target->block == NULL);
3041 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3043 *node = (pm_call_operator_write_node_t) {
3045 .type = PM_CALL_OPERATOR_WRITE_NODE,
3046 .flags = target->base.flags,
3047 .node_id = PM_NODE_IDENTIFY(parser),
3049 .start = target->base.location.start,
3050 .end = value->location.end
3053 .receiver = target->receiver,
3054 .call_operator_loc = target->call_operator_loc,
3055 .message_loc = target->message_loc,
3057 .write_name = target->name,
3058 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3059 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3063 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3065 // Here we're going to free the target, since it is no longer necessary.
3066 // However, we don't want to call `pm_node_destroy` because we want to keep
3067 // around all of its children since we just reused them.
3076static pm_index_operator_write_node_t *
3077pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3078 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3080 pm_index_arguments_check(parser, target->arguments, target->block);
3082 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3083 *node = (pm_index_operator_write_node_t) {
3085 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3086 .flags = target->base.flags,
3087 .node_id = PM_NODE_IDENTIFY(parser),
3089 .start = target->base.location.start,
3090 .end = value->location.end
3093 .receiver = target->receiver,
3094 .call_operator_loc = target->call_operator_loc,
3095 .opening_loc = target->opening_loc,
3096 .arguments = target->arguments,
3097 .closing_loc = target->closing_loc,
3098 .block = (pm_block_argument_node_t *) target->block,
3099 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3100 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3104 // Here we're going to free the target, since it is no longer necessary.
3105 // However, we don't want to call `pm_node_destroy` because we want to keep
3106 // around all of its children since we just reused them.
3115static pm_call_or_write_node_t *
3116pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3117 assert(target->block == NULL);
3118 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3119 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3121 *node = (pm_call_or_write_node_t) {
3123 .type = PM_CALL_OR_WRITE_NODE,
3124 .flags = target->base.flags,
3125 .node_id = PM_NODE_IDENTIFY(parser),
3127 .start = target->base.location.start,
3128 .end = value->location.end
3131 .receiver = target->receiver,
3132 .call_operator_loc = target->call_operator_loc,
3133 .message_loc = target->message_loc,
3135 .write_name = target->name,
3136 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3140 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3142 // Here we're going to free the target, since it is no longer necessary.
3143 // However, we don't want to call `pm_node_destroy` because we want to keep
3144 // around all of its children since we just reused them.
3153static pm_index_or_write_node_t *
3154pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3155 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3156 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3158 pm_index_arguments_check(parser, target->arguments, target->block);
3160 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3161 *node = (pm_index_or_write_node_t) {
3163 .type = PM_INDEX_OR_WRITE_NODE,
3164 .flags = target->base.flags,
3165 .node_id = PM_NODE_IDENTIFY(parser),
3167 .start = target->base.location.start,
3168 .end = value->location.end
3171 .receiver = target->receiver,
3172 .call_operator_loc = target->call_operator_loc,
3173 .opening_loc = target->opening_loc,
3174 .arguments = target->arguments,
3175 .closing_loc = target->closing_loc,
3176 .block = (pm_block_argument_node_t *) target->block,
3177 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3181 // Here we're going to free the target, since it is no longer necessary.
3182 // However, we don't want to call `pm_node_destroy` because we want to keep
3183 // around all of its children since we just reused them.
3193static pm_call_target_node_t *
3194pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3195 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3197 *node = (pm_call_target_node_t) {
3199 .type = PM_CALL_TARGET_NODE,
3200 .flags = target->base.flags,
3201 .node_id = PM_NODE_IDENTIFY(parser),
3202 .location = target->base.location
3204 .receiver = target->receiver,
3205 .call_operator_loc = target->call_operator_loc,
3206 .name = target->name,
3207 .message_loc = target->message_loc
3210 // Here we're going to free the target, since it is no longer necessary.
3211 // However, we don't want to call `pm_node_destroy` because we want to keep
3212 // around all of its children since we just reused them.
3222static pm_index_target_node_t *
3223pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3224 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3225 pm_node_flags_t flags = target->base.flags;
3227 pm_index_arguments_check(parser, target->arguments, target->block);
3229 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3230 *node = (pm_index_target_node_t) {
3232 .type = PM_INDEX_TARGET_NODE,
3233 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3234 .node_id = PM_NODE_IDENTIFY(parser),
3235 .location = target->base.location
3237 .receiver = target->receiver,
3238 .opening_loc = target->opening_loc,
3239 .arguments = target->arguments,
3240 .closing_loc = target->closing_loc,
3241 .block = (pm_block_argument_node_t *) target->block,
3244 // Here we're going to free the target, since it is no longer necessary.
3245 // However, we don't want to call `pm_node_destroy` because we want to keep
3246 // around all of its children since we just reused them.
3255static pm_capture_pattern_node_t *
3256pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3257 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3259 *node = (pm_capture_pattern_node_t) {
3261 .type = PM_CAPTURE_PATTERN_NODE,
3262 .node_id = PM_NODE_IDENTIFY(parser),
3264 .start = value->location.start,
3265 .end = target->base.location.end
3270 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3279static pm_case_node_t *
3280pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3281 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3283 *node = (pm_case_node_t) {
3285 .type = PM_CASE_NODE,
3286 .node_id = PM_NODE_IDENTIFY(parser),
3288 .start = case_keyword->start,
3289 .end = end_keyword->end
3292 .predicate = predicate,
3293 .else_clause = NULL,
3294 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3295 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3306pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3307 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3309 pm_node_list_append(&node->conditions, condition);
3310 node->base.location.end = condition->location.end;
3317pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3318 node->else_clause = else_clause;
3319 node->base.location.end = else_clause->base.location.end;
3326pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3327 node->base.location.end = end_keyword->end;
3328 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3334static pm_case_match_node_t *
3335pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3336 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3338 *node = (pm_case_match_node_t) {
3340 .type = PM_CASE_MATCH_NODE,
3341 .node_id = PM_NODE_IDENTIFY(parser),
3343 .start = case_keyword->start,
3344 .end = end_keyword->end
3347 .predicate = predicate,
3348 .else_clause = NULL,
3349 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3350 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3361pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3362 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3364 pm_node_list_append(&node->conditions, condition);
3365 node->base.location.end = condition->location.end;
3372pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3373 node->else_clause = else_clause;
3374 node->base.location.end = else_clause->base.location.end;
3381pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3382 node->base.location.end = end_keyword->end;
3383 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3389static pm_class_node_t *
3390pm_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) {
3391 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3393 *node = (pm_class_node_t) {
3395 .type = PM_CLASS_NODE,
3396 .node_id = PM_NODE_IDENTIFY(parser),
3397 .location = { .start = class_keyword->start, .end = end_keyword->end },
3400 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3401 .constant_path = constant_path,
3402 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3403 .superclass = superclass,
3405 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3406 .name = pm_parser_constant_id_token(parser, name)
3415static pm_class_variable_and_write_node_t *
3416pm_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) {
3417 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3418 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3420 *node = (pm_class_variable_and_write_node_t) {
3422 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3423 .node_id = PM_NODE_IDENTIFY(parser),
3425 .start = target->base.location.start,
3426 .end = value->location.end
3429 .name = target->name,
3430 .name_loc = target->base.location,
3431 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3441static pm_class_variable_operator_write_node_t *
3442pm_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) {
3443 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3445 *node = (pm_class_variable_operator_write_node_t) {
3447 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3448 .node_id = PM_NODE_IDENTIFY(parser),
3450 .start = target->base.location.start,
3451 .end = value->location.end
3454 .name = target->name,
3455 .name_loc = target->base.location,
3456 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3458 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3467static pm_class_variable_or_write_node_t *
3468pm_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) {
3469 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3470 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3472 *node = (pm_class_variable_or_write_node_t) {
3474 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3475 .node_id = PM_NODE_IDENTIFY(parser),
3477 .start = target->base.location.start,
3478 .end = value->location.end
3481 .name = target->name,
3482 .name_loc = target->base.location,
3483 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3493static pm_class_variable_read_node_t *
3494pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3495 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3496 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3498 *node = (pm_class_variable_read_node_t) {
3500 .type = PM_CLASS_VARIABLE_READ_NODE,
3501 .node_id = PM_NODE_IDENTIFY(parser),
3502 .location = PM_LOCATION_TOKEN_VALUE(token)
3504 .name = pm_parser_constant_id_token(parser, token)
3516static inline pm_node_flags_t
3517pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3518 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3527static pm_class_variable_write_node_t *
3528pm_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) {
3529 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3531 *node = (pm_class_variable_write_node_t) {
3533 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3534 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3535 .node_id = PM_NODE_IDENTIFY(parser),
3537 .start = read_node->base.location.start,
3538 .end = value->location.end
3541 .name = read_node->name,
3542 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3543 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3553static pm_constant_path_and_write_node_t *
3554pm_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) {
3555 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3556 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3558 *node = (pm_constant_path_and_write_node_t) {
3560 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3561 .node_id = PM_NODE_IDENTIFY(parser),
3563 .start = target->base.location.start,
3564 .end = value->location.end
3568 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3578static pm_constant_path_operator_write_node_t *
3579pm_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) {
3580 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3582 *node = (pm_constant_path_operator_write_node_t) {
3584 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3585 .node_id = PM_NODE_IDENTIFY(parser),
3587 .start = target->base.location.start,
3588 .end = value->location.end
3592 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3594 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3603static pm_constant_path_or_write_node_t *
3604pm_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) {
3605 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3606 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3608 *node = (pm_constant_path_or_write_node_t) {
3610 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3611 .node_id = PM_NODE_IDENTIFY(parser),
3613 .start = target->base.location.start,
3614 .end = value->location.end
3618 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3628static pm_constant_path_node_t *
3629pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3630 pm_assert_value_expression(parser, parent);
3631 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3633 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3634 if (name_token->type == PM_TOKEN_CONSTANT) {
3635 name = pm_parser_constant_id_token(parser, name_token);
3638 *node = (pm_constant_path_node_t) {
3640 .type = PM_CONSTANT_PATH_NODE,
3641 .node_id = PM_NODE_IDENTIFY(parser),
3643 .start = parent == NULL ? delimiter->start : parent->location.start,
3644 .end = name_token->end
3649 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3650 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3659static pm_constant_path_write_node_t *
3660pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3661 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3663 *node = (pm_constant_path_write_node_t) {
3665 .type = PM_CONSTANT_PATH_WRITE_NODE,
3666 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3667 .node_id = PM_NODE_IDENTIFY(parser),
3669 .start = target->base.location.start,
3670 .end = value->location.end
3674 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3684static pm_constant_and_write_node_t *
3685pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3686 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3687 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3689 *node = (pm_constant_and_write_node_t) {
3691 .type = PM_CONSTANT_AND_WRITE_NODE,
3692 .node_id = PM_NODE_IDENTIFY(parser),
3694 .start = target->base.location.start,
3695 .end = value->location.end
3698 .name = target->name,
3699 .name_loc = target->base.location,
3700 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3710static pm_constant_operator_write_node_t *
3711pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3712 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3714 *node = (pm_constant_operator_write_node_t) {
3716 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3717 .node_id = PM_NODE_IDENTIFY(parser),
3719 .start = target->base.location.start,
3720 .end = value->location.end
3723 .name = target->name,
3724 .name_loc = target->base.location,
3725 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3727 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3736static pm_constant_or_write_node_t *
3737pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3738 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3739 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3741 *node = (pm_constant_or_write_node_t) {
3743 .type = PM_CONSTANT_OR_WRITE_NODE,
3744 .node_id = PM_NODE_IDENTIFY(parser),
3746 .start = target->base.location.start,
3747 .end = value->location.end
3750 .name = target->name,
3751 .name_loc = target->base.location,
3752 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3762static pm_constant_read_node_t *
3763pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3764 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3765 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3767 *node = (pm_constant_read_node_t) {
3769 .type = PM_CONSTANT_READ_NODE,
3770 .node_id = PM_NODE_IDENTIFY(parser),
3771 .location = PM_LOCATION_TOKEN_VALUE(name)
3773 .name = pm_parser_constant_id_token(parser, name)
3782static pm_constant_write_node_t *
3783pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3784 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3786 *node = (pm_constant_write_node_t) {
3788 .type = PM_CONSTANT_WRITE_NODE,
3789 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3790 .node_id = PM_NODE_IDENTIFY(parser),
3792 .start = target->base.location.start,
3793 .end = value->location.end
3796 .name = target->name,
3797 .name_loc = target->base.location,
3798 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3809pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3810 switch (PM_NODE_TYPE(node)) {
3811 case PM_BEGIN_NODE: {
3812 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3813 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3816 case PM_PARENTHESES_NODE: {
3817 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3818 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3821 case PM_STATEMENTS_NODE: {
3822 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3823 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3828 case PM_IMAGINARY_NODE:
3829 case PM_INTEGER_NODE:
3830 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3831 case PM_INTERPOLATED_STRING_NODE:
3832 case PM_INTERPOLATED_SYMBOL_NODE:
3833 case PM_INTERPOLATED_X_STRING_NODE:
3834 case PM_RATIONAL_NODE:
3835 case PM_REGULAR_EXPRESSION_NODE:
3836 case PM_SOURCE_ENCODING_NODE:
3837 case PM_SOURCE_FILE_NODE:
3838 case PM_SOURCE_LINE_NODE:
3839 case PM_STRING_NODE:
3840 case PM_SYMBOL_NODE:
3841 case PM_X_STRING_NODE:
3842 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3852static pm_def_node_t *
3854 pm_parser_t *parser,
3855 pm_constant_id_t name,
3856 const pm_token_t *name_loc,
3857 pm_node_t *receiver,
3858 pm_parameters_node_t *parameters,
3860 pm_constant_id_list_t *locals,
3861 const pm_token_t *def_keyword,
3862 const pm_token_t *operator,
3863 const pm_token_t *lparen,
3864 const pm_token_t *rparen,
3865 const pm_token_t *equal,
3866 const pm_token_t *end_keyword
3868 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3871 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3872 end = body->location.end;
3874 end = end_keyword->end;
3877 if ((receiver != NULL) && PM_NODE_TYPE_P(receiver, PM_PARENTHESES_NODE)) {
3878 pm_def_node_receiver_check(parser, receiver);
3881 *node = (pm_def_node_t) {
3883 .type = PM_DEF_NODE,
3884 .node_id = PM_NODE_IDENTIFY(parser),
3885 .location = { .start = def_keyword->start, .end = end },
3888 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3889 .receiver = receiver,
3890 .parameters = parameters,
3893 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3894 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3895 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3896 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3897 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3898 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3907static pm_defined_node_t *
3908pm_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) {
3909 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3911 *node = (pm_defined_node_t) {
3913 .type = PM_DEFINED_NODE,
3914 .node_id = PM_NODE_IDENTIFY(parser),
3916 .start = keyword_loc->start,
3917 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3920 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3922 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3923 .keyword_loc = *keyword_loc
3932static pm_else_node_t *
3933pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3934 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3935 const uint8_t *end = NULL;
3936 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3937 end = statements->base.location.end;
3939 end = end_keyword->end;
3942 *node = (pm_else_node_t) {
3944 .type = PM_ELSE_NODE,
3945 .node_id = PM_NODE_IDENTIFY(parser),
3947 .start = else_keyword->start,
3951 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3952 .statements = statements,
3953 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3962static pm_embedded_statements_node_t *
3963pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3964 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3966 *node = (pm_embedded_statements_node_t) {
3968 .type = PM_EMBEDDED_STATEMENTS_NODE,
3969 .node_id = PM_NODE_IDENTIFY(parser),
3971 .start = opening->start,
3975 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3976 .statements = statements,
3977 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3986static pm_embedded_variable_node_t *
3987pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3988 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3990 *node = (pm_embedded_variable_node_t) {
3992 .type = PM_EMBEDDED_VARIABLE_NODE,
3993 .node_id = PM_NODE_IDENTIFY(parser),
3995 .start = operator->start,
3996 .end = variable->location.end
3999 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4000 .variable = variable
4009static pm_ensure_node_t *
4010pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4011 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4013 *node = (pm_ensure_node_t) {
4015 .type = PM_ENSURE_NODE,
4016 .node_id = PM_NODE_IDENTIFY(parser),
4018 .start = ensure_keyword->start,
4019 .end = end_keyword->end
4022 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4023 .statements = statements,
4024 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4033static pm_false_node_t *
4034pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4035 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4036 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4038 *node = (pm_false_node_t) {{
4039 .type = PM_FALSE_NODE,
4040 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4041 .node_id = PM_NODE_IDENTIFY(parser),
4042 .location = PM_LOCATION_TOKEN_VALUE(token)
4052static pm_find_pattern_node_t *
4053pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4054 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4056 pm_node_t *left = nodes->nodes[0];
4057 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4058 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4062 if (nodes->size == 1) {
4063 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4065 right = nodes->nodes[nodes->size - 1];
4066 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4069#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4070 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4071 // The resulting AST will anyway be ignored, but this file still needs to compile.
4072 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4074 pm_node_t *right_splat_node = right;
4076 *node = (pm_find_pattern_node_t) {
4078 .type = PM_FIND_PATTERN_NODE,
4079 .node_id = PM_NODE_IDENTIFY(parser),
4081 .start = left->location.start,
4082 .end = right->location.end,
4086 .left = left_splat_node,
4087 .right = right_splat_node,
4089 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4090 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4093 // For now we're going to just copy over each pointer manually. This could be
4094 // much more efficient, as we could instead resize the node list to only point
4096 for (size_t index = 1; index < nodes->size - 1; index++) {
4097 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4108pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4109 ptrdiff_t diff = token->end - token->start;
4110 if (diff <= 0) return 0.0;
4112 // First, get a buffer of the content.
4113 size_t length = (size_t) diff;
4114 char *buffer = xmalloc(sizeof(char) * (length + 1));
4115 memcpy((void *) buffer, token->start, length);
4117 // Next, determine if we need to replace the decimal point because of
4118 // locale-specific options, and then normalize them if we have to.
4119 char decimal_point = *localeconv()->decimal_point;
4120 if (decimal_point != '.') {
4121 for (size_t index = 0; index < length; index++) {
4122 if (buffer[index] == '.') buffer[index] = decimal_point;
4126 // Next, handle underscores by removing them from the buffer.
4127 for (size_t index = 0; index < length; index++) {
4128 if (buffer[index] == '_') {
4129 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4134 // Null-terminate the buffer so that strtod cannot read off the end.
4135 buffer[length] = '\0';
4137 // Now, call strtod to parse the value. Note that CRuby has their own
4138 // version of strtod which avoids locales. We're okay using the locale-aware
4139 // version because we've already validated through the parser that the token
4140 // is in a valid format.
4143 double value = strtod(buffer, &eptr);
4145 // This should never happen, because we've already checked that the token
4146 // is in a valid format. However it's good to be safe.
4147 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4148 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4149 xfree((void *) buffer);
4153 // If errno is set, then it should only be ERANGE. At this point we need to
4154 // check if it's infinity (it should be).
4155 if (errno == ERANGE && PRISM_ISINF(value)) {
4157 const char *ellipsis;
4163 warn_width = (int) length;
4167 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);
4168 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4171 // Finally we can free the buffer and return the value.
4172 xfree((void *) buffer);
4179static pm_float_node_t *
4180pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4181 assert(token->type == PM_TOKEN_FLOAT);
4182 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4184 *node = (pm_float_node_t) {
4186 .type = PM_FLOAT_NODE,
4187 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4188 .node_id = PM_NODE_IDENTIFY(parser),
4189 .location = PM_LOCATION_TOKEN_VALUE(token)
4191 .value = pm_double_parse(parser, token)
4200static pm_imaginary_node_t *
4201pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4202 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4204 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4205 *node = (pm_imaginary_node_t) {
4207 .type = PM_IMAGINARY_NODE,
4208 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4209 .node_id = PM_NODE_IDENTIFY(parser),
4210 .location = PM_LOCATION_TOKEN_VALUE(token)
4212 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4213 .type = PM_TOKEN_FLOAT,
4214 .start = token->start,
4215 .end = token->end - 1
4225static pm_rational_node_t *
4226pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4227 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4229 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4230 *node = (pm_rational_node_t) {
4232 .type = PM_RATIONAL_NODE,
4233 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4234 .node_id = PM_NODE_IDENTIFY(parser),
4235 .location = PM_LOCATION_TOKEN_VALUE(token)
4238 .denominator = { 0 }
4241 const uint8_t *start = token->start;
4242 const uint8_t *end = token->end - 1; // r
4244 while (start < end && *start == '0') start++; // 0.1 -> .1
4245 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4247 size_t length = (size_t) (end - start);
4249 node->denominator.value = 1;
4253 const uint8_t *point = memchr(start, '.', length);
4254 assert(point && "should have a decimal point");
4256 uint8_t *digits = malloc(length);
4257 if (digits == NULL) {
4258 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4262 memcpy(digits, start, (unsigned long) (point - start));
4263 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4264 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4267 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4268 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4271 pm_integers_reduce(&node->numerator, &node->denominator);
4279static pm_imaginary_node_t *
4280pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4281 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4283 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4284 *node = (pm_imaginary_node_t) {
4286 .type = PM_IMAGINARY_NODE,
4287 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4288 .node_id = PM_NODE_IDENTIFY(parser),
4289 .location = PM_LOCATION_TOKEN_VALUE(token)
4291 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4292 .type = PM_TOKEN_FLOAT_RATIONAL,
4293 .start = token->start,
4294 .end = token->end - 1
4304static pm_for_node_t *
4306 pm_parser_t *parser,
4308 pm_node_t *collection,
4309 pm_statements_node_t *statements,
4310 const pm_token_t *for_keyword,
4311 const pm_token_t *in_keyword,
4312 const pm_token_t *do_keyword,
4313 const pm_token_t *end_keyword
4315 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4317 *node = (pm_for_node_t) {
4319 .type = PM_FOR_NODE,
4320 .node_id = PM_NODE_IDENTIFY(parser),
4322 .start = for_keyword->start,
4323 .end = end_keyword->end
4327 .collection = collection,
4328 .statements = statements,
4329 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4330 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4331 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4332 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4341static pm_forwarding_arguments_node_t *
4342pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4343 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4344 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4346 *node = (pm_forwarding_arguments_node_t) {{
4347 .type = PM_FORWARDING_ARGUMENTS_NODE,
4348 .node_id = PM_NODE_IDENTIFY(parser),
4349 .location = PM_LOCATION_TOKEN_VALUE(token)
4358static pm_forwarding_parameter_node_t *
4359pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4360 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4361 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4363 *node = (pm_forwarding_parameter_node_t) {{
4364 .type = PM_FORWARDING_PARAMETER_NODE,
4365 .node_id = PM_NODE_IDENTIFY(parser),
4366 .location = PM_LOCATION_TOKEN_VALUE(token)
4375static pm_forwarding_super_node_t *
4376pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4377 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4378 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4379 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4381 pm_block_node_t *block = NULL;
4382 if (arguments->block != NULL) {
4383 block = (pm_block_node_t *) arguments->block;
4386 *node = (pm_forwarding_super_node_t) {
4388 .type = PM_FORWARDING_SUPER_NODE,
4389 .node_id = PM_NODE_IDENTIFY(parser),
4391 .start = token->start,
4392 .end = block != NULL ? block->base.location.end : token->end
4405static pm_hash_pattern_node_t *
4406pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4407 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4409 *node = (pm_hash_pattern_node_t) {
4411 .type = PM_HASH_PATTERN_NODE,
4412 .node_id = PM_NODE_IDENTIFY(parser),
4414 .start = opening->start,
4419 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4420 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4431static pm_hash_pattern_node_t *
4432pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4433 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4435 const uint8_t *start;
4438 if (elements->size > 0) {
4440 start = elements->nodes[0]->location.start;
4441 end = rest->location.end;
4443 start = elements->nodes[0]->location.start;
4444 end = elements->nodes[elements->size - 1]->location.end;
4447 assert(rest != NULL);
4448 start = rest->location.start;
4449 end = rest->location.end;
4452 *node = (pm_hash_pattern_node_t) {
4454 .type = PM_HASH_PATTERN_NODE,
4455 .node_id = PM_NODE_IDENTIFY(parser),
4464 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4465 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4469 PM_NODE_LIST_FOREACH(elements, index, element) {
4470 pm_node_list_append(&node->elements, element);
4479static pm_constant_id_t
4480pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4481 switch (PM_NODE_TYPE(target)) {
4482 case PM_GLOBAL_VARIABLE_READ_NODE:
4483 return ((pm_global_variable_read_node_t *) target)->name;
4484 case PM_BACK_REFERENCE_READ_NODE:
4485 return ((pm_back_reference_read_node_t *) target)->name;
4486 case PM_NUMBERED_REFERENCE_READ_NODE:
4487 // This will only ever happen in the event of a syntax error, but we
4488 // still need to provide something for the node.
4489 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4491 assert(false && "unreachable");
4492 return (pm_constant_id_t) -1;
4499static pm_global_variable_and_write_node_t *
4500pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4501 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4502 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4504 *node = (pm_global_variable_and_write_node_t) {
4506 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4507 .node_id = PM_NODE_IDENTIFY(parser),
4509 .start = target->location.start,
4510 .end = value->location.end
4513 .name = pm_global_variable_write_name(parser, target),
4514 .name_loc = target->location,
4515 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4525static pm_global_variable_operator_write_node_t *
4526pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4527 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4529 *node = (pm_global_variable_operator_write_node_t) {
4531 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4532 .node_id = PM_NODE_IDENTIFY(parser),
4534 .start = target->location.start,
4535 .end = value->location.end
4538 .name = pm_global_variable_write_name(parser, target),
4539 .name_loc = target->location,
4540 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4542 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4551static pm_global_variable_or_write_node_t *
4552pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4553 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4554 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4556 *node = (pm_global_variable_or_write_node_t) {
4558 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4559 .node_id = PM_NODE_IDENTIFY(parser),
4561 .start = target->location.start,
4562 .end = value->location.end
4565 .name = pm_global_variable_write_name(parser, target),
4566 .name_loc = target->location,
4567 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4577static pm_global_variable_read_node_t *
4578pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4579 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4581 *node = (pm_global_variable_read_node_t) {
4583 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4584 .node_id = PM_NODE_IDENTIFY(parser),
4585 .location = PM_LOCATION_TOKEN_VALUE(name),
4587 .name = pm_parser_constant_id_token(parser, name)
4596static pm_global_variable_read_node_t *
4597pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4598 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4600 *node = (pm_global_variable_read_node_t) {
4602 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4603 .node_id = PM_NODE_IDENTIFY(parser),
4604 .location = PM_LOCATION_NULL_VALUE(parser)
4615static pm_global_variable_write_node_t *
4616pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4617 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4619 *node = (pm_global_variable_write_node_t) {
4621 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4622 .node_id = PM_NODE_IDENTIFY(parser),
4623 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4625 .start = target->location.start,
4626 .end = value->location.end
4629 .name = pm_global_variable_write_name(parser, target),
4630 .name_loc = PM_LOCATION_NODE_VALUE(target),
4631 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4641static pm_global_variable_write_node_t *
4642pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4643 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4645 *node = (pm_global_variable_write_node_t) {
4647 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4648 .node_id = PM_NODE_IDENTIFY(parser),
4649 .location = PM_LOCATION_NULL_VALUE(parser)
4652 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4653 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4663static pm_hash_node_t *
4664pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4665 assert(opening != NULL);
4666 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4668 *node = (pm_hash_node_t) {
4670 .type = PM_HASH_NODE,
4671 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4672 .node_id = PM_NODE_IDENTIFY(parser),
4673 .location = PM_LOCATION_TOKEN_VALUE(opening)
4675 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4676 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4687pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4688 pm_node_list_append(&hash->elements, element);
4690 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4691 if (static_literal) {
4692 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4693 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);
4694 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4695 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4698 if (!static_literal) {
4699 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4704pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4705 hash->base.location.end = token->end;
4706 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4712static pm_if_node_t *
4713pm_if_node_create(pm_parser_t *parser,
4714 const pm_token_t *if_keyword,
4715 pm_node_t *predicate,
4716 const pm_token_t *then_keyword,
4717 pm_statements_node_t *statements,
4718 pm_node_t *subsequent,
4719 const pm_token_t *end_keyword
4721 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4722 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4725 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4726 end = end_keyword->end;
4727 } else if (subsequent != NULL) {
4728 end = subsequent->location.end;
4729 } else if (pm_statements_node_body_length(statements) != 0) {
4730 end = statements->base.location.end;
4732 end = predicate->location.end;
4735 *node = (pm_if_node_t) {
4738 .flags = PM_NODE_FLAG_NEWLINE,
4739 .node_id = PM_NODE_IDENTIFY(parser),
4741 .start = if_keyword->start,
4745 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4746 .predicate = predicate,
4747 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4748 .statements = statements,
4749 .subsequent = subsequent,
4750 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4759static pm_if_node_t *
4760pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4761 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4762 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4764 pm_statements_node_t *statements = pm_statements_node_create(parser);
4765 pm_statements_node_body_append(parser, statements, statement, true);
4767 *node = (pm_if_node_t) {
4770 .flags = PM_NODE_FLAG_NEWLINE,
4771 .node_id = PM_NODE_IDENTIFY(parser),
4773 .start = statement->location.start,
4774 .end = predicate->location.end
4777 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4778 .predicate = predicate,
4779 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4780 .statements = statements,
4782 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4791static pm_if_node_t *
4792pm_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) {
4793 pm_assert_value_expression(parser, predicate);
4794 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4796 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4797 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4799 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4800 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4802 pm_token_t end_keyword = not_provided(parser);
4803 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4805 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4807 *node = (pm_if_node_t) {
4810 .flags = PM_NODE_FLAG_NEWLINE,
4811 .node_id = PM_NODE_IDENTIFY(parser),
4813 .start = predicate->location.start,
4814 .end = false_expression->location.end,
4817 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4818 .predicate = predicate,
4819 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4820 .statements = if_statements,
4821 .subsequent = (pm_node_t *) else_node,
4822 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4830pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4831 node->base.location.end = keyword->end;
4832 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4836pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4837 node->base.location.end = keyword->end;
4838 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4844static pm_implicit_node_t *
4845pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4846 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4848 *node = (pm_implicit_node_t) {
4850 .type = PM_IMPLICIT_NODE,
4851 .node_id = PM_NODE_IDENTIFY(parser),
4852 .location = value->location
4863static pm_implicit_rest_node_t *
4864pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4865 assert(token->type == PM_TOKEN_COMMA);
4867 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4869 *node = (pm_implicit_rest_node_t) {
4871 .type = PM_IMPLICIT_REST_NODE,
4872 .node_id = PM_NODE_IDENTIFY(parser),
4873 .location = PM_LOCATION_TOKEN_VALUE(token)
4883static pm_integer_node_t *
4884pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4885 assert(token->type == PM_TOKEN_INTEGER);
4886 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4888 *node = (pm_integer_node_t) {
4890 .type = PM_INTEGER_NODE,
4891 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4892 .node_id = PM_NODE_IDENTIFY(parser),
4893 .location = PM_LOCATION_TOKEN_VALUE(token)
4898 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4900 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4901 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4902 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4903 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4904 default: assert(false && "unreachable"); break;
4907 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4915static pm_imaginary_node_t *
4916pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4917 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4919 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4920 *node = (pm_imaginary_node_t) {
4922 .type = PM_IMAGINARY_NODE,
4923 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4924 .node_id = PM_NODE_IDENTIFY(parser),
4925 .location = PM_LOCATION_TOKEN_VALUE(token)
4927 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4928 .type = PM_TOKEN_INTEGER,
4929 .start = token->start,
4930 .end = token->end - 1
4941static pm_rational_node_t *
4942pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4943 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4945 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4946 *node = (pm_rational_node_t) {
4948 .type = PM_RATIONAL_NODE,
4949 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4950 .node_id = PM_NODE_IDENTIFY(parser),
4951 .location = PM_LOCATION_TOKEN_VALUE(token)
4954 .denominator = { .value = 1, 0 }
4957 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4959 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4960 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4961 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4962 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4963 default: assert(false && "unreachable"); break;
4966 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4975static pm_imaginary_node_t *
4976pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4977 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4979 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4980 *node = (pm_imaginary_node_t) {
4982 .type = PM_IMAGINARY_NODE,
4983 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4984 .node_id = PM_NODE_IDENTIFY(parser),
4985 .location = PM_LOCATION_TOKEN_VALUE(token)
4987 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4988 .type = PM_TOKEN_INTEGER_RATIONAL,
4989 .start = token->start,
4990 .end = token->end - 1
5000static pm_in_node_t *
5001pm_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) {
5002 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
5005 if (statements != NULL) {
5006 end = statements->base.location.end;
5007 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
5008 end = then_keyword->end;
5010 end = pattern->location.end;
5013 *node = (pm_in_node_t) {
5016 .node_id = PM_NODE_IDENTIFY(parser),
5018 .start = in_keyword->start,
5023 .statements = statements,
5024 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5025 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5034static pm_instance_variable_and_write_node_t *
5035pm_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) {
5036 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5037 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5039 *node = (pm_instance_variable_and_write_node_t) {
5041 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5042 .node_id = PM_NODE_IDENTIFY(parser),
5044 .start = target->base.location.start,
5045 .end = value->location.end
5048 .name = target->name,
5049 .name_loc = target->base.location,
5050 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5060static pm_instance_variable_operator_write_node_t *
5061pm_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) {
5062 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5064 *node = (pm_instance_variable_operator_write_node_t) {
5066 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5067 .node_id = PM_NODE_IDENTIFY(parser),
5069 .start = target->base.location.start,
5070 .end = value->location.end
5073 .name = target->name,
5074 .name_loc = target->base.location,
5075 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5077 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5086static pm_instance_variable_or_write_node_t *
5087pm_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) {
5088 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5089 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5091 *node = (pm_instance_variable_or_write_node_t) {
5093 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5094 .node_id = PM_NODE_IDENTIFY(parser),
5096 .start = target->base.location.start,
5097 .end = value->location.end
5100 .name = target->name,
5101 .name_loc = target->base.location,
5102 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5112static pm_instance_variable_read_node_t *
5113pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5114 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5115 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5117 *node = (pm_instance_variable_read_node_t) {
5119 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5120 .node_id = PM_NODE_IDENTIFY(parser),
5121 .location = PM_LOCATION_TOKEN_VALUE(token)
5123 .name = pm_parser_constant_id_token(parser, token)
5133static pm_instance_variable_write_node_t *
5134pm_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) {
5135 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5136 *node = (pm_instance_variable_write_node_t) {
5138 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5139 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5140 .node_id = PM_NODE_IDENTIFY(parser),
5142 .start = read_node->base.location.start,
5143 .end = value->location.end
5146 .name = read_node->name,
5147 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5148 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5161pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5162 switch (PM_NODE_TYPE(part)) {
5163 case PM_STRING_NODE:
5164 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5166 case PM_EMBEDDED_STATEMENTS_NODE: {
5167 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5168 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5170 if (embedded == NULL) {
5171 // If there are no statements or more than one statement, then
5172 // we lose the static literal flag.
5173 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5174 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5175 // If the embedded statement is a string, then we can keep the
5176 // static literal flag and mark the string as frozen.
5177 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5178 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5179 // If the embedded statement is an interpolated string and it's
5180 // a static literal, then we can keep the static literal flag.
5182 // Otherwise we lose the static literal flag.
5183 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5188 case PM_EMBEDDED_VARIABLE_NODE:
5189 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5192 assert(false && "unexpected node type");
5196 pm_node_list_append(parts, part);
5202static pm_interpolated_regular_expression_node_t *
5203pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5204 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5206 *node = (pm_interpolated_regular_expression_node_t) {
5208 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5209 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5210 .node_id = PM_NODE_IDENTIFY(parser),
5212 .start = opening->start,
5216 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5217 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5225pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5226 if (node->base.location.start > part->location.start) {
5227 node->base.location.start = part->location.start;
5229 if (node->base.location.end < part->location.end) {
5230 node->base.location.end = part->location.end;
5233 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5237pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5238 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5239 node->base.location.end = closing->end;
5240 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5267pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5268#define CLEAR_FLAGS(node) \
5269 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))
5271#define MUTABLE_FLAGS(node) \
5272 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5274 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5275 node->base.location.start = part->location.start;
5278 node->base.location.end = MAX(node->base.location.end, part->location.end);
5280 switch (PM_NODE_TYPE(part)) {
5281 case PM_STRING_NODE:
5282 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5284 case PM_INTERPOLATED_STRING_NODE:
5285 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5286 // If the string that we're concatenating is a static literal,
5287 // then we can keep the static literal flag for this string.
5289 // Otherwise, we lose the static literal flag here and we should
5290 // also clear the mutability flags.
5294 case PM_EMBEDDED_STATEMENTS_NODE: {
5295 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5296 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5298 if (embedded == NULL) {
5299 // If we're embedding multiple statements or no statements, then
5300 // the string is not longer a static literal.
5302 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5303 // If the embedded statement is a string, then we can make that
5304 // string as frozen and static literal, and not touch the static
5305 // literal status of this string.
5306 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5308 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5309 MUTABLE_FLAGS(node);
5311 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5312 // If the embedded statement is an interpolated string, but that
5313 // string is marked as static literal, then we can keep our
5314 // static literal status for this string.
5315 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5316 MUTABLE_FLAGS(node);
5319 // In all other cases, we lose the static literal flag here and
5326 case PM_EMBEDDED_VARIABLE_NODE:
5327 // Embedded variables clear static literal, which means we also
5328 // should clear the mutability flags.
5332 assert(false && "unexpected node type");
5336 pm_node_list_append(&node->parts, part);
5345static pm_interpolated_string_node_t *
5346pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5347 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5348 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5350 switch (parser->frozen_string_literal) {
5351 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5352 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5354 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5355 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5359 *node = (pm_interpolated_string_node_t) {
5361 .type = PM_INTERPOLATED_STRING_NODE,
5363 .node_id = PM_NODE_IDENTIFY(parser),
5365 .start = opening->start,
5366 .end = closing->end,
5369 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5370 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5374 if (parts != NULL) {
5376 PM_NODE_LIST_FOREACH(parts, index, part) {
5377 pm_interpolated_string_node_append(node, part);
5388pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5389 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5390 node->base.location.end = closing->end;
5394pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5395 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5396 node->base.location.start = part->location.start;
5399 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5400 node->base.location.end = MAX(node->base.location.end, part->location.end);
5404pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5405 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5406 node->base.location.end = closing->end;
5412static pm_interpolated_symbol_node_t *
5413pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5414 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5416 *node = (pm_interpolated_symbol_node_t) {
5418 .type = PM_INTERPOLATED_SYMBOL_NODE,
5419 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5420 .node_id = PM_NODE_IDENTIFY(parser),
5422 .start = opening->start,
5423 .end = closing->end,
5426 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5427 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5431 if (parts != NULL) {
5433 PM_NODE_LIST_FOREACH(parts, index, part) {
5434 pm_interpolated_symbol_node_append(node, part);
5444static pm_interpolated_x_string_node_t *
5445pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5446 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5448 *node = (pm_interpolated_x_string_node_t) {
5450 .type = PM_INTERPOLATED_X_STRING_NODE,
5451 .node_id = PM_NODE_IDENTIFY(parser),
5453 .start = opening->start,
5457 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5458 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5466pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5467 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5468 node->base.location.end = part->location.end;
5472pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5473 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5474 node->base.location.end = closing->end;
5480static pm_it_local_variable_read_node_t *
5481pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5482 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5484 *node = (pm_it_local_variable_read_node_t) {
5486 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5487 .node_id = PM_NODE_IDENTIFY(parser),
5488 .location = PM_LOCATION_TOKEN_VALUE(name)
5498static pm_it_parameters_node_t *
5499pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5500 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5502 *node = (pm_it_parameters_node_t) {
5504 .type = PM_IT_PARAMETERS_NODE,
5505 .node_id = PM_NODE_IDENTIFY(parser),
5507 .start = opening->start,
5519static pm_keyword_hash_node_t *
5520pm_keyword_hash_node_create(pm_parser_t *parser) {
5521 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5523 *node = (pm_keyword_hash_node_t) {
5525 .type = PM_KEYWORD_HASH_NODE,
5526 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5527 .node_id = PM_NODE_IDENTIFY(parser),
5528 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5540pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5541 // If the element being added is not an AssocNode or does not have a symbol
5542 // key, then we want to turn the SYMBOL_KEYS flag off.
5543 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5544 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5547 pm_node_list_append(&hash->elements, element);
5548 if (hash->base.location.start == NULL) {
5549 hash->base.location.start = element->location.start;
5551 hash->base.location.end = element->location.end;
5557static pm_required_keyword_parameter_node_t *
5558pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5559 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5561 *node = (pm_required_keyword_parameter_node_t) {
5563 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5564 .node_id = PM_NODE_IDENTIFY(parser),
5566 .start = name->start,
5570 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5571 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5580static pm_optional_keyword_parameter_node_t *
5581pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5582 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5584 *node = (pm_optional_keyword_parameter_node_t) {
5586 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5587 .node_id = PM_NODE_IDENTIFY(parser),
5589 .start = name->start,
5590 .end = value->location.end
5593 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5594 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5604static pm_keyword_rest_parameter_node_t *
5605pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5606 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5608 *node = (pm_keyword_rest_parameter_node_t) {
5610 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5611 .node_id = PM_NODE_IDENTIFY(parser),
5613 .start = operator->start,
5614 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5617 .name = pm_parser_optional_constant_id_token(parser, name),
5618 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5619 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5628static pm_lambda_node_t *
5629pm_lambda_node_create(
5630 pm_parser_t *parser,
5631 pm_constant_id_list_t *locals,
5632 const pm_token_t *operator,
5633 const pm_token_t *opening,
5634 const pm_token_t *closing,
5635 pm_node_t *parameters,
5638 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5640 *node = (pm_lambda_node_t) {
5642 .type = PM_LAMBDA_NODE,
5643 .node_id = PM_NODE_IDENTIFY(parser),
5645 .start = operator->start,
5650 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5651 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5652 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5653 .parameters = parameters,
5663static pm_local_variable_and_write_node_t *
5664pm_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) {
5665 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5666 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5667 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5669 *node = (pm_local_variable_and_write_node_t) {
5671 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5672 .node_id = PM_NODE_IDENTIFY(parser),
5674 .start = target->location.start,
5675 .end = value->location.end
5678 .name_loc = target->location,
5679 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5691static pm_local_variable_operator_write_node_t *
5692pm_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) {
5693 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5695 *node = (pm_local_variable_operator_write_node_t) {
5697 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5698 .node_id = PM_NODE_IDENTIFY(parser),
5700 .start = target->location.start,
5701 .end = value->location.end
5704 .name_loc = target->location,
5705 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5708 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5718static pm_local_variable_or_write_node_t *
5719pm_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) {
5720 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5721 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5722 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5724 *node = (pm_local_variable_or_write_node_t) {
5726 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5727 .node_id = PM_NODE_IDENTIFY(parser),
5729 .start = target->location.start,
5730 .end = value->location.end
5733 .name_loc = target->location,
5734 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5746static pm_local_variable_read_node_t *
5747pm_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) {
5748 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5750 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5752 *node = (pm_local_variable_read_node_t) {
5754 .type = PM_LOCAL_VARIABLE_READ_NODE,
5755 .node_id = PM_NODE_IDENTIFY(parser),
5756 .location = PM_LOCATION_TOKEN_VALUE(name)
5768static pm_local_variable_read_node_t *
5769pm_local_variable_read_node_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, false);
5778static pm_local_variable_read_node_t *
5779pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5780 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5781 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5787static pm_local_variable_write_node_t *
5788pm_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) {
5789 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5791 *node = (pm_local_variable_write_node_t) {
5793 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5794 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5795 .node_id = PM_NODE_IDENTIFY(parser),
5797 .start = name_loc->start,
5798 .end = value->location.end
5804 .name_loc = *name_loc,
5805 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5815pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5816 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5824pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5825 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5833pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5834 if (pm_token_is_numbered_parameter(start, end)) {
5835 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5843static pm_local_variable_target_node_t *
5844pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5845 pm_refute_numbered_parameter(parser, location->start, location->end);
5846 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5848 *node = (pm_local_variable_target_node_t) {
5850 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5851 .node_id = PM_NODE_IDENTIFY(parser),
5852 .location = *location
5864static pm_match_predicate_node_t *
5865pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5866 pm_assert_value_expression(parser, value);
5868 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5870 *node = (pm_match_predicate_node_t) {
5872 .type = PM_MATCH_PREDICATE_NODE,
5873 .node_id = PM_NODE_IDENTIFY(parser),
5875 .start = value->location.start,
5876 .end = pattern->location.end
5881 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5890static pm_match_required_node_t *
5891pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5892 pm_assert_value_expression(parser, value);
5894 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5896 *node = (pm_match_required_node_t) {
5898 .type = PM_MATCH_REQUIRED_NODE,
5899 .node_id = PM_NODE_IDENTIFY(parser),
5901 .start = value->location.start,
5902 .end = pattern->location.end
5907 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5916static pm_match_write_node_t *
5917pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5918 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5920 *node = (pm_match_write_node_t) {
5922 .type = PM_MATCH_WRITE_NODE,
5923 .node_id = PM_NODE_IDENTIFY(parser),
5924 .location = call->base.location
5936static pm_module_node_t *
5937pm_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) {
5938 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5940 *node = (pm_module_node_t) {
5942 .type = PM_MODULE_NODE,
5943 .node_id = PM_NODE_IDENTIFY(parser),
5945 .start = module_keyword->start,
5946 .end = end_keyword->end
5949 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5950 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5951 .constant_path = constant_path,
5953 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5954 .name = pm_parser_constant_id_token(parser, name)
5963static pm_multi_target_node_t *
5964pm_multi_target_node_create(pm_parser_t *parser) {
5965 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5967 *node = (pm_multi_target_node_t) {
5969 .type = PM_MULTI_TARGET_NODE,
5970 .node_id = PM_NODE_IDENTIFY(parser),
5971 .location = { .start = NULL, .end = NULL }
5976 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5977 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5987pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5988 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5989 if (node->rest == NULL) {
5990 node->rest = target;
5992 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5993 pm_node_list_append(&node->rights, target);
5995 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5996 if (node->rest == NULL) {
5997 node->rest = target;
5999 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
6000 pm_node_list_append(&node->rights, target);
6002 } else if (node->rest == NULL) {
6003 pm_node_list_append(&node->lefts, target);
6005 pm_node_list_append(&node->rights, target);
6008 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
6009 node->base.location.start = target->location.start;
6012 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6013 node->base.location.end = target->location.end;
6021pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6022 node->base.location.start = lparen->start;
6023 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6030pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6031 node->base.location.end = rparen->end;
6032 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6038static pm_multi_write_node_t *
6039pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6040 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6042 *node = (pm_multi_write_node_t) {
6044 .type = PM_MULTI_WRITE_NODE,
6045 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6046 .node_id = PM_NODE_IDENTIFY(parser),
6048 .start = target->base.location.start,
6049 .end = value->location.end
6052 .lefts = target->lefts,
6053 .rest = target->rest,
6054 .rights = target->rights,
6055 .lparen_loc = target->lparen_loc,
6056 .rparen_loc = target->rparen_loc,
6057 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6061 // Explicitly do not call pm_node_destroy here because we want to keep
6062 // around all of the information within the MultiWriteNode node.
6071static pm_next_node_t *
6072pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6073 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6074 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6076 *node = (pm_next_node_t) {
6078 .type = PM_NEXT_NODE,
6079 .node_id = PM_NODE_IDENTIFY(parser),
6081 .start = keyword->start,
6082 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6085 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6086 .arguments = arguments
6095static pm_nil_node_t *
6096pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6097 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6098 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6100 *node = (pm_nil_node_t) {{
6101 .type = PM_NIL_NODE,
6102 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6103 .node_id = PM_NODE_IDENTIFY(parser),
6104 .location = PM_LOCATION_TOKEN_VALUE(token)
6113static pm_no_keywords_parameter_node_t *
6114pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6115 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6116 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6117 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6119 *node = (pm_no_keywords_parameter_node_t) {
6121 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6122 .node_id = PM_NODE_IDENTIFY(parser),
6124 .start = operator->start,
6128 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6129 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6138static pm_numbered_parameters_node_t *
6139pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6140 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6142 *node = (pm_numbered_parameters_node_t) {
6144 .type = PM_NUMBERED_PARAMETERS_NODE,
6145 .node_id = PM_NODE_IDENTIFY(parser),
6146 .location = *location
6158#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6167pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6168 const uint8_t *start = token->start + 1;
6169 const uint8_t *end = token->end;
6171 ptrdiff_t diff = end - start;
6173#if PTRDIFF_MAX > SIZE_MAX
6174 assert(diff < (ptrdiff_t) SIZE_MAX);
6176 size_t length = (size_t) diff;
6178 char *digits = xcalloc(length + 1, sizeof(char));
6179 memcpy(digits, start, length);
6180 digits[length] = '\0';
6184 unsigned long value = strtoul(digits, &endptr, 10);
6186 if ((digits == endptr) || (*endptr != '\0')) {
6187 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6193 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6194 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6198 return (uint32_t) value;
6206static pm_numbered_reference_read_node_t *
6207pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6208 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6209 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6211 *node = (pm_numbered_reference_read_node_t) {
6213 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6214 .node_id = PM_NODE_IDENTIFY(parser),
6215 .location = PM_LOCATION_TOKEN_VALUE(name),
6217 .number = pm_numbered_reference_read_node_number(parser, name)
6226static pm_optional_parameter_node_t *
6227pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6228 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6230 *node = (pm_optional_parameter_node_t) {
6232 .type = PM_OPTIONAL_PARAMETER_NODE,
6233 .node_id = PM_NODE_IDENTIFY(parser),
6235 .start = name->start,
6236 .end = value->location.end
6239 .name = pm_parser_constant_id_token(parser, name),
6240 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6241 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6251static pm_or_node_t *
6252pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6253 pm_assert_value_expression(parser, left);
6255 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6257 *node = (pm_or_node_t) {
6260 .node_id = PM_NODE_IDENTIFY(parser),
6262 .start = left->location.start,
6263 .end = right->location.end
6268 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6277static pm_parameters_node_t *
6278pm_parameters_node_create(pm_parser_t *parser) {
6279 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6281 *node = (pm_parameters_node_t) {
6283 .type = PM_PARAMETERS_NODE,
6284 .node_id = PM_NODE_IDENTIFY(parser),
6285 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6288 .keyword_rest = NULL,
6303pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6304 if (params->base.location.start == NULL) {
6305 params->base.location.start = param->location.start;
6307 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6310 if (params->base.location.end == NULL) {
6311 params->base.location.end = param->location.end;
6313 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6321pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6322 pm_parameters_node_location_set(params, param);
6323 pm_node_list_append(¶ms->requireds, param);
6330pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6331 pm_parameters_node_location_set(params, (pm_node_t *) param);
6332 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6339pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6340 pm_parameters_node_location_set(params, param);
6341 pm_node_list_append(¶ms->posts, param);
6348pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6349 pm_parameters_node_location_set(params, param);
6350 params->rest = param;
6357pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6358 pm_parameters_node_location_set(params, param);
6359 pm_node_list_append(¶ms->keywords, param);
6366pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6367 assert(params->keyword_rest == NULL);
6368 pm_parameters_node_location_set(params, param);
6369 params->keyword_rest = param;
6376pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6377 assert(params->block == NULL);
6378 pm_parameters_node_location_set(params, (pm_node_t *) param);
6379 params->block = param;
6385static pm_program_node_t *
6386pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6387 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6389 *node = (pm_program_node_t) {
6391 .type = PM_PROGRAM_NODE,
6392 .node_id = PM_NODE_IDENTIFY(parser),
6394 .start = statements == NULL ? parser->start : statements->base.location.start,
6395 .end = statements == NULL ? parser->end : statements->base.location.end
6399 .statements = statements
6408static pm_parentheses_node_t *
6409pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
6410 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6412 *node = (pm_parentheses_node_t) {
6414 .type = PM_PARENTHESES_NODE,
6415 .node_id = PM_NODE_IDENTIFY(parser),
6417 .start = opening->start,
6422 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6423 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6432static pm_pinned_expression_node_t *
6433pm_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) {
6434 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6436 *node = (pm_pinned_expression_node_t) {
6438 .type = PM_PINNED_EXPRESSION_NODE,
6439 .node_id = PM_NODE_IDENTIFY(parser),
6441 .start = operator->start,
6445 .expression = expression,
6446 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6447 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6448 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6457static pm_pinned_variable_node_t *
6458pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6459 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6461 *node = (pm_pinned_variable_node_t) {
6463 .type = PM_PINNED_VARIABLE_NODE,
6464 .node_id = PM_NODE_IDENTIFY(parser),
6466 .start = operator->start,
6467 .end = variable->location.end
6470 .variable = variable,
6471 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6480static pm_post_execution_node_t *
6481pm_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) {
6482 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6484 *node = (pm_post_execution_node_t) {
6486 .type = PM_POST_EXECUTION_NODE,
6487 .node_id = PM_NODE_IDENTIFY(parser),
6489 .start = keyword->start,
6493 .statements = statements,
6494 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6495 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6496 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6505static pm_pre_execution_node_t *
6506pm_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) {
6507 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6509 *node = (pm_pre_execution_node_t) {
6511 .type = PM_PRE_EXECUTION_NODE,
6512 .node_id = PM_NODE_IDENTIFY(parser),
6514 .start = keyword->start,
6518 .statements = statements,
6519 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6520 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6521 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6530static pm_range_node_t *
6531pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6532 pm_assert_value_expression(parser, left);
6533 pm_assert_value_expression(parser, right);
6535 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6536 pm_node_flags_t flags = 0;
6538 // Indicate that this node is an exclusive range if the operator is `...`.
6539 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6540 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6543 // Indicate that this node is a static literal (i.e., can be compiled with
6544 // a putobject in CRuby) if the left and right are implicit nil, explicit
6545 // nil, or integers.
6547 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6548 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6550 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6553 *node = (pm_range_node_t) {
6555 .type = PM_RANGE_NODE,
6557 .node_id = PM_NODE_IDENTIFY(parser),
6559 .start = (left == NULL ? operator->start : left->location.start),
6560 .end = (right == NULL ? operator->end : right->location.end)
6565 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6574static pm_redo_node_t *
6575pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6576 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6577 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6579 *node = (pm_redo_node_t) {{
6580 .type = PM_REDO_NODE,
6581 .node_id = PM_NODE_IDENTIFY(parser),
6582 .location = PM_LOCATION_TOKEN_VALUE(token)
6592static pm_regular_expression_node_t *
6593pm_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) {
6594 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6596 *node = (pm_regular_expression_node_t) {
6598 .type = PM_REGULAR_EXPRESSION_NODE,
6599 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6600 .node_id = PM_NODE_IDENTIFY(parser),
6602 .start = MIN(opening->start, closing->start),
6603 .end = MAX(opening->end, closing->end)
6606 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6607 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6608 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6609 .unescaped = *unescaped
6618static inline pm_regular_expression_node_t *
6619pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6620 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6626static pm_required_parameter_node_t *
6627pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6628 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6630 *node = (pm_required_parameter_node_t) {
6632 .type = PM_REQUIRED_PARAMETER_NODE,
6633 .node_id = PM_NODE_IDENTIFY(parser),
6634 .location = PM_LOCATION_TOKEN_VALUE(token)
6636 .name = pm_parser_constant_id_token(parser, token)
6645static pm_rescue_modifier_node_t *
6646pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6647 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6649 *node = (pm_rescue_modifier_node_t) {
6651 .type = PM_RESCUE_MODIFIER_NODE,
6652 .node_id = PM_NODE_IDENTIFY(parser),
6654 .start = expression->location.start,
6655 .end = rescue_expression->location.end
6658 .expression = expression,
6659 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6660 .rescue_expression = rescue_expression
6669static pm_rescue_node_t *
6670pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6671 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6673 *node = (pm_rescue_node_t) {
6675 .type = PM_RESCUE_NODE,
6676 .node_id = PM_NODE_IDENTIFY(parser),
6677 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6679 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6680 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6691pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6692 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6699pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6700 node->reference = reference;
6701 node->base.location.end = reference->location.end;
6708pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6709 node->statements = statements;
6710 if (pm_statements_node_body_length(statements) > 0) {
6711 node->base.location.end = statements->base.location.end;
6719pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6720 node->subsequent = subsequent;
6721 node->base.location.end = subsequent->base.location.end;
6728pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6729 pm_node_list_append(&node->exceptions, exception);
6730 node->base.location.end = exception->location.end;
6736static pm_rest_parameter_node_t *
6737pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6738 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6740 *node = (pm_rest_parameter_node_t) {
6742 .type = PM_REST_PARAMETER_NODE,
6743 .node_id = PM_NODE_IDENTIFY(parser),
6745 .start = operator->start,
6746 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6749 .name = pm_parser_optional_constant_id_token(parser, name),
6750 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6751 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6760static pm_retry_node_t *
6761pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6762 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6763 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6765 *node = (pm_retry_node_t) {{
6766 .type = PM_RETRY_NODE,
6767 .node_id = PM_NODE_IDENTIFY(parser),
6768 .location = PM_LOCATION_TOKEN_VALUE(token)
6777static pm_return_node_t *
6778pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6779 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6781 *node = (pm_return_node_t) {
6783 .type = PM_RETURN_NODE,
6784 .node_id = PM_NODE_IDENTIFY(parser),
6786 .start = keyword->start,
6787 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6790 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6791 .arguments = arguments
6800static pm_self_node_t *
6801pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6802 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6803 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6805 *node = (pm_self_node_t) {{
6806 .type = PM_SELF_NODE,
6807 .node_id = PM_NODE_IDENTIFY(parser),
6808 .location = PM_LOCATION_TOKEN_VALUE(token)
6817static pm_shareable_constant_node_t *
6818pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6819 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6821 *node = (pm_shareable_constant_node_t) {
6823 .type = PM_SHAREABLE_CONSTANT_NODE,
6824 .flags = (pm_node_flags_t) value,
6825 .node_id = PM_NODE_IDENTIFY(parser),
6826 .location = PM_LOCATION_NODE_VALUE(write)
6837static pm_singleton_class_node_t *
6838pm_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) {
6839 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6841 *node = (pm_singleton_class_node_t) {
6843 .type = PM_SINGLETON_CLASS_NODE,
6844 .node_id = PM_NODE_IDENTIFY(parser),
6846 .start = class_keyword->start,
6847 .end = end_keyword->end
6851 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6852 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6853 .expression = expression,
6855 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6864static pm_source_encoding_node_t *
6865pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6866 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6867 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6869 *node = (pm_source_encoding_node_t) {{
6870 .type = PM_SOURCE_ENCODING_NODE,
6871 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6872 .node_id = PM_NODE_IDENTIFY(parser),
6873 .location = PM_LOCATION_TOKEN_VALUE(token)
6882static pm_source_file_node_t*
6883pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6884 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6885 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6887 pm_node_flags_t flags = 0;
6889 switch (parser->frozen_string_literal) {
6890 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6891 flags |= PM_STRING_FLAGS_MUTABLE;
6893 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6894 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6898 *node = (pm_source_file_node_t) {
6900 .type = PM_SOURCE_FILE_NODE,
6902 .node_id = PM_NODE_IDENTIFY(parser),
6903 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6905 .filepath = parser->filepath
6914static pm_source_line_node_t *
6915pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6916 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6917 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6919 *node = (pm_source_line_node_t) {{
6920 .type = PM_SOURCE_LINE_NODE,
6921 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6922 .node_id = PM_NODE_IDENTIFY(parser),
6923 .location = PM_LOCATION_TOKEN_VALUE(token)
6932static pm_splat_node_t *
6933pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6934 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6936 *node = (pm_splat_node_t) {
6938 .type = PM_SPLAT_NODE,
6939 .node_id = PM_NODE_IDENTIFY(parser),
6941 .start = operator->start,
6942 .end = (expression == NULL ? operator->end : expression->location.end)
6945 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6946 .expression = expression
6955static pm_statements_node_t *
6956pm_statements_node_create(pm_parser_t *parser) {
6957 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6959 *node = (pm_statements_node_t) {
6961 .type = PM_STATEMENTS_NODE,
6962 .node_id = PM_NODE_IDENTIFY(parser),
6963 .location = PM_LOCATION_NULL_VALUE(parser)
6975pm_statements_node_body_length(pm_statements_node_t *node) {
6976 return node && node->body.size;
6983pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6984 node->base.location = (pm_location_t) { .start = start, .end = end };
6992pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6993 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6994 node->base.location.start = statement->location.start;
6997 if (statement->location.end > node->base.location.end) {
6998 node->base.location.end = statement->location.end;
7006pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
7007 pm_statements_node_body_update(node, statement);
7009 if (node->body.size > 0) {
7010 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
7012 switch (PM_NODE_TYPE(previous)) {
7017 case PM_RETURN_NODE:
7018 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7025 pm_node_list_append(&node->body, statement);
7026 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7033pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7034 pm_statements_node_body_update(node, statement);
7035 pm_node_list_prepend(&node->body, statement);
7036 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7042static inline pm_string_node_t *
7043pm_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) {
7044 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7045 pm_node_flags_t flags = 0;
7047 switch (parser->frozen_string_literal) {
7048 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7049 flags = PM_STRING_FLAGS_MUTABLE;
7051 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7052 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7056 *node = (pm_string_node_t) {
7058 .type = PM_STRING_NODE,
7060 .node_id = PM_NODE_IDENTIFY(parser),
7062 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7063 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7066 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7067 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7068 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7069 .unescaped = *string
7078static pm_string_node_t *
7079pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7080 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7087static pm_string_node_t *
7088pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7089 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7090 parser->current_string = PM_STRING_EMPTY;
7097static pm_super_node_t *
7098pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7099 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7100 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7102 const uint8_t *end = pm_arguments_end(arguments);
7104 assert(false && "unreachable");
7107 *node = (pm_super_node_t) {
7109 .type = PM_SUPER_NODE,
7110 .node_id = PM_NODE_IDENTIFY(parser),
7112 .start = keyword->start,
7116 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7117 .lparen_loc = arguments->opening_loc,
7118 .arguments = arguments->arguments,
7119 .rparen_loc = arguments->closing_loc,
7120 .block = arguments->block
7131pm_ascii_only_p(const pm_string_t *contents) {
7132 const size_t length = pm_string_length(contents);
7133 const uint8_t *source = pm_string_source(contents);
7135 for (size_t index = 0; index < length; index++) {
7136 if (source[index] & 0x80) return false;
7146parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7147 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7148 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7151 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7164parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7165 const pm_encoding_t *encoding = parser->encoding;
7167 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7168 size_t width = encoding->char_width(cursor, end - cursor);
7171 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7188static inline pm_node_flags_t
7189parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7190 if (parser->explicit_encoding != NULL) {
7191 // A Symbol may optionally have its encoding explicitly set. This will
7192 // happen if an escape sequence results in a non-ASCII code point.
7193 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7194 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7195 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7196 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7197 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7198 } else if (validate) {
7199 parse_symbol_encoding_validate_other(parser, location, contents);
7201 } else if (pm_ascii_only_p(contents)) {
7202 // Ruby stipulates that all source files must use an ASCII-compatible
7203 // encoding. Thus, all symbols appearing in source are eligible for
7204 // "downgrading" to US-ASCII.
7205 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7206 } else if (validate) {
7207 parse_symbol_encoding_validate_other(parser, location, contents);
7213static pm_node_flags_t
7214parse_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) {
7215 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7216 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7217 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7218 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7220 // There's special validation logic used if a string does not contain any character escape sequences.
7221 if (parser->explicit_encoding == NULL) {
7222 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7223 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7224 // the US-ASCII encoding.
7226 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7229 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7231 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7233 } else if (parser->encoding != modifier_encoding) {
7234 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7236 if (modifier == 'n' && !ascii_only) {
7237 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));
7244 // 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.
7245 bool mixed_encoding = false;
7247 if (mixed_encoding) {
7248 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7249 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7250 // 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.
7251 bool valid_string_in_modifier_encoding = true;
7253 if (!valid_string_in_modifier_encoding) {
7254 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7256 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7257 // 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.
7258 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7259 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));
7263 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7273static pm_node_flags_t
7274parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7275 // 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.
7276 bool valid_unicode_range = true;
7277 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7278 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));
7282 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7283 // to multi-byte characters are allowed.
7284 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7285 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7286 // following error message appearing twice. We do the same for compatibility.
7287 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7298 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7299 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7302 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7303 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7306 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7307 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7310 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7311 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7314 // At this point no encoding modifiers will be present on the regular expression as they would have already
7315 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7316 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7318 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7321 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7322 // or by specifying a modifier.
7324 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7325 if (parser->explicit_encoding != NULL) {
7326 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7327 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7328 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7329 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7340static pm_symbol_node_t *
7341pm_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) {
7342 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7344 *node = (pm_symbol_node_t) {
7346 .type = PM_SYMBOL_NODE,
7347 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7348 .node_id = PM_NODE_IDENTIFY(parser),
7350 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7351 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7354 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7355 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7356 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7357 .unescaped = *unescaped
7366static inline pm_symbol_node_t *
7367pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7368 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7374static pm_symbol_node_t *
7375pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7376 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));
7377 parser->current_string = PM_STRING_EMPTY;
7384static pm_symbol_node_t *
7385pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7386 pm_symbol_node_t *node;
7388 switch (token->type) {
7389 case PM_TOKEN_LABEL: {
7390 pm_token_t opening = not_provided(parser);
7391 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7393 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7394 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7396 assert((label.end - label.start) >= 0);
7397 pm_string_shared_init(&node->unescaped, label.start, label.end);
7398 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7402 case PM_TOKEN_MISSING: {
7403 pm_token_t opening = not_provided(parser);
7404 pm_token_t closing = not_provided(parser);
7406 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7407 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7411 assert(false && "unreachable");
7422static pm_symbol_node_t *
7423pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7424 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7426 *node = (pm_symbol_node_t) {
7428 .type = PM_SYMBOL_NODE,
7429 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7430 .node_id = PM_NODE_IDENTIFY(parser),
7431 .location = PM_LOCATION_NULL_VALUE(parser)
7433 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7437 pm_string_constant_init(&node->unescaped, content, strlen(content));
7445pm_symbol_node_label_p(pm_node_t *node) {
7446 const uint8_t *end = NULL;
7448 switch (PM_NODE_TYPE(node)) {
7449 case PM_SYMBOL_NODE:
7450 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7452 case PM_INTERPOLATED_SYMBOL_NODE:
7453 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7459 return (end != NULL) && (end[-1] == ':');
7465static pm_symbol_node_t *
7466pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7467 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7469 *new_node = (pm_symbol_node_t) {
7471 .type = PM_SYMBOL_NODE,
7472 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7473 .node_id = PM_NODE_IDENTIFY(parser),
7475 .start = opening->start,
7479 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7480 .value_loc = node->content_loc,
7481 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7482 .unescaped = node->unescaped
7485 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7486 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7488 // We are explicitly _not_ using pm_node_destroy here because we don't want
7489 // to trash the unescaped string. We could instead copy the string if we
7490 // know that it is owned, but we're taking the fast path for now.
7499static pm_string_node_t *
7500pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7501 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7502 pm_node_flags_t flags = 0;
7504 switch (parser->frozen_string_literal) {
7505 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7506 flags = PM_STRING_FLAGS_MUTABLE;
7508 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7509 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7513 *new_node = (pm_string_node_t) {
7515 .type = PM_STRING_NODE,
7517 .node_id = PM_NODE_IDENTIFY(parser),
7518 .location = node->base.location
7520 .opening_loc = node->opening_loc,
7521 .content_loc = node->value_loc,
7522 .closing_loc = node->closing_loc,
7523 .unescaped = node->unescaped
7526 // We are explicitly _not_ using pm_node_destroy here because we don't want
7527 // to trash the unescaped string. We could instead copy the string if we
7528 // know that it is owned, but we're taking the fast path for now.
7537static pm_true_node_t *
7538pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7539 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7540 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7542 *node = (pm_true_node_t) {{
7543 .type = PM_TRUE_NODE,
7544 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7545 .node_id = PM_NODE_IDENTIFY(parser),
7546 .location = PM_LOCATION_TOKEN_VALUE(token)
7555static pm_true_node_t *
7556pm_true_node_synthesized_create(pm_parser_t *parser) {
7557 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7559 *node = (pm_true_node_t) {{
7560 .type = PM_TRUE_NODE,
7561 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7562 .node_id = PM_NODE_IDENTIFY(parser),
7563 .location = { .start = parser->start, .end = parser->end }
7572static pm_undef_node_t *
7573pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7574 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7575 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7577 *node = (pm_undef_node_t) {
7579 .type = PM_UNDEF_NODE,
7580 .node_id = PM_NODE_IDENTIFY(parser),
7581 .location = PM_LOCATION_TOKEN_VALUE(token),
7583 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7594pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7595 node->base.location.end = name->location.end;
7596 pm_node_list_append(&node->names, name);
7602static pm_unless_node_t *
7603pm_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) {
7604 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7605 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7608 if (statements != NULL) {
7609 end = statements->base.location.end;
7611 end = predicate->location.end;
7614 *node = (pm_unless_node_t) {
7616 .type = PM_UNLESS_NODE,
7617 .flags = PM_NODE_FLAG_NEWLINE,
7618 .node_id = PM_NODE_IDENTIFY(parser),
7620 .start = keyword->start,
7624 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7625 .predicate = predicate,
7626 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7627 .statements = statements,
7628 .else_clause = NULL,
7629 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7638static pm_unless_node_t *
7639pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7640 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7641 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7643 pm_statements_node_t *statements = pm_statements_node_create(parser);
7644 pm_statements_node_body_append(parser, statements, statement, true);
7646 *node = (pm_unless_node_t) {
7648 .type = PM_UNLESS_NODE,
7649 .flags = PM_NODE_FLAG_NEWLINE,
7650 .node_id = PM_NODE_IDENTIFY(parser),
7652 .start = statement->location.start,
7653 .end = predicate->location.end
7656 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7657 .predicate = predicate,
7658 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7659 .statements = statements,
7660 .else_clause = NULL,
7661 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7668pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7669 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7670 node->base.location.end = end_keyword->end;
7679pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7680 assert(parser->current_block_exits != NULL);
7682 // All of the block exits that we want to remove should be within the
7683 // statements, and since we are modifying the statements, we shouldn't have
7684 // to check the end location.
7685 const uint8_t *start = statements->base.location.start;
7687 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7688 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7689 if (block_exit->location.start < start) break;
7691 // Implicitly remove from the list by lowering the size.
7692 parser->current_block_exits->size--;
7699static pm_until_node_t *
7700pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
7701 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7702 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7704 *node = (pm_until_node_t) {
7706 .type = PM_UNTIL_NODE,
7708 .node_id = PM_NODE_IDENTIFY(parser),
7710 .start = keyword->start,
7711 .end = closing->end,
7714 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7715 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7716 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7717 .predicate = predicate,
7718 .statements = statements
7727static pm_until_node_t *
7728pm_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) {
7729 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7730 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7731 pm_loop_modifier_block_exits(parser, statements);
7733 *node = (pm_until_node_t) {
7735 .type = PM_UNTIL_NODE,
7737 .node_id = PM_NODE_IDENTIFY(parser),
7739 .start = statements->base.location.start,
7740 .end = predicate->location.end,
7743 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7744 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7745 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7746 .predicate = predicate,
7747 .statements = statements
7756static pm_when_node_t *
7757pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7758 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7760 *node = (pm_when_node_t) {
7762 .type = PM_WHEN_NODE,
7763 .node_id = PM_NODE_IDENTIFY(parser),
7765 .start = keyword->start,
7769 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7771 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7782pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7783 node->base.location.end = condition->location.end;
7784 pm_node_list_append(&node->conditions, condition);
7791pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7792 node->base.location.end = then_keyword->end;
7793 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7800pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7801 if (statements->base.location.end > node->base.location.end) {
7802 node->base.location.end = statements->base.location.end;
7805 node->statements = statements;
7811static pm_while_node_t *
7812pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
7813 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7814 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7816 *node = (pm_while_node_t) {
7818 .type = PM_WHILE_NODE,
7820 .node_id = PM_NODE_IDENTIFY(parser),
7822 .start = keyword->start,
7826 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7827 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7828 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7829 .predicate = predicate,
7830 .statements = statements
7839static pm_while_node_t *
7840pm_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) {
7841 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7842 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7843 pm_loop_modifier_block_exits(parser, statements);
7845 *node = (pm_while_node_t) {
7847 .type = PM_WHILE_NODE,
7849 .node_id = PM_NODE_IDENTIFY(parser),
7851 .start = statements->base.location.start,
7852 .end = predicate->location.end
7855 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7856 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7857 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7858 .predicate = predicate,
7859 .statements = statements
7868static pm_while_node_t *
7869pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7870 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7872 *node = (pm_while_node_t) {
7874 .type = PM_WHILE_NODE,
7875 .node_id = PM_NODE_IDENTIFY(parser),
7876 .location = PM_LOCATION_NULL_VALUE(parser)
7878 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7879 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7880 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7881 .predicate = predicate,
7882 .statements = statements
7892static pm_x_string_node_t *
7893pm_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) {
7894 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7896 *node = (pm_x_string_node_t) {
7898 .type = PM_X_STRING_NODE,
7899 .flags = PM_STRING_FLAGS_FROZEN,
7900 .node_id = PM_NODE_IDENTIFY(parser),
7902 .start = opening->start,
7906 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7907 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7908 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7909 .unescaped = *unescaped
7918static inline pm_x_string_node_t *
7919pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7920 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7926static pm_yield_node_t *
7927pm_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) {
7928 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7931 if (rparen_loc->start != NULL) {
7932 end = rparen_loc->end;
7933 } else if (arguments != NULL) {
7934 end = arguments->base.location.end;
7935 } else if (lparen_loc->start != NULL) {
7936 end = lparen_loc->end;
7941 *node = (pm_yield_node_t) {
7943 .type = PM_YIELD_NODE,
7944 .node_id = PM_NODE_IDENTIFY(parser),
7946 .start = keyword->start,
7950 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7951 .lparen_loc = *lparen_loc,
7952 .arguments = arguments,
7953 .rparen_loc = *rparen_loc
7960#undef PM_NODE_IDENTIFY
7967pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7968 pm_scope_t *scope = parser->current_scope;
7971 while (scope != NULL) {
7972 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7973 if (scope->closed) break;
7975 scope = scope->previous;
7988pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7989 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7996pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7997 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
8003static pm_constant_id_t
8004pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8005 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
8006 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8013static inline pm_constant_id_t
8014pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8015 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8021static pm_constant_id_t
8022pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8023 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8024 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8031static pm_constant_id_t
8032pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8033 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8034 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8046pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8047 // We want to check whether the parameter name is a numbered parameter or
8049 pm_refute_numbered_parameter(parser, name->start, name->end);
8051 // Otherwise we'll fetch the constant id for the parameter name and check
8052 // whether it's already in the current scope.
8053 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8055 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8056 // Add an error if the parameter doesn't start with _ and has been seen before
8057 if ((name->start < name->end) && (*name->start != '_')) {
8058 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8069pm_parser_scope_pop(pm_parser_t *parser) {
8070 pm_scope_t *scope = parser->current_scope;
8071 parser->current_scope = scope->previous;
8072 pm_locals_free(&scope->locals);
8073 pm_node_list_free(&scope->implicit_parameters);
8077/******************************************************************************/
8079/******************************************************************************/
8085pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8086 *stack = (*stack << 1) | (value & 1);
8093pm_state_stack_pop(pm_state_stack_t *stack) {
8101pm_state_stack_p(const pm_state_stack_t *stack) {
8106pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8107 // Use the negation of the value to prevent stack overflow.
8108 pm_state_stack_push(&parser->accepts_block_stack, !value);
8112pm_accepts_block_stack_pop(pm_parser_t *parser) {
8113 pm_state_stack_pop(&parser->accepts_block_stack);
8117pm_accepts_block_stack_p(pm_parser_t *parser) {
8118 return !pm_state_stack_p(&parser->accepts_block_stack);
8122pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8123 pm_state_stack_push(&parser->do_loop_stack, value);
8127pm_do_loop_stack_pop(pm_parser_t *parser) {
8128 pm_state_stack_pop(&parser->do_loop_stack);
8132pm_do_loop_stack_p(pm_parser_t *parser) {
8133 return pm_state_stack_p(&parser->do_loop_stack);
8136/******************************************************************************/
8137/* Lexer check helpers */
8138/******************************************************************************/
8144static inline uint8_t
8145peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8146 if (cursor < parser->end) {
8158static inline uint8_t
8159peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8160 return peek_at(parser, parser->current.end + offset);
8167static inline uint8_t
8168peek(const pm_parser_t *parser) {
8169 return peek_at(parser, parser->current.end);
8177match(pm_parser_t *parser, uint8_t value) {
8178 if (peek(parser) == value) {
8179 parser->current.end++;
8190match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8191 if (peek_at(parser, cursor) == '\n') {
8194 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8206match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8207 return match_eol_at(parser, parser->current.end + offset);
8216match_eol(pm_parser_t *parser) {
8217 return match_eol_at(parser, parser->current.end);
8223static inline const uint8_t *
8224next_newline(const uint8_t *cursor, ptrdiff_t length) {
8225 assert(length >= 0);
8227 // Note that it's okay for us to use memchr here to look for \n because none
8228 // of the encodings that we support have \n as a component of a multi-byte
8230 return memchr(cursor, '\n', (size_t) length);
8237ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8238 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));
8246parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8247 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8249 if (encoding != NULL) {
8250 if (parser->encoding != encoding) {
8251 parser->encoding = encoding;
8252 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8255 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8267parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8268 const uint8_t *cursor = parser->current.start + 1;
8269 const uint8_t *end = parser->current.end;
8271 bool separator = false;
8273 if (end - cursor <= 6) return;
8274 switch (cursor[6]) {
8275 case 'C': case 'c': cursor += 6; continue;
8276 case 'O': case 'o': cursor += 5; continue;
8277 case 'D': case 'd': cursor += 4; continue;
8278 case 'I': case 'i': cursor += 3; continue;
8279 case 'N': case 'n': cursor += 2; continue;
8280 case 'G': case 'g': cursor += 1; continue;
8287 if (pm_char_is_whitespace(*cursor)) break;
8290 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8296 if (++cursor >= end) return;
8297 } while (pm_char_is_whitespace(*cursor));
8299 if (separator) break;
8300 if (*cursor != '=' && *cursor != ':') return;
8306 const uint8_t *value_start = cursor;
8307 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8309 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8310 // If we were unable to parse the encoding value, then we've got an
8311 // issue because we didn't understand the encoding that the user was
8312 // trying to use. In this case we'll keep using the default encoding but
8313 // add an error to the parser to indicate an unsuccessful parse.
8314 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8319 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8320 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8321 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8322} pm_magic_comment_boolean_value_t;
8328static pm_magic_comment_boolean_value_t
8329parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8330 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8331 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8332 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8333 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8335 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8340pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8341 return b == '\'' || b == '"' || b == ':' || b == ';';
8349static inline const uint8_t *
8350parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8351 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8352 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8371parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8374 const uint8_t *start = parser->
current.start + 1;
8375 const uint8_t *end = parser->
current.end;
8376 if (end - start <= 7)
return false;
8378 const uint8_t *cursor;
8379 bool indicator =
false;
8381 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8384 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8395 while (cursor < end) {
8396 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8398 const uint8_t *key_start = cursor;
8399 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8401 const uint8_t *key_end = cursor;
8402 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8403 if (cursor == end)
break;
8405 if (*cursor ==
':') {
8408 if (!indicator)
return false;
8412 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8413 if (cursor == end)
break;
8415 const uint8_t *value_start;
8416 const uint8_t *value_end;
8418 if (*cursor ==
'"') {
8419 value_start = ++cursor;
8420 for (; cursor < end && *cursor !=
'"'; cursor++) {
8421 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8424 if (*cursor ==
'"') cursor++;
8426 value_start = cursor;
8427 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8432 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8434 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8435 if (cursor != end)
return false;
8441 const size_t key_length = (size_t) (key_end - key_start);
8445 pm_string_shared_init(&key, key_start, key_end);
8447 uint8_t *buffer =
xmalloc(key_length);
8448 if (buffer == NULL)
break;
8450 memcpy(buffer, key_start, key_length);
8451 buffer[dash - key_start] =
'_';
8453 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8454 buffer[dash - key_start] =
'_';
8457 pm_string_owned_init(&key, buffer, key_length);
8462 const uint8_t *key_source = pm_string_source(&key);
8463 uint32_t value_length = (uint32_t) (value_end - value_start);
8469 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8470 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8472 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8476 if (key_length == 11) {
8477 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8478 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8479 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8480 PM_PARSER_WARN_TOKEN_FORMAT(
8483 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8485 (
const char *) key_source,
8487 (
const char *) value_start
8490 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8493 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8498 }
else if (key_length == 21) {
8499 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8502 if (semantic_token_seen) {
8503 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8505 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8506 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8507 PM_PARSER_WARN_TOKEN_FORMAT(
8510 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8512 (
const char *) key_source,
8514 (
const char *) value_start
8517 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8520 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8526 }
else if (key_length == 24) {
8527 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8528 const uint8_t *cursor = parser->
current.start;
8529 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8531 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8532 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8533 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8534 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8535 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8536 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8537 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8538 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8539 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8540 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8542 PM_PARSER_WARN_TOKEN_FORMAT(
8545 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8547 (
const char *) key_source,
8549 (
const char *) value_start
8557 pm_string_free(&key);
8666 while (context_node != NULL) {
8667 if (context_terminator(context_node->
context, token))
return context_node->
context;
8668 context_node = context_node->
prev;
8677 if (context_node == NULL)
return false;
8702 while (context_node != NULL) {
8703 if (context_node->
context == context)
return true;
8704 context_node = context_node->
prev;
8714 while (context_node != NULL) {
8715 switch (context_node->
context) {
8736 context_node = context_node->
prev;
8751 assert(
false &&
"unreachable");
8808 assert(
false &&
"unreachable");
8817pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8818 if (invalid != NULL) {
8819 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8820 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8825pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8826 const uint8_t *invalid = NULL;
8827 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8828 pm_strspn_number_validate(parser,
string, length, invalid);
8833pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8834 const uint8_t *invalid = NULL;
8835 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8836 pm_strspn_number_validate(parser,
string, length, invalid);
8841pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8842 const uint8_t *invalid = NULL;
8843 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8844 pm_strspn_number_validate(parser,
string, length, invalid);
8849pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8850 const uint8_t *invalid = NULL;
8851 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8852 pm_strspn_number_validate(parser,
string, length, invalid);
8857lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8862 if (peek(parser) ==
'.') {
8863 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8865 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8876 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8877 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8880 if (pm_char_is_decimal_digit(peek(parser))) {
8882 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8884 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8886 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8888 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8901lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8905 if (peek_offset(parser, -1) ==
'0') {
8906 switch (*parser->
current.end) {
8911 if (pm_char_is_decimal_digit(peek(parser))) {
8912 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8915 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8924 if (pm_char_is_binary_digit(peek(parser))) {
8925 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8928 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8938 if (pm_char_is_octal_digit(peek(parser))) {
8939 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8942 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8958 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8966 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8967 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8970 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8978 type = lex_optional_float_suffix(parser, seen_e);
8985 type = lex_optional_float_suffix(parser, seen_e);
8992 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8995 type = lex_optional_float_suffix(parser, seen_e);
9001 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
9002 const uint8_t *fraction_start = parser->
current.end;
9003 const uint8_t *fraction_end = parser->
current.end + 2;
9004 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
9005 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9017 bool seen_e =
false;
9018 type = lex_numeric_prefix(parser, &seen_e);
9020 const uint8_t *end = parser->
current.end;
9024 if (match(parser,
'r')) {
9027 if (match(parser,
'i')) {
9030 }
else if (match(parser,
'i')) {
9034 if (!seen_e && match(parser,
'r')) {
9037 if (match(parser,
'i')) {
9040 }
else if (match(parser,
'i')) {
9045 const uint8_t b = peek(parser);
9046 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9059 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9065 bool allow_multiple =
true;
9067 switch (*parser->
current.end) {
9098 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9101 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9105 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9125 allow_multiple =
false;
9130 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9133 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9134 }
else if (pm_char_is_whitespace(peek(parser))) {
9137 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9143 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9165 if (memcmp(current_start, value, vlen) == 0) {
9168 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9169 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9171 lex_state_set(parser, state);
9172 if (state == PM_LEX_STATE_BEG) {
9176 if ((modifier_type !=
PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9177 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9178 return modifier_type;
9189lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9192 const uint8_t *end = parser->
end;
9193 const uint8_t *current_start = parser->
current.start;
9194 const uint8_t *current_end = parser->
current.end;
9197 if (encoding_changed) {
9198 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
9199 current_end += width;
9202 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
9203 current_end += width;
9206 parser->
current.end = current_end;
9210 width = (size_t) (current_end - current_start);
9212 if (current_end < end) {
9213 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9219 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9220 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9224 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9225 (void) match(parser,
':');
9229 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9238 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,
'=')) {
9245 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9246 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9250 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9251 (void) match(parser,
':');
9256 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9261 if (pm_do_loop_stack_p(parser)) {
9322 if (encoding_changed) {
9352lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9355 if (pound + 1 >= parser->
end) {
9356 parser->
current.end = pound + 1;
9366 if (pound + 2 >= parser->
end) {
9367 parser->
current.end = pound + 1;
9373 const uint8_t *variable = pound + 2;
9374 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9376 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
9380 if (pound > parser->
current.start) {
9387 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9388 parser->
current.end = pound + 1;
9395 parser->
current.end = pound + 1;
9401 if (pound + 2 >= parser->
end) {
9402 parser->
current.end = pound + 1;
9409 const uint8_t *check = pound + 2;
9411 if (pound[2] ==
'-') {
9412 if (pound + 3 >= parser->
end) {
9413 parser->
current.end = pound + 2;
9425 char_is_identifier_start(parser, check, parser->
end - check) ||
9426 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9431 if (pound > parser->
current.start) {
9438 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9439 parser->
current.end = pound + 1;
9445 parser->
current.end = pound + 1;
9451 if (pound > parser->
current.start) {
9460 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9461 parser->
current.end = pound + 2;
9463 pm_do_loop_stack_push(parser,
false);
9469 parser->
current.end = pound + 1;
9474static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9475static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9476static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9477static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9478static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9483static const bool ascii_printable_chars[] = {
9484 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9485 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9486 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9487 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9488 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9489 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9490 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9491 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9495char_is_ascii_printable(
const uint8_t b) {
9496 return (b < 0x80) && ascii_printable_chars[b];
9503static inline uint8_t
9504escape_hexadecimal_digit(
const uint8_t value) {
9505 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9513static inline uint32_t
9514escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9516 for (
size_t index = 0; index < length; index++) {
9517 if (index != 0) value <<= 4;
9518 value |= escape_hexadecimal_digit(
string[index]);
9523 if (value >= 0xD800 && value <= 0xDFFF) {
9524 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9534static inline uint8_t
9535escape_byte(uint8_t value,
const uint8_t flags) {
9536 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9537 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9545escape_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) {
9549 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9557 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9558 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9559 pm_buffer_append_byte(buffer, 0xEF);
9560 pm_buffer_append_byte(buffer, 0xBF);
9561 pm_buffer_append_byte(buffer, 0xBD);
9573 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9579 pm_buffer_append_byte(buffer,
byte);
9599 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9600 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9603 escape_write_byte_encoded(parser, buffer,
byte);
9615 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9619 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
9620 }
else if (width > 1) {
9622 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9623 pm_buffer_append_bytes(b, parser->
current.end, width);
9629 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9639escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9640#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9642 PM_PARSER_WARN_TOKEN_FORMAT(
9645 PM_WARN_INVALID_CHARACTER,
9659 uint8_t peeked = peek(parser);
9663 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9668 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9673 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9678 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9683 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9688 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9693 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9698 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9703 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9708 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9713 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9716 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9717 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9720 if (pm_char_is_octal_digit(peek(parser))) {
9721 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9724 if (pm_char_is_octal_digit(peek(parser))) {
9725 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9730 value = escape_byte(value, flags);
9731 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9735 const uint8_t *start = parser->
current.end - 1;
9738 uint8_t
byte = peek(parser);
9740 if (pm_char_is_hexadecimal_digit(
byte)) {
9741 uint8_t value = escape_hexadecimal_digit(
byte);
9744 byte = peek(parser);
9745 if (pm_char_is_hexadecimal_digit(
byte)) {
9746 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9750 value = escape_byte(value, flags);
9751 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9752 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9753 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9755 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9759 escape_write_byte_encoded(parser, buffer, value);
9761 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9767 const uint8_t *start = parser->
current.end - 1;
9771 const uint8_t *start = parser->
current.end - 2;
9772 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9773 }
else if (peek(parser) ==
'{') {
9774 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9779 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9780 parser->
current.end += whitespace;
9781 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9792 const uint8_t *extra_codepoints_start = NULL;
9793 int codepoints_count = 0;
9796 const uint8_t *unicode_start = parser->
current.end;
9797 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9799 if (hexadecimal_length > 6) {
9801 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9802 }
else if (hexadecimal_length == 0) {
9805 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9809 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9811 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9812 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9818 parser->
current.end += hexadecimal_length;
9820 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9821 extra_codepoints_start = unicode_start;
9824 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9825 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9832 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9833 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9837 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9838 }
else if (peek(parser) ==
'}') {
9841 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9845 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9847 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9851 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9852 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9855 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9858 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9859 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9861 const uint8_t *start = parser->
current.end - 2;
9862 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9864 }
else if (length == 4) {
9865 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9867 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9868 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9871 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9874 parser->
current.end += length;
9876 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9880 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9882 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9891 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9892 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9896 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9900 uint8_t peeked = peek(parser);
9904 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9910 if (match(parser,
'u') || match(parser,
'U')) {
9911 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9915 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9919 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9920 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9924 escape_read_warn(parser, flags, 0,
"\\t");
9925 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9928 if (!char_is_ascii_printable(peeked)) {
9929 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9934 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9941 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9942 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9945 if (peek(parser) !=
'-') {
9947 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9953 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9957 uint8_t peeked = peek(parser);
9961 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9967 if (match(parser,
'u') || match(parser,
'U')) {
9968 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9972 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9976 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9977 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9981 escape_read_warn(parser, flags, 0,
"\\t");
9982 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9985 if (!char_is_ascii_printable(peeked)) {
9987 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9992 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9999 if (flags & PM_ESCAPE_FLAG_META) {
10000 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
10003 if (peek(parser) !=
'-') {
10005 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10011 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10015 uint8_t peeked = peek(parser);
10020 if (match(parser,
'u') || match(parser,
'U')) {
10021 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10025 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10029 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10030 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10034 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10035 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10038 if (!char_is_ascii_printable(peeked)) {
10040 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10045 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10050 if (peek_offset(parser, 1) ==
'\n') {
10052 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10058 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
10060 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10064 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
10066 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10100 if (lex_state_end_p(parser)) {
10101 lex_state_set(parser, PM_LEX_STATE_BEG);
10106 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10111 if (pm_char_is_whitespace(*parser->
current.end)) {
10112 lex_state_set(parser, PM_LEX_STATE_BEG);
10116 lex_state_set(parser, PM_LEX_STATE_BEG);
10118 if (match(parser,
'\\')) {
10119 lex_state_set(parser, PM_LEX_STATE_END);
10122 pm_buffer_init_capacity(&buffer, 3);
10124 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10136 (parser->
current.end + encoding_width >= parser->
end) ||
10137 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
10140 lex_state_set(parser, PM_LEX_STATE_END);
10141 parser->
current.end += encoding_width;
10157 const uint8_t *end = parser->
end;
10160 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10161 parser->
current.end += width;
10163 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10164 parser->
current.end += width;
10166 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
10173 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10176 pm_parser_err_token(parser, &parser->
current, diag_id);
10182 lex_mode_pop(parser);
10204 if (comment == NULL)
return NULL;
10222 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10224 if (newline == NULL) {
10227 pm_newline_list_append(&parser->
newline_list, newline);
10228 parser->
current.end = newline + 1;
10232 parser_lex_callback(parser);
10235 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10240 while (parser->
current.end + 4 <= parser->
end) {
10246 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10249 pm_char_is_whitespace(parser->
current.end[4]) ||
10250 (parser->
current.end[4] ==
'\0') ||
10251 (parser->
current.end[4] ==
'\004') ||
10252 (parser->
current.end[4] ==
'\032')
10255 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10257 if (newline == NULL) {
10260 pm_newline_list_append(&parser->
newline_list, newline);
10261 parser->
current.end = newline + 1;
10265 parser_lex_callback(parser);
10275 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10277 if (newline == NULL) {
10280 pm_newline_list_append(&parser->
newline_list, newline);
10281 parser->
current.end = newline + 1;
10285 parser_lex_callback(parser);
10288 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10304 parser_lex_callback(parser);
10328 const uint8_t *cursor = parser->
current.end;
10330 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10331 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10394 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10405static inline size_t
10411 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10416 return (width == 0 ? 1 : width);
10424 size_t width = parser_char_width(parser);
10425 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10426 parser->
current.end += width;
10431 size_t width = parser_char_width(parser);
10432 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10434 parser->
current.end += width;
10438pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10439 for (
size_t index = 0; index < length; index++) {
10440 if (value[index] & 0x80)
return false;
10454 pm_string_owned_init(&parser->
current_string, (uint8_t *) pm_buffer_value(&token_buffer->
buffer), pm_buffer_length(&token_buffer->
buffer));
10475 if (token_buffer->
cursor == NULL) {
10478 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10479 pm_token_buffer_copy(parser, token_buffer);
10491 pm_regexp_token_buffer_copy(parser, token_buffer);
10495#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10507 const uint8_t *start;
10508 if (token_buffer->
cursor == NULL) {
10509 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10510 start = parser->
current.start;
10512 start = token_buffer->
cursor;
10515 const uint8_t *end = parser->
current.end - 1;
10516 assert(end >= start);
10517 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10519 token_buffer->
cursor = end;
10524 const uint8_t *start;
10526 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10527 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10528 start = parser->
current.start;
10533 const uint8_t *end = parser->
current.end - 1;
10534 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10535 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10540#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10546static inline size_t
10548 size_t whitespace = 0;
10551 case PM_HEREDOC_INDENT_NONE:
10556 case PM_HEREDOC_INDENT_DASH:
10558 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10560 case PM_HEREDOC_INDENT_TILDE:
10563 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10564 if (**cursor ==
'\t') {
10565 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10584 size_t eol_length = match_eol(parser);
10591 parser_flush_heredoc_end(parser);
10597 uint8_t delimiter = *parser->
current.end;
10601 if (eol_length == 2) {
10602 delimiter = *(parser->
current.end + 1);
10605 parser->
current.end += eol_length;
10609 return *parser->
current.end++;
10616#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10635 bool lexed_comment =
false;
10643 case PM_LEX_DEFAULT:
10644 case PM_LEX_EMBEXPR:
10645 case PM_LEX_EMBVAR:
10661 bool space_seen =
false;
10665 bool chomping =
true;
10666 while (parser->
current.end < parser->
end && chomping) {
10667 switch (*parser->
current.end) {
10676 if (match_eol_offset(parser, 1)) {
10679 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10685 size_t eol_length = match_eol_offset(parser, 1);
10691 parser->
current.end += eol_length + 1;
10695 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10728 switch (*parser->
current.end++) {
10736 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10737 parser->
current.end = ending == NULL ? parser->
end : ending;
10742 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10745 if (ending) parser->
current.end++;
10747 parser_lex_callback(parser);
10759 parser_lex_magic_comment_encoding(parser);
10763 lexed_comment =
true;
10769 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10781 if (!lexed_comment) {
10782 parser->
current.end += eol_length - 1;
10791 parser_flush_heredoc_end(parser);
10796 switch (lex_state_ignored_p(parser)) {
10797 case PM_IGNORED_NEWLINE_NONE:
10799 case PM_IGNORED_NEWLINE_PATTERN:
10801 if (!lexed_comment) parser_lex_ignored_newline(parser);
10802 lex_state_set(parser, PM_LEX_STATE_BEG);
10808 case PM_IGNORED_NEWLINE_ALL:
10809 if (!lexed_comment) parser_lex_ignored_newline(parser);
10810 lexed_comment =
false;
10811 goto lex_next_token;
10819 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10821 if (next_content < parser->end) {
10827 if (next_content[0] ==
'#') {
10829 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10831 while (following && (following + 1 < parser->
end)) {
10833 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10837 if (peek_at(parser, following) !=
'#')
break;
10841 following = next_newline(following, parser->
end - following);
10847 lex_state_ignored_p(parser) ||
10849 (peek_at(parser, following) ==
'.') ||
10850 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10853 if (!lexed_comment) parser_lex_ignored_newline(parser);
10854 lexed_comment =
false;
10855 goto lex_next_token;
10861 if (next_content[0] ==
'.') {
10865 if (peek_at(parser, next_content + 1) ==
'.') {
10866 if (!lexed_comment) parser_lex_ignored_newline(parser);
10867 lex_state_set(parser, PM_LEX_STATE_BEG);
10873 if (!lexed_comment) parser_lex_ignored_newline(parser);
10874 lex_state_set(parser, PM_LEX_STATE_DOT);
10875 parser->
current.start = next_content;
10876 parser->
current.end = next_content + 1;
10883 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10884 if (!lexed_comment) parser_lex_ignored_newline(parser);
10885 lex_state_set(parser, PM_LEX_STATE_DOT);
10886 parser->
current.start = next_content;
10887 parser->
current.end = next_content + 2;
10895 lex_state_set(parser, PM_LEX_STATE_BEG);
10898 if (!lexed_comment) parser_lex_callback(parser);
10908 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10915 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10920 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10921 pm_do_loop_stack_push(parser,
false);
10928 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10929 pm_do_loop_stack_pop(parser);
10934 lex_state_set(parser, PM_LEX_STATE_BEG);
10943 if (lex_state_operator_p(parser)) {
10944 if (match(parser,
']')) {
10946 lex_state_set(parser, PM_LEX_STATE_ARG);
10950 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10954 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10958 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10959 pm_do_loop_stack_push(parser,
false);
10965 lex_state_set(parser, PM_LEX_STATE_END);
10966 pm_do_loop_stack_pop(parser);
10976 lex_state_set(parser, PM_LEX_STATE_BEG);
10978 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10980 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10981 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10984 lex_state_set(parser, PM_LEX_STATE_BEG);
10985 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10988 lex_state_set(parser, PM_LEX_STATE_BEG);
10991 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10996 pm_do_loop_stack_push(parser,
false);
11004 pm_do_loop_stack_pop(parser);
11007 lex_mode_pop(parser);
11012 lex_state_set(parser, PM_LEX_STATE_END);
11017 if (match(parser,
'*')) {
11018 if (match(parser,
'=')) {
11019 lex_state_set(parser, PM_LEX_STATE_BEG);
11025 if (lex_state_spcarg_p(parser, space_seen)) {
11026 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11028 }
else if (lex_state_beg_p(parser)) {
11030 }
else if (ambiguous_operator_p(parser, space_seen)) {
11031 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11034 if (lex_state_operator_p(parser)) {
11035 lex_state_set(parser, PM_LEX_STATE_ARG);
11037 lex_state_set(parser, PM_LEX_STATE_BEG);
11043 if (match(parser,
'=')) {
11044 lex_state_set(parser, PM_LEX_STATE_BEG);
11050 if (lex_state_spcarg_p(parser, space_seen)) {
11051 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11053 }
else if (lex_state_beg_p(parser)) {
11055 }
else if (ambiguous_operator_p(parser, space_seen)) {
11056 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11059 if (lex_state_operator_p(parser)) {
11060 lex_state_set(parser, PM_LEX_STATE_ARG);
11062 lex_state_set(parser, PM_LEX_STATE_BEG);
11070 if (lex_state_operator_p(parser)) {
11071 lex_state_set(parser, PM_LEX_STATE_ARG);
11072 if (match(parser,
'@')) {
11076 lex_state_set(parser, PM_LEX_STATE_BEG);
11079 if (match(parser,
'=')) {
11083 if (match(parser,
'~')) {
11092 current_token_starts_line(parser) &&
11094 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11095 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11102 goto lex_next_token;
11105 if (lex_state_operator_p(parser)) {
11106 lex_state_set(parser, PM_LEX_STATE_ARG);
11108 lex_state_set(parser, PM_LEX_STATE_BEG);
11111 if (match(parser,
'>')) {
11115 if (match(parser,
'~')) {
11119 if (match(parser,
'=')) {
11127 if (match(parser,
'<')) {
11129 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11130 !lex_state_end_p(parser) &&
11131 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11133 const uint8_t *end = parser->
current.end;
11138 if (match(parser,
'-')) {
11139 indent = PM_HEREDOC_INDENT_DASH;
11141 else if (match(parser,
'~')) {
11142 indent = PM_HEREDOC_INDENT_TILDE;
11145 if (match(parser,
'`')) {
11146 quote = PM_HEREDOC_QUOTE_BACKTICK;
11148 else if (match(parser,
'"')) {
11149 quote = PM_HEREDOC_QUOTE_DOUBLE;
11151 else if (match(parser,
'\'')) {
11152 quote = PM_HEREDOC_QUOTE_SINGLE;
11155 const uint8_t *ident_start = parser->
current.end;
11160 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
11163 if (quote == PM_HEREDOC_QUOTE_NONE) {
11164 parser->
current.end += width;
11166 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
11167 parser->
current.end += width;
11173 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11178 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11179 bool ident_error =
false;
11181 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11182 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11183 ident_error =
true;
11188 .mode = PM_LEX_HEREDOC,
11191 .ident_start = ident_start,
11192 .ident_length = ident_length,
11196 .next_start = parser->
current.end,
11198 .line_continuation =
false
11203 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11205 if (body_start == NULL) {
11210 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11211 body_start = parser->
end;
11215 pm_newline_list_append(&parser->
newline_list, body_start);
11228 if (match(parser,
'=')) {
11229 lex_state_set(parser, PM_LEX_STATE_BEG);
11233 if (ambiguous_operator_p(parser, space_seen)) {
11234 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11237 if (lex_state_operator_p(parser)) {
11238 lex_state_set(parser, PM_LEX_STATE_ARG);
11240 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11241 lex_state_set(parser, PM_LEX_STATE_BEG);
11247 if (lex_state_operator_p(parser)) {
11248 lex_state_set(parser, PM_LEX_STATE_ARG);
11250 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11251 lex_state_set(parser, PM_LEX_STATE_BEG);
11254 if (match(parser,
'=')) {
11255 if (match(parser,
'>')) {
11266 if (match(parser,
'>')) {
11267 if (lex_state_operator_p(parser)) {
11268 lex_state_set(parser, PM_LEX_STATE_ARG);
11270 lex_state_set(parser, PM_LEX_STATE_BEG);
11275 if (lex_state_operator_p(parser)) {
11276 lex_state_set(parser, PM_LEX_STATE_ARG);
11278 lex_state_set(parser, PM_LEX_STATE_BEG);
11285 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11286 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11292 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11293 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11297 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11298 if (previous_command_start) {
11299 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11301 lex_state_set(parser, PM_LEX_STATE_ARG);
11307 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11313 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11314 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11320 LEX(lex_question_mark(parser));
11324 if (match(parser,
'&')) {
11325 lex_state_set(parser, PM_LEX_STATE_BEG);
11327 if (match(parser,
'=')) {
11334 if (match(parser,
'=')) {
11335 lex_state_set(parser, PM_LEX_STATE_BEG);
11339 if (match(parser,
'.')) {
11340 lex_state_set(parser, PM_LEX_STATE_DOT);
11345 if (lex_state_spcarg_p(parser, space_seen)) {
11346 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11347 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11349 const uint8_t delim = peek_offset(parser, 1);
11351 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
11352 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11357 }
else if (lex_state_beg_p(parser)) {
11359 }
else if (ambiguous_operator_p(parser, space_seen)) {
11360 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11363 if (lex_state_operator_p(parser)) {
11364 lex_state_set(parser, PM_LEX_STATE_ARG);
11366 lex_state_set(parser, PM_LEX_STATE_BEG);
11374 if (match(parser,
'|')) {
11375 if (match(parser,
'=')) {
11376 lex_state_set(parser, PM_LEX_STATE_BEG);
11380 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11385 lex_state_set(parser, PM_LEX_STATE_BEG);
11389 if (match(parser,
'=')) {
11390 lex_state_set(parser, PM_LEX_STATE_BEG);
11394 if (lex_state_operator_p(parser)) {
11395 lex_state_set(parser, PM_LEX_STATE_ARG);
11397 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11404 if (lex_state_operator_p(parser)) {
11405 lex_state_set(parser, PM_LEX_STATE_ARG);
11407 if (match(parser,
'@')) {
11414 if (match(parser,
'=')) {
11415 lex_state_set(parser, PM_LEX_STATE_BEG);
11420 lex_state_beg_p(parser) ||
11421 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11423 lex_state_set(parser, PM_LEX_STATE_BEG);
11425 if (pm_char_is_decimal_digit(peek(parser))) {
11428 lex_state_set(parser, PM_LEX_STATE_END);
11435 if (ambiguous_operator_p(parser, space_seen)) {
11436 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11439 lex_state_set(parser, PM_LEX_STATE_BEG);
11445 if (lex_state_operator_p(parser)) {
11446 lex_state_set(parser, PM_LEX_STATE_ARG);
11448 if (match(parser,
'@')) {
11455 if (match(parser,
'=')) {
11456 lex_state_set(parser, PM_LEX_STATE_BEG);
11460 if (match(parser,
'>')) {
11461 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11465 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11466 bool is_beg = lex_state_beg_p(parser);
11467 if (!is_beg && spcarg) {
11468 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11471 if (is_beg || spcarg) {
11472 lex_state_set(parser, PM_LEX_STATE_BEG);
11476 if (ambiguous_operator_p(parser, space_seen)) {
11477 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11480 lex_state_set(parser, PM_LEX_STATE_BEG);
11486 bool beg_p = lex_state_beg_p(parser);
11488 if (match(parser,
'.')) {
11489 if (match(parser,
'.')) {
11492 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11493 lex_state_set(parser, PM_LEX_STATE_BEG);
11495 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11501 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11504 lex_state_set(parser, PM_LEX_STATE_BEG);
11508 lex_state_set(parser, PM_LEX_STATE_BEG);
11512 lex_state_set(parser, PM_LEX_STATE_DOT);
11528 lex_state_set(parser, PM_LEX_STATE_END);
11534 if (match(parser,
':')) {
11535 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)) {
11536 lex_state_set(parser, PM_LEX_STATE_BEG);
11540 lex_state_set(parser, PM_LEX_STATE_DOT);
11544 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11545 lex_state_set(parser, PM_LEX_STATE_BEG);
11549 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11550 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11554 lex_state_set(parser, PM_LEX_STATE_FNAME);
11559 if (lex_state_beg_p(parser)) {
11560 lex_mode_push_regexp(parser,
'\0',
'/');
11564 if (match(parser,
'=')) {
11565 lex_state_set(parser, PM_LEX_STATE_BEG);
11569 if (lex_state_spcarg_p(parser, space_seen)) {
11570 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11571 lex_mode_push_regexp(parser,
'\0',
'/');
11575 if (ambiguous_operator_p(parser, space_seen)) {
11576 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11579 if (lex_state_operator_p(parser)) {
11580 lex_state_set(parser, PM_LEX_STATE_ARG);
11582 lex_state_set(parser, PM_LEX_STATE_BEG);
11589 if (lex_state_operator_p(parser)) {
11590 lex_state_set(parser, PM_LEX_STATE_ARG);
11592 lex_state_set(parser, PM_LEX_STATE_BEG);
11598 if (lex_state_operator_p(parser)) {
11599 (void) match(parser,
'@');
11600 lex_state_set(parser, PM_LEX_STATE_ARG);
11602 lex_state_set(parser, PM_LEX_STATE_BEG);
11613 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11614 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11618 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11619 lex_state_set(parser, PM_LEX_STATE_BEG);
11622 lex_state_beg_p(parser) ||
11623 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11624 lex_state_spcarg_p(parser, space_seen)
11627 if (*parser->
current.end >= 0x80) {
11628 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11631 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11632 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11638 uint8_t delimiter = peek_offset(parser, 1);
11640 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11641 goto lex_next_token;
11644 switch (peek(parser)) {
11649 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11651 lex_mode_push_list_eof(parser);
11660 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11662 lex_mode_push_list_eof(parser);
11671 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11672 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11674 lex_mode_push_regexp(parser,
'\0',
'\0');
11683 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11684 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11686 lex_mode_push_string_eof(parser);
11695 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11696 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11698 lex_mode_push_string_eof(parser);
11707 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11708 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11709 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11711 lex_mode_push_string_eof(parser);
11720 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11722 lex_mode_push_list_eof(parser);
11731 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11733 lex_mode_push_list_eof(parser);
11742 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11743 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11745 lex_mode_push_string_eof(parser);
11755 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11756 goto lex_next_token;
11760 if (ambiguous_operator_p(parser, space_seen)) {
11761 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11764 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11775 lex_mode_pop(parser);
11778 lex_state_set(parser, PM_LEX_STATE_END);
11784 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11785 LEX(lex_at_variable(parser));
11788 if (*parser->
current.start !=
'_') {
11789 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11796 if (*parser->
current.start >= 0x80) {
11797 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11798 }
else if (*parser->
current.start ==
'\\') {
11799 switch (peek_at(parser, parser->
current.start + 1)) {
11802 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11806 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11810 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11814 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11817 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11819 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11824 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11827 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11828 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11830 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11833 goto lex_next_token;
11847 current_token_starts_line(parser) &&
11848 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11849 (parser->
current.end == parser->
end || match_eol(parser))
11854 const uint8_t *cursor = parser->
current.end;
11855 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11856 pm_newline_list_append(&parser->
newline_list, cursor++);
11861 parser_lex_callback(parser);
11872 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11873 if (previous_command_start) {
11874 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11876 lex_state_set(parser, PM_LEX_STATE_ARG);
11878 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11879 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11881 lex_state_set(parser, PM_LEX_STATE_END);
11886 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11888 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11889 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11891 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11898 case PM_LEX_LIST: {
11912 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11913 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11920 if (whitespace > 0) {
11921 parser->
current.end += whitespace;
11922 if (peek_offset(parser, -1) ==
'\n') {
11924 parser_flush_heredoc_end(parser);
11938 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11939 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11945 while (breakpoint != NULL) {
11948 if (pm_char_is_whitespace(*breakpoint)) {
11949 parser->
current.end = breakpoint;
11950 pm_token_buffer_flush(parser, &token_buffer);
11960 parser->
current.end = breakpoint + 1;
11961 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11968 if (breakpoint > parser->
current.start) {
11969 parser->
current.end = breakpoint;
11970 pm_token_buffer_flush(parser, &token_buffer);
11976 parser->
current.end = breakpoint + 1;
11977 lex_mode_pop(parser);
11978 lex_state_set(parser, PM_LEX_STATE_END);
11983 if (*breakpoint ==
'\0') {
11984 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11991 if (*breakpoint ==
'\\') {
11992 parser->
current.end = breakpoint + 1;
12001 pm_token_buffer_escape(parser, &token_buffer);
12002 uint8_t peeked = peek(parser);
12010 pm_token_buffer_push_byte(&token_buffer, peeked);
12015 if (peek(parser) !=
'\n') {
12016 pm_token_buffer_push_byte(&token_buffer,
'\r');
12021 pm_token_buffer_push_byte(&token_buffer,
'\n');
12027 parser_flush_heredoc_end(parser);
12028 pm_token_buffer_copy(parser, &token_buffer);
12039 pm_token_buffer_push_byte(&token_buffer, peeked);
12042 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12044 pm_token_buffer_push_byte(&token_buffer,
'\\');
12045 pm_token_buffer_push_escaped(&token_buffer, parser);
12052 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12057 if (*breakpoint ==
'#') {
12065 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12070 pm_token_buffer_flush(parser, &token_buffer);
12079 parser->
current.end = breakpoint + 1;
12080 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12086 pm_token_buffer_flush(parser, &token_buffer);
12093 pm_token_buffer_flush(parser, &token_buffer);
12096 case PM_LEX_REGEXP: {
12118 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12119 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12122 while (breakpoint != NULL) {
12124 bool is_terminator = (*breakpoint == term);
12129 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12130 if (term ==
'\n') {
12131 is_terminator =
true;
12137 if (term ==
'\r') {
12138 is_terminator =
false;
12144 if (is_terminator) {
12146 parser->
current.end = breakpoint + 1;
12147 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12155 if (breakpoint > parser->
current.start) {
12156 parser->
current.end = breakpoint;
12157 pm_regexp_token_buffer_flush(parser, &token_buffer);
12162 size_t eol_length = match_eol_at(parser, breakpoint);
12164 parser->
current.end = breakpoint + eol_length;
12167 parser->
current.end = breakpoint + 1;
12174 lex_mode_pop(parser);
12175 lex_state_set(parser, PM_LEX_STATE_END);
12181 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12182 parser->
current.end = breakpoint + 1;
12183 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12188 switch (*breakpoint) {
12191 parser->
current.end = breakpoint + 1;
12192 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12195 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12196 parser->
current.end = breakpoint + 1;
12197 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12202 parser->
current.end = breakpoint;
12203 pm_regexp_token_buffer_escape(parser, &token_buffer);
12211 pm_newline_list_append(&parser->
newline_list, breakpoint);
12212 parser->
current.end = breakpoint + 1;
12213 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12217 parser->
current.end = breakpoint + 1;
12218 parser_flush_heredoc_end(parser);
12219 pm_regexp_token_buffer_flush(parser, &token_buffer);
12225 parser->
current.end = breakpoint + 1;
12234 pm_regexp_token_buffer_escape(parser, &token_buffer);
12235 uint8_t peeked = peek(parser);
12240 if (peek(parser) !=
'\n') {
12242 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12244 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12245 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12254 parser_flush_heredoc_end(parser);
12255 pm_regexp_token_buffer_copy(parser, &token_buffer);
12277 case '$':
case ')':
case '*':
case '+':
12278 case '.':
case '>':
case '?':
case ']':
12279 case '^':
case '|':
case '}':
12280 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12286 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12287 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12292 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12293 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12298 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12311 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12316 pm_regexp_token_buffer_flush(parser, &token_buffer);
12322 assert(
false &&
"unreachable");
12328 pm_regexp_token_buffer_flush(parser, &token_buffer);
12335 pm_regexp_token_buffer_flush(parser, &token_buffer);
12338 case PM_LEX_STRING: {
12357 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12358 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12364 while (breakpoint != NULL) {
12369 parser->
current.end = breakpoint + 1;
12370 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12375 bool is_terminator = (*breakpoint == term);
12380 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12381 if (term ==
'\n') {
12382 is_terminator =
true;
12388 if (term ==
'\r') {
12389 is_terminator =
false;
12396 if (is_terminator) {
12400 parser->
current.end = breakpoint + 1;
12401 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12408 if (breakpoint > parser->
current.start) {
12409 parser->
current.end = breakpoint;
12410 pm_token_buffer_flush(parser, &token_buffer);
12416 size_t eol_length = match_eol_at(parser, breakpoint);
12418 parser->
current.end = breakpoint + eol_length;
12421 parser->
current.end = breakpoint + 1;
12424 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12426 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12427 lex_mode_pop(parser);
12431 lex_state_set(parser, PM_LEX_STATE_END);
12432 lex_mode_pop(parser);
12436 switch (*breakpoint) {
12439 parser->
current.end = breakpoint + 1;
12440 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12443 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12444 parser->
current.end = breakpoint + 1;
12445 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12452 parser->
current.end = breakpoint;
12453 pm_token_buffer_escape(parser, &token_buffer);
12454 token_buffer.
cursor = breakpoint;
12463 pm_newline_list_append(&parser->
newline_list, breakpoint);
12464 parser->
current.end = breakpoint + 1;
12465 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12469 parser->
current.end = breakpoint + 1;
12470 parser_flush_heredoc_end(parser);
12471 pm_token_buffer_flush(parser, &token_buffer);
12475 parser->
current.end = breakpoint + 1;
12484 pm_token_buffer_escape(parser, &token_buffer);
12485 uint8_t peeked = peek(parser);
12489 pm_token_buffer_push_byte(&token_buffer,
'\\');
12494 if (peek(parser) !=
'\n') {
12496 pm_token_buffer_push_byte(&token_buffer,
'\\');
12498 pm_token_buffer_push_byte(&token_buffer,
'\r');
12504 pm_token_buffer_push_byte(&token_buffer,
'\\');
12505 pm_token_buffer_push_byte(&token_buffer,
'\n');
12512 parser_flush_heredoc_end(parser);
12513 pm_token_buffer_copy(parser, &token_buffer);
12524 pm_token_buffer_push_byte(&token_buffer, peeked);
12527 pm_token_buffer_push_byte(&token_buffer, peeked);
12530 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12532 pm_token_buffer_push_byte(&token_buffer,
'\\');
12533 pm_token_buffer_push_escaped(&token_buffer, parser);
12540 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12551 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12556 pm_token_buffer_flush(parser, &token_buffer);
12562 assert(
false &&
"unreachable");
12567 pm_token_buffer_flush(parser, &token_buffer);
12574 pm_token_buffer_flush(parser, &token_buffer);
12577 case PM_LEX_HEREDOC: {
12604 lex_state_set(parser, PM_LEX_STATE_END);
12605 lex_mode_pop(parser);
12609 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12614 if (current_token_starts_line(parser)) {
12615 const uint8_t *start = parser->
current.start;
12617 if (!line_continuation && (start + ident_length <= parser->end)) {
12618 const uint8_t *newline = next_newline(start, parser->
end - start);
12619 const uint8_t *ident_end = newline;
12620 const uint8_t *terminator_end = newline;
12622 if (newline == NULL) {
12623 terminator_end = parser->
end;
12624 ident_end = parser->
end;
12627 if (newline[-1] ==
'\r') {
12632 const uint8_t *terminator_start = ident_end - ident_length;
12633 const uint8_t *cursor = start;
12635 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12636 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12642 (cursor == terminator_start) &&
12643 (memcmp(terminator_start, ident_start, ident_length) == 0)
12645 if (newline != NULL) {
12646 pm_newline_list_append(&parser->
newline_list, newline);
12649 parser->
current.end = terminator_end;
12657 lex_state_set(parser, PM_LEX_STATE_END);
12658 lex_mode_pop(parser);
12663 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12665 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12668 peek_at(parser, start) !=
'\n'
12677 uint8_t breakpoints[] =
"\r\n\\#";
12680 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12681 breakpoints[3] =
'\0';
12684 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12686 bool was_line_continuation =
false;
12688 while (breakpoint != NULL) {
12689 switch (*breakpoint) {
12692 parser->
current.end = breakpoint + 1;
12693 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12696 parser->
current.end = breakpoint + 1;
12698 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12699 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12706 pm_token_buffer_escape(parser, &token_buffer);
12707 token_buffer.
cursor = breakpoint;
12712 parser_flush_heredoc_end(parser);
12713 parser->
current.end = breakpoint + 1;
12714 pm_token_buffer_flush(parser, &token_buffer);
12718 pm_newline_list_append(&parser->
newline_list, breakpoint);
12722 const uint8_t *start = breakpoint + 1;
12724 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12727 const uint8_t *newline = next_newline(start, parser->
end - start);
12729 if (newline == NULL) {
12730 newline = parser->
end;
12731 }
else if (newline[-1] ==
'\r') {
12736 const uint8_t *terminator_start = newline - ident_length;
12740 const uint8_t *cursor = start;
12742 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12743 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12749 cursor == terminator_start &&
12750 (memcmp(terminator_start, ident_start, ident_length) == 0)
12752 parser->
current.end = breakpoint + 1;
12753 pm_token_buffer_flush(parser, &token_buffer);
12758 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12765 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12770 parser->
current.end = breakpoint + 1;
12771 pm_token_buffer_flush(parser, &token_buffer);
12777 parser->
current.end = breakpoint + 1;
12778 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12788 parser->
current.end = breakpoint + 1;
12797 pm_token_buffer_escape(parser, &token_buffer);
12798 uint8_t peeked = peek(parser);
12800 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12804 if (peek(parser) !=
'\n') {
12805 pm_token_buffer_push_byte(&token_buffer,
'\\');
12806 pm_token_buffer_push_byte(&token_buffer,
'\r');
12811 pm_token_buffer_push_byte(&token_buffer,
'\\');
12812 pm_token_buffer_push_byte(&token_buffer,
'\n');
12814 breakpoint = parser->
current.end;
12817 pm_token_buffer_push_byte(&token_buffer,
'\\');
12818 pm_token_buffer_push_escaped(&token_buffer, parser);
12825 if (peek(parser) !=
'\n') {
12826 pm_token_buffer_push_byte(&token_buffer,
'\r');
12834 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12835 const uint8_t *end = parser->
current.end;
12840 parser->
current.end = breakpoint;
12841 pm_token_buffer_flush(parser, &token_buffer);
12845 parser->
current.end = end + 1;
12850 was_line_continuation =
true;
12852 breakpoint = parser->
current.end;
12855 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12861 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12873 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12878 pm_token_buffer_flush(parser, &token_buffer);
12884 assert(
false &&
"unreachable");
12887 was_line_continuation =
false;
12892 pm_token_buffer_flush(parser, &token_buffer);
12899 pm_token_buffer_flush(parser, &token_buffer);
12904 assert(
false &&
"unreachable");
12922 PM_BINDING_POWER_UNSET = 0,
12923 PM_BINDING_POWER_STATEMENT = 2,
12924 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12925 PM_BINDING_POWER_MODIFIER = 6,
12926 PM_BINDING_POWER_COMPOSITION = 8,
12927 PM_BINDING_POWER_NOT = 10,
12928 PM_BINDING_POWER_MATCH = 12,
12929 PM_BINDING_POWER_DEFINED = 14,
12930 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12931 PM_BINDING_POWER_ASSIGNMENT = 18,
12932 PM_BINDING_POWER_TERNARY = 20,
12933 PM_BINDING_POWER_RANGE = 22,
12934 PM_BINDING_POWER_LOGICAL_OR = 24,
12935 PM_BINDING_POWER_LOGICAL_AND = 26,
12936 PM_BINDING_POWER_EQUALITY = 28,
12937 PM_BINDING_POWER_COMPARISON = 30,
12938 PM_BINDING_POWER_BITWISE_OR = 32,
12939 PM_BINDING_POWER_BITWISE_AND = 34,
12940 PM_BINDING_POWER_SHIFT = 36,
12941 PM_BINDING_POWER_TERM = 38,
12942 PM_BINDING_POWER_FACTOR = 40,
12943 PM_BINDING_POWER_UMINUS = 42,
12944 PM_BINDING_POWER_EXPONENT = 44,
12945 PM_BINDING_POWER_UNARY = 46,
12946 PM_BINDING_POWER_INDEX = 48,
12947 PM_BINDING_POWER_CALL = 50,
12948 PM_BINDING_POWER_MAX = 52
12949} pm_binding_power_t;
12972#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12973#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12974#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12975#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12976#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
13038 [
PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13042 [
PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13043 [
PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13059 [
PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13060 [
PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13063 [
PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13071 [
PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13072 [
PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13073 [
PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13080 [
PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13084#undef BINDING_POWER_ASSIGNMENT
13085#undef LEFT_ASSOCIATIVE
13086#undef RIGHT_ASSOCIATIVE
13087#undef RIGHT_ASSOCIATIVE_UNARY
13102 return match1(parser, type1) || match1(parser, type2);
13110 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13118 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13126 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13134 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);
13142 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) || match1(parser, type9);
13153 if (match1(parser,
type)) {
13154 parser_lex(parser);
13166 if (match2(parser, type1, type2)) {
13167 parser_lex(parser);
13186 if (accept1(parser,
type))
return;
13189 pm_parser_err(parser, location, location, diag_id);
13201 if (accept2(parser, type1, type2))
return;
13204 pm_parser_err(parser, location, location, diag_id);
13215expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13217 parser_lex(parser);
13219 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13226parse_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);
13233parse_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) {
13234 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13235 pm_assert_value_expression(parser, node);
13289 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13309 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13318parse_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) {
13321 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13322 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13325 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13339 size_t length = constant->
length;
13340 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13341 if (name == NULL)
return;
13343 memcpy(name, constant->
start, length);
13344 name[length] =
'=';
13349 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13361 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13362 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13363 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13364 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13365 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13366 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13367 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13374 pm_node_destroy(parser, target);
13387 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13388 if (implicit_parameters->
nodes[index] == node) {
13392 if (index != implicit_parameters->
size - 1) {
13393 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13396 implicit_parameters->
size--;
13424 return parse_unwriteable_target(parser, target);
13431 if (context_def_p(parser)) {
13432 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13440 if (context_def_p(parser)) {
13441 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13450 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13459 parse_target_implicit_parameter(parser, target);
13463 uint32_t name = cast->
name;
13464 uint32_t depth = cast->
depth;
13465 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13476 parse_target_implicit_parameter(parser, target);
13477 pm_node_destroy(parser, target);
13486 if (splat_parent) {
13489 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13514 (call->
block == NULL)
13529 pm_node_destroy(parser, target);
13531 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13536 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13539 parse_write_name(parser, &call->
name);
13540 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13548 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13556 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13567 pm_node_t *result = parse_target(parser, target, multiple,
false);
13576 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13590 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13591 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13604 pm_node_destroy(parser, value);
13608 pm_node_destroy(parser, target);
13614 if (context_def_p(parser)) {
13615 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13618 return parse_shareable_constant_write(parser, node);
13623 if (context_def_p(parser)) {
13624 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13627 pm_node_destroy(parser, target);
13628 return parse_shareable_constant_write(parser, node);
13632 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13636 pm_node_destroy(parser, target);
13645 uint32_t depth = local_read->
depth;
13646 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13649 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13651 parse_target_implicit_parameter(parser, target);
13654 pm_locals_unread(&scope->
locals, name);
13655 pm_node_destroy(parser, target);
13657 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13663 parse_target_implicit_parameter(parser, target);
13664 pm_node_destroy(parser, target);
13670 pm_node_destroy(parser, target);
13683 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13685 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13699 (call->
block == NULL)
13713 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13714 pm_node_destroy(parser, target);
13717 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13719 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13737 pm_arguments_node_arguments_append(arguments, value);
13740 parse_write_name(parser, &call->
name);
13752 call->
arguments = pm_arguments_node_create(parser);
13755 pm_arguments_node_arguments_append(call->
arguments, value);
13759 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13773 pm_node_destroy(parser, value);
13780 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13794 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13795 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13796 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13797 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13798 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13799 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13800 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13807 pm_node_destroy(parser, target);
13822parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13826 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13834 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13840 if (token_begins_expression_p(parser->
current.type)) {
13841 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13842 name = parse_target(parser, name,
true,
true);
13845 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13846 pm_multi_target_node_targets_append(parser, result, splat);
13850 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13851 target = parse_target(parser, target,
true,
false);
13853 pm_multi_target_node_targets_append(parser, result, target);
13854 context_pop(parser);
13855 }
else if (token_begins_expression_p(parser->
current.type)) {
13856 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13857 target = parse_target(parser, target,
true,
false);
13859 pm_multi_target_node_targets_append(parser, result, target);
13864 pm_multi_target_node_targets_append(parser, result, rest);
13877parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13878 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13883 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13899 if (context_terminator(context, &parser->
current))
return NULL;
13905 context_push(parser, context);
13908 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13909 pm_statements_node_body_append(parser, statements, node,
true);
13926 if (context_terminator(context, &parser->
current))
break;
13936 if (context_terminator(context, &parser->
current))
break;
13949 parser_lex(parser);
13961 if (context_terminator(context, &parser->
current))
break;
13972 context_pop(parser);
13973 bool last_value =
true;
13977 last_value =
false;
13982 pm_void_statements_check(parser, statements, last_value);
13995 if (duplicated != NULL) {
13999 pm_diagnostic_list_append_format(
14003 PM_WARN_DUPLICATED_HASH_KEY,
14004 (
int) pm_buffer_length(&buffer),
14005 pm_buffer_value(&buffer),
14009 pm_buffer_free(&buffer);
14021 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14022 pm_diagnostic_list_append_format(
14026 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14039 bool contains_keyword_splat =
false;
14044 switch (parser->
current.type) {
14046 parser_lex(parser);
14056 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14057 }
else if (token_begins_expression_p(parser->
current.type)) {
14058 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14060 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14063 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14064 contains_keyword_splat =
true;
14069 parser_lex(parser);
14072 pm_hash_key_static_literals_add(parser, literals, key);
14077 if (token_begins_expression_p(parser->
current.type)) {
14078 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14082 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14087 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14088 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14090 depth = pm_parser_local_depth(parser, &identifier);
14094 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14096 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14101 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14104 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14108 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14116 pm_hash_key_static_literals_add(parser, literals, key);
14119 if (pm_symbol_node_label_p(key)) {
14120 operator = not_provided(parser);
14126 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14127 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14147 if (token_begins_expression_p(parser->
current.type))
continue;
14153 return contains_keyword_splat;
14162 arguments->
arguments = pm_arguments_node_create(parser);
14165 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14173 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
14179 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14185 bool parsed_first_argument =
false;
14186 bool parsed_bare_hash =
false;
14187 bool parsed_block_argument =
false;
14188 bool parsed_forwarding_arguments =
false;
14191 if (parsed_forwarding_arguments) {
14192 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14197 switch (parser->
current.type) {
14200 if (parsed_bare_hash) {
14201 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14208 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14210 parse_arguments_append(parser, arguments, argument);
14216 pm_static_literals_free(&hash_keys);
14217 parsed_bare_hash =
true;
14222 parser_lex(parser);
14226 if (token_begins_expression_p(parser->
current.type)) {
14227 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14229 pm_parser_scope_forwarding_block_check(parser, &
operator);
14232 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14233 if (parsed_block_argument) {
14234 parse_arguments_append(parser, arguments, argument);
14236 arguments->
block = argument;
14240 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14243 parsed_block_argument =
true;
14247 parser_lex(parser);
14251 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14252 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14253 if (parsed_bare_hash) {
14254 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14257 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14259 if (parsed_bare_hash) {
14260 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14263 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14266 parse_arguments_append(parser, arguments, argument);
14270 if (accepts_forwarding) {
14271 parser_lex(parser);
14273 if (token_begins_expression_p(parser->
current.type)) {
14278 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14285 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14288 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14290 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14291 if (parsed_first_argument && terminator ==
PM_TOKEN_EOF) {
14292 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14295 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14296 parse_arguments_append(parser, arguments, argument);
14299 parsed_forwarding_arguments =
true;
14306 if (argument == NULL) {
14307 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14310 bool contains_keywords =
false;
14311 bool contains_keyword_splat =
false;
14314 if (parsed_bare_hash) {
14315 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14322 operator = not_provided(parser);
14326 contains_keywords =
true;
14330 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14333 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14334 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14336 pm_keyword_hash_node_elements_append(bare_hash, argument);
14341 token_begins_expression_p(parser->
current.type) ||
14344 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14347 pm_static_literals_free(&hash_keys);
14348 parsed_bare_hash =
true;
14351 parse_arguments_append(parser, arguments, argument);
14362 parsed_first_argument =
true;
14370 bool accepted_newline =
false;
14382 if (accepted_newline) {
14383 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14393 if (match1(parser, terminator))
break;
14408parse_required_destructured_parameter(
pm_parser_t *parser) {
14412 pm_multi_target_node_opening_set(node, &parser->
previous);
14423 pm_multi_target_node_targets_append(parser, node, param);
14424 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14429 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14436 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14437 if (pm_parser_parameter_name_check(parser, &name)) {
14438 pm_node_flag_set_repeated_parameter(value);
14440 pm_parser_local_add_token(parser, &name, 1);
14443 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14448 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14449 if (pm_parser_parameter_name_check(parser, &name)) {
14450 pm_node_flag_set_repeated_parameter(param);
14452 pm_parser_local_add_token(parser, &name, 1);
14455 pm_multi_target_node_targets_append(parser, node, param);
14460 pm_multi_target_node_closing_set(node, &parser->
previous);
14470 PM_PARAMETERS_NO_CHANGE = 0,
14471 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14472 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14473 PM_PARAMETERS_ORDER_KEYWORDS,
14474 PM_PARAMETERS_ORDER_REST,
14475 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14476 PM_PARAMETERS_ORDER_OPTIONAL,
14477 PM_PARAMETERS_ORDER_NAMED,
14478 PM_PARAMETERS_ORDER_NONE,
14479} pm_parameters_order_t;
14485 [0] = PM_PARAMETERS_NO_CHANGE,
14508 pm_parameters_order_t state = parameters_ordering[token->type];
14509 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14513 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14514 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14516 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14520 if (token->type ==
PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14521 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14523 }
else if (token->type ==
PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14524 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14526 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14528 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14532 if (state < *current) *current = state;
14542 pm_binding_power_t binding_power,
14543 bool uses_parentheses,
14544 bool allows_trailing_comma,
14545 bool allows_forwarding_parameters,
14546 bool accepts_blocks_in_defaults,
14550 pm_do_loop_stack_push(parser,
false);
14553 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14556 bool parsing =
true;
14558 switch (parser->
current.type) {
14560 update_parameter_state(parser, &parser->
current, &order);
14563 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14564 pm_parameters_node_requireds_append(params, param);
14566 pm_parameters_node_posts_append(params, param);
14572 update_parameter_state(parser, &parser->
current, &order);
14573 parser_lex(parser);
14578 bool repeated =
false;
14581 repeated = pm_parser_parameter_name_check(parser, &name);
14582 pm_parser_local_add_token(parser, &name, 1);
14584 name = not_provided(parser);
14590 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14592 if (params->
block == NULL) {
14593 pm_parameters_node_block_set(params, param);
14595 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14596 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14602 if (!allows_forwarding_parameters) {
14603 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14606 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14607 parser_lex(parser);
14616 pm_parameters_node_posts_append(params, keyword_rest);
14617 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14621 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14630 parser_lex(parser);
14633 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14636 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14639 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14642 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14645 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14651 update_parameter_state(parser, &parser->
current, &order);
14653 update_parameter_state(parser, &parser->
previous, &order);
14657 bool repeated = pm_parser_parameter_name_check(parser, &name);
14658 pm_parser_local_add_token(parser, &name, 1);
14663 parser_lex(parser);
14668 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14669 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14670 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14675 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14677 pm_parameters_node_optionals_append(params, param);
14683 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14686 context_pop(parser);
14695 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14698 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14700 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14704 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14706 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14712 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14713 update_parameter_state(parser, &parser->
current, &order);
14716 parser_lex(parser);
14723 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14724 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14725 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14728 bool repeated = pm_parser_parameter_name_check(parser, &local);
14729 pm_parser_local_add_token(parser, &local, 1);
14731 switch (parser->
current.type) {
14735 context_pop(parser);
14737 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14739 pm_node_flag_set_repeated_parameter(param);
14742 pm_parameters_node_keywords_append(params, param);
14747 context_pop(parser);
14749 if (uses_parentheses) {
14754 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14756 pm_node_flag_set_repeated_parameter(param);
14759 pm_parameters_node_keywords_append(params, param);
14765 if (token_begins_expression_p(parser->
current.type)) {
14769 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14770 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14771 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14774 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14777 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14780 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14784 pm_node_flag_set_repeated_parameter(param);
14787 context_pop(parser);
14788 pm_parameters_node_keywords_append(params, param);
14805 update_parameter_state(parser, &parser->
current, &order);
14806 parser_lex(parser);
14810 bool repeated =
false;
14814 repeated = pm_parser_parameter_name_check(parser, &name);
14815 pm_parser_local_add_token(parser, &name, 1);
14817 name = not_provided(parser);
14821 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14823 pm_node_flag_set_repeated_parameter(param);
14826 if (params->
rest == NULL) {
14827 pm_parameters_node_rest_set(params, param);
14829 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14830 pm_parameters_node_posts_append(params, param);
14837 pm_parameters_order_t previous_order = order;
14838 update_parameter_state(parser, &parser->
current, &order);
14839 parser_lex(parser);
14845 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14846 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14849 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14853 bool repeated =
false;
14856 repeated = pm_parser_parameter_name_check(parser, &name);
14857 pm_parser_local_add_token(parser, &name, 1);
14859 name = not_provided(parser);
14863 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14865 pm_node_flag_set_repeated_parameter(param);
14870 pm_parameters_node_keyword_rest_set(params, param);
14872 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14873 pm_parameters_node_posts_append(params, param);
14880 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14885 if (params->
rest == NULL) {
14886 pm_parameters_node_rest_set(params, param);
14888 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14889 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14892 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14903 if (!parsing)
break;
14905 bool accepted_newline =
false;
14906 if (uses_parentheses) {
14913 if (accepted_newline) {
14914 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14922 pm_do_loop_stack_pop(parser);
14926 pm_node_destroy(parser, (
pm_node_t *) params);
14958token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14960 const uint8_t *end = token->start;
14964 newline_index == 0 &&
14965 parser->
start[0] == 0xef &&
14966 parser->
start[1] == 0xbb &&
14967 parser->
start[2] == 0xbf
14970 int64_t column = 0;
14971 for (; cursor < end; cursor++) {
14974 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14981 if (break_on_non_space)
return -1;
14994parser_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) {
14999 size_t closing_newline_index = token_newline_index(parser);
15000 if (opening_newline_index == closing_newline_index)
return;
15005 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15006 if (!if_after_else && (opening_column == -1))
return;
15013 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15014 if ((closing_column == -1) || (opening_column == closing_column))
return;
15018 if (allow_indent && (closing_column > opening_column))
return;
15021 PM_PARSER_WARN_FORMAT(
15023 closing_token->
start,
15024 closing_token->
end,
15025 PM_WARN_INDENTATION_MISMATCH,
15026 (
int) (closing_token->
end - closing_token->
start),
15027 (
const char *) closing_token->
start,
15028 (
int) (opening_token->
end - opening_token->
start),
15029 (
const char *) opening_token->
start,
15030 ((int32_t) opening_newline_index) + parser->
start_line
15035 PM_RESCUES_BEGIN = 1,
15042} pm_rescues_type_t;
15053 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15054 parser_lex(parser);
15058 switch (parser->
current.type) {
15063 parser_lex(parser);
15064 pm_rescue_node_operator_set(rescue, &parser->
previous);
15066 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15067 reference = parse_target(parser, reference,
false,
false);
15069 pm_rescue_node_reference_set(rescue, reference);
15084 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15085 pm_rescue_node_exceptions_append(rescue, expression);
15094 pm_rescue_node_operator_set(rescue, &parser->
previous);
15096 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15097 reference = parse_target(parser, reference,
false,
false);
15099 pm_rescue_node_reference_set(rescue, reference);
15114 pm_accepts_block_stack_push(parser,
true);
15129 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15131 pm_accepts_block_stack_pop(parser);
15135 if (current == NULL) {
15136 pm_begin_node_rescue_clause_set(parent_node, rescue);
15138 pm_rescue_node_subsequent_set(current, rescue);
15147 if (current != NULL) {
15151 while (clause != NULL) {
15159 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15160 opening_newline_index = token_newline_index(parser);
15162 else_keyword = parser->
current;
15163 opening = &else_keyword;
15165 parser_lex(parser);
15170 pm_accepts_block_stack_push(parser,
true);
15184 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15185 pm_accepts_block_stack_pop(parser);
15190 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15191 pm_begin_node_else_clause_set(parent_node, else_clause);
15195 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15199 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15202 parser_lex(parser);
15207 pm_accepts_block_stack_push(parser,
true);
15221 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15222 pm_accepts_block_stack_pop(parser);
15227 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15228 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15232 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15233 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15236 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15246 pm_token_t begin_keyword = not_provided(parser);
15247 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15249 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15259parse_block_parameters(
15261 bool allows_trailing_comma,
15263 bool is_lambda_literal,
15264 bool accepts_blocks_in_defaults,
15269 parameters = parse_parameters(
15271 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15273 allows_trailing_comma,
15275 accepts_blocks_in_defaults,
15277 (uint16_t) (depth + 1)
15287 switch (parser->
current.type) {
15289 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15290 parser_lex(parser);
15293 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15294 parser_lex(parser);
15297 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15298 parser_lex(parser);
15301 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15302 parser_lex(parser);
15309 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15310 pm_parser_local_add_token(parser, &parser->
previous, 1);
15313 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15315 pm_block_parameters_node_append_local(block_parameters, local);
15320 return block_parameters;
15328outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15330 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15341static const char *
const pm_numbered_parameter_names[] = {
15342 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15356 if (parameters != NULL) {
15358 if (implicit_parameters->
size > 0) {
15362 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15364 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15366 assert(
false &&
"unreachable");
15375 if (implicit_parameters->
size == 0) {
15382 uint8_t numbered_parameter = 0;
15383 bool it_parameter =
false;
15385 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15389 if (it_parameter) {
15390 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15391 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15392 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15394 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15396 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15398 assert(
false &&
"unreachable");
15401 if (numbered_parameter > 0) {
15402 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15404 it_parameter =
true;
15409 if (numbered_parameter > 0) {
15413 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15417 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15420 if (it_parameter) {
15421 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15431parse_block(
pm_parser_t *parser, uint16_t depth) {
15435 pm_accepts_block_stack_push(parser,
true);
15436 pm_parser_scope_push(parser,
false);
15443 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15445 parser_lex(parser);
15447 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15450 expect1(parser,
PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15453 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15468 pm_accepts_block_stack_push(parser,
true);
15470 pm_accepts_block_stack_pop(parser);
15475 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));
15483 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15486 pm_parser_scope_pop(parser);
15487 pm_accepts_block_stack_pop(parser);
15489 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15498parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15499 bool found =
false;
15508 pm_accepts_block_stack_push(parser,
true);
15517 pm_accepts_block_stack_pop(parser);
15522 pm_accepts_block_stack_push(parser,
false);
15527 parse_arguments(parser, arguments, accepts_block,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
15536 pm_accepts_block_stack_pop(parser);
15542 if (accepts_block) {
15547 block = parse_block(parser, (uint16_t) (depth + 1));
15548 pm_arguments_validate_block(parser, arguments, block);
15551 block = parse_block(parser, (uint16_t) (depth + 1));
15554 if (block != NULL) {
15558 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15560 if (arguments->
block != NULL) {
15562 arguments->
arguments = pm_arguments_node_create(parser);
15564 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15580 bool in_sclass =
false;
15582 switch (context_node->
context) {
15627 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15649 assert(
false &&
"unreachable");
15654 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15665 switch (context_node->
context) {
15739 assert(
false &&
"unreachable");
15753 return previous_block_exits;
15771 default: assert(
false &&
"unreachable");
type =
"";
break;
15774 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15791 }
else if (previous_block_exits != NULL) {
15803 flush_block_exits(parser, previous_block_exits);
15811 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15817 predicate_closed =
true;
15821 if (!predicate_closed) {
15822 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15825 context_pop(parser);
15830parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15832 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15835 pm_token_t then_keyword = not_provided(parser);
15837 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15841 pm_accepts_block_stack_push(parser,
true);
15842 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15843 pm_accepts_block_stack_pop(parser);
15847 pm_token_t end_keyword = not_provided(parser);
15852 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15855 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15858 assert(
false &&
"unreachable");
15868 if (parser_end_of_line_p(parser)) {
15869 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15872 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15874 parser_lex(parser);
15876 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15877 pm_accepts_block_stack_push(parser,
true);
15880 pm_accepts_block_stack_pop(parser);
15883 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15890 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15891 opening_newline_index = token_newline_index(parser);
15893 parser_lex(parser);
15896 pm_accepts_block_stack_push(parser,
true);
15898 pm_accepts_block_stack_pop(parser);
15901 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15904 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15914 assert(
false &&
"unreachable");
15918 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15926 bool recursing =
true;
15928 while (recursing) {
15933 recursing = current != NULL;
15951 assert(
false &&
"unreachable");
15955 pop_block_exits(parser, previous_block_exits);
15956 pm_node_list_free(¤t_block_exits);
15965#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15966 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15967 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15968 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15969 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15970 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15971 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15972 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15973 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15974 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15975 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15981#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15982 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15983 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15984 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15985 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15986 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15987 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15988 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15995#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15996 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15997 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15998 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15999 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16000 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16001 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16002 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16003 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16009#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16010 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16011 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16012 case PM_TOKEN_CLASS_VARIABLE
16018#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16019 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16020 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16021 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16032parse_unescaped_encoding(
const pm_parser_t *parser) {
16054parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16055 switch (parser->
current.type) {
16067 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16069 parser_lex(parser);
16087 lex_state_set(parser, PM_LEX_STATE_BEG);
16088 parser_lex(parser);
16094 pm_accepts_block_stack_push(parser,
true);
16096 pm_accepts_block_stack_pop(parser);
16100 lex_state_set(parser, state);
16108 if (statements != NULL && statements->
body.
size == 1) {
16112 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16126 lex_state_set(parser, PM_LEX_STATE_BEG);
16127 parser_lex(parser);
16132 switch (parser->
current.type) {
16136 parser_lex(parser);
16137 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16142 parser_lex(parser);
16143 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16148 parser_lex(parser);
16149 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16154 parser_lex(parser);
16155 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16160 parser_lex(parser);
16161 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16172 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16175 parser_lex(parser);
16176 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16186static const uint8_t *
16187parse_operator_symbol_name(
const pm_token_t *name) {
16188 switch (name->type) {
16191 if (name->end[-1] ==
'@')
return name->end - 1;
16203 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16205 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16206 parser_lex(parser);
16223 if (lex_mode->
mode != PM_LEX_STRING) {
16224 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16226 switch (parser->
current.type) {
16227 case PM_CASE_OPERATOR:
16228 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16237 case PM_CASE_KEYWORD:
16238 parser_lex(parser);
16249 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16257 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16258 parser_lex(parser);
16262 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16266 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16271 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16278 if (part) pm_interpolated_symbol_node_append(symbol, part);
16281 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16282 pm_interpolated_symbol_node_append(symbol, part);
16286 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16288 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16293 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16303 parser_lex(parser);
16318 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16319 pm_interpolated_symbol_node_append(symbol, part);
16322 pm_interpolated_symbol_node_append(symbol, part);
16324 if (next_state != PM_LEX_STATE_NONE) {
16325 lex_state_set(parser, next_state);
16328 parser_lex(parser);
16331 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16336 pm_string_shared_init(&unescaped, content.
start, content.
end);
16339 if (next_state != PM_LEX_STATE_NONE) {
16340 lex_state_set(parser, next_state);
16344 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16349 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16357parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16358 switch (parser->
current.type) {
16359 case PM_CASE_OPERATOR: {
16360 const pm_token_t opening = not_provided(parser);
16361 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16363 case PM_CASE_KEYWORD:
16367 parser_lex(parser);
16374 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16380 parser_lex(parser);
16382 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16385 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16397parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16398 switch (parser->
current.type) {
16399 case PM_CASE_OPERATOR: {
16400 const pm_token_t opening = not_provided(parser);
16401 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16403 case PM_CASE_KEYWORD:
16407 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16408 parser_lex(parser);
16415 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16421 parser_lex(parser);
16423 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16426 parser_lex(parser);
16427 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16429 parser_lex(parser);
16430 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16432 parser_lex(parser);
16433 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16435 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16450 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16451 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16455 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16456 if (is_numbered_param) {
16461 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16462 for (uint8_t number = 1; number <= maximum; number++) {
16463 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16470 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16493 pm_node_t *node = parse_variable(parser);
16494 if (node != NULL)
return node;
16499 pm_node_flag_set((
pm_node_t *)node, flags);
16510parse_method_definition_name(
pm_parser_t *parser) {
16511 switch (parser->
current.type) {
16512 case PM_CASE_KEYWORD:
16515 parser_lex(parser);
16518 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16519 parser_lex(parser);
16521 case PM_CASE_OPERATOR:
16522 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16523 parser_lex(parser);
16532parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16535 pm_string_ensure_owned(
string);
16540 size_t dest_length = pm_string_length(
string);
16541 const uint8_t *source_cursor = (uint8_t *) string->
source;
16542 const uint8_t *source_end = source_cursor + dest_length;
16547 size_t trimmed_whitespace = 0;
16553 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16554 if (*source_cursor ==
'\t') {
16555 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16556 if (trimmed_whitespace > common_whitespace)
break;
16558 trimmed_whitespace++;
16565 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16566 string->length = dest_length;
16576 bool dedent_next =
true;
16581 size_t write_index = 0;
16589 nodes->
nodes[write_index++] = node;
16590 dedent_next =
false;
16596 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16600 pm_node_destroy(parser, node);
16602 nodes->
nodes[write_index++] = node;
16606 dedent_next =
true;
16609 nodes->
size = write_index;
16616parse_strings_empty_content(
const uint8_t *location) {
16626 bool concating =
false;
16634 assert(lex_mode->
mode == PM_LEX_STRING);
16636 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16639 parser_lex(parser);
16661 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16662 }
else if (!lex_interpolation) {
16670 content = not_provided(parser);
16691 pm_token_t delimiters = not_provided(parser);
16692 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16693 pm_node_list_append(&parts, part);
16696 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16697 pm_node_list_append(&parts, part);
16698 parser_lex(parser);
16702 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16704 pm_node_list_free(&parts);
16706 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16707 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16709 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16710 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16712 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16717 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16726 parser_lex(parser);
16729 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16730 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16738 if (location > parser->
start && location[-1] ==
'\n') location--;
16739 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16745 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16746 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16751 pm_token_t string_opening = not_provided(parser);
16752 pm_token_t string_closing = not_provided(parser);
16754 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16755 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16756 pm_node_list_append(&parts, part);
16759 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16760 pm_node_list_append(&parts, part);
16765 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16766 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16768 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16769 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16772 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16775 pm_node_list_free(&parts);
16785 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16786 pm_node_list_append(&parts, part);
16791 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16792 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16794 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16795 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16798 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16801 pm_node_list_free(&parts);
16804 if (current == NULL) {
16820 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16830 pm_interpolated_string_node_append(container, current);
16841#define PM_PARSE_PATTERN_SINGLE 0
16842#define PM_PARSE_PATTERN_TOP 1
16843#define PM_PARSE_PATTERN_MULTI 2
16856 if (*location->
start ==
'_')
return;
16858 if (pm_constant_id_list_includes(captures, capture)) {
16859 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16861 pm_constant_id_list_append(captures, capture);
16875 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16894 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16901 parser_lex(parser);
16906 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16917 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16933 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16934 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16949 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16950 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16965 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16966 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16980 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16981 pm_array_pattern_node_requireds_append(pattern_node, inner);
16999 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
17002 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17003 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
17006 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
17007 name = (
pm_node_t *) pm_local_variable_target_node_create(
17009 &PM_LOCATION_TOKEN_VALUE(&identifier),
17011 (uint32_t) (depth == -1 ? 0 : depth)
17016 return pm_splat_node_create(parser, &
operator, name);
17025 parser_lex(parser);
17031 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17038 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17042 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17043 value = (
pm_node_t *) pm_local_variable_target_node_create(
17045 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17047 (uint32_t) (depth == -1 ? 0 : depth)
17051 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17059pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17060 ptrdiff_t length = end - start;
17061 if (length == 0)
return false;
17064 size_t width = char_is_identifier_start(parser, start, end - start);
17065 if (width == 0)
return false;
17071 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17076 const uint8_t *cursor = start + width;
17077 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17078 return cursor == end;
17092 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17093 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17095 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17097 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17098 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);
17103 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17106 parse_pattern_capture(parser, captures, constant_id, value_loc);
17111 (uint32_t) (depth == -1 ? 0 : depth)
17124 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17143 if (pm_symbol_node_label_p(first_node)) {
17144 parse_pattern_hash_key(parser, &keys, first_node);
17150 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17154 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17158 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17160 pm_node_list_append(&assocs, assoc);
17170 pm_parser_err_node(parser, first_node, diag_id);
17174 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17176 pm_node_list_append(&assocs, assoc);
17186 if (rest != NULL) {
17187 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17194 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17196 if (rest == NULL) {
17199 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17200 pm_node_list_append(&assocs, assoc);
17206 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17209 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17210 }
else if (!pm_symbol_node_label_p(key)) {
17211 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17214 expect1(parser,
PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17218 parse_pattern_hash_key(parser, &keys, key);
17222 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17224 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17228 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17230 if (rest != NULL) {
17231 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17234 pm_node_list_append(&assocs, assoc);
17241 pm_static_literals_free(&keys);
17250 switch (parser->
current.type) {
17253 parser_lex(parser);
17257 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17261 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17262 return (
pm_node_t *) pm_local_variable_target_node_create(
17264 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17266 (uint32_t) (depth == -1 ? 0 : depth)
17271 parser_lex(parser);
17276 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17281 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17294 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17295 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17308 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17309 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17321 pm_array_pattern_node_requireds_append(node, inner);
17330 parser_lex(parser);
17335 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17339 switch (parser->
current.type) {
17341 parser_lex(parser);
17342 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17345 first_node = parse_pattern_keyword_rest(parser, captures);
17348 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17352 parser_lex(parser);
17359 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17368 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17369 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17378 parser_lex(parser);
17382 switch (parser->
current.type) {
17383 case PM_CASE_PRIMITIVE: {
17384 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17385 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17388 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17389 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17390 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17394 case PM_CASE_PRIMITIVE: {
17395 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17398 if (pm_symbol_node_label_p(node))
return node;
17407 switch (parser->
current.type) {
17408 case PM_CASE_PRIMITIVE: {
17409 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17410 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17413 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17420 parser_lex(parser);
17425 switch (parser->
current.type) {
17427 parser_lex(parser);
17430 if (variable == NULL) {
17431 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17432 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17435 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17438 parser_lex(parser);
17441 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17444 parser_lex(parser);
17447 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17450 parser_lex(parser);
17453 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17456 parser_lex(parser);
17459 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17462 parser_lex(parser);
17465 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17472 parser_lex(parser);
17474 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17479 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17484 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17485 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17486 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17492 parser_lex(parser);
17497 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17501 parser_lex(parser);
17504 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17507 pm_parser_err_current(parser, diag_id);
17523 switch (parser->
current.type) {
17532 case PM_CASE_PRIMITIVE: {
17533 if (node == NULL) {
17534 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17536 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17537 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17545 parser_lex(parser);
17547 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17552 if (node == NULL) {
17555 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17561 pm_parser_err_current(parser, diag_id);
17564 if (node == NULL) {
17567 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17584 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17588 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17591 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17593 (uint32_t) (depth == -1 ? 0 : depth)
17596 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17609 bool leading_rest =
false;
17610 bool trailing_rest =
false;
17612 switch (parser->
current.type) {
17614 parser_lex(parser);
17616 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17618 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17619 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17625 node = parse_pattern_keyword_rest(parser, captures);
17626 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17628 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17629 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17637 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17639 if (pm_symbol_node_label_p(node)) {
17640 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17642 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17643 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17649 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17653 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17654 parser_lex(parser);
17655 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17656 leading_rest =
true;
17662 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17668 if (pm_symbol_node_label_p(node)) {
17669 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17672 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser,
PM_TOKEN_COMMA)) {
17677 pm_node_list_append(&nodes, node);
17684 pm_node_list_append(&nodes, node);
17685 trailing_rest =
true;
17690 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17695 if (trailing_rest) {
17696 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17699 trailing_rest =
true;
17701 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17704 pm_node_list_append(&nodes, node);
17712 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17714 if (nodes.
size == 2) {
17715 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17718 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17720 if (leading_rest && trailing_rest) {
17721 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17726 }
else if (leading_rest) {
17729 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17741parse_negative_numeric(
pm_node_t *node) {
17766 assert(
false &&
"unreachable");
17779 case PM_ERR_HASH_KEY: {
17783 case PM_ERR_HASH_VALUE:
17784 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17788 case PM_ERR_UNARY_RECEIVER: {
17793 case PM_ERR_UNARY_DISALLOWED:
17794 case PM_ERR_EXPECT_ARGUMENT: {
17799 pm_parser_err_previous(parser, diag_id);
17809#define CONTEXT_NONE 0
17810#define CONTEXT_THROUGH_ENSURE 1
17811#define CONTEXT_THROUGH_ELSE 2
17814 int context = CONTEXT_NONE;
17816 while (context_node != NULL) {
17817 switch (context_node->
context) {
17838 if (context == CONTEXT_NONE) {
17839 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17840 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17841 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17842 }
else if (context == CONTEXT_THROUGH_ELSE) {
17843 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17855 context = CONTEXT_THROUGH_ELSE;
17866 context = CONTEXT_THROUGH_ENSURE;
17870 assert(
false &&
"unreachable");
17900 context_node = context_node->
prev;
17904#undef CONTEXT_ENSURE
17915 while (context_node != NULL) {
17916 switch (context_node->
context) {
17941 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17945 assert(
false &&
"unreachable");
17986 context_node = context_node->
prev;
18018parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18022 if (callback_data->
shared) {
18028 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18041 .shared = unescaped->
type == PM_STRING_SHARED
18051parse_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) {
18052 switch (parser->
current.type) {
18054 parser_lex(parser);
18057 pm_accepts_block_stack_push(parser,
true);
18058 bool parsed_bare_hash =
false;
18074 if (accepted_newline) {
18075 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18100 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18102 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18105 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18107 if (parsed_bare_hash) {
18108 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18111 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18115 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18118 pm_static_literals_free(&hash_keys);
18119 parsed_bare_hash =
true;
18121 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18124 if (parsed_bare_hash) {
18125 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18130 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18136 operator = not_provided(parser);
18139 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18140 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18141 pm_keyword_hash_node_elements_append(hash, assoc);
18145 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18148 pm_static_literals_free(&hash_keys);
18149 parsed_bare_hash =
true;
18153 pm_array_node_elements_append(array, element);
18165 pm_array_node_close_set(array, &parser->
previous);
18166 pm_accepts_block_stack_pop(parser);
18175 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18177 parser_lex(parser);
18185 pop_block_exits(parser, previous_block_exits);
18186 pm_node_list_free(¤t_block_exits);
18188 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous);
18193 pm_accepts_block_stack_push(parser,
true);
18195 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18196 context_pop(parser);
18202 if (terminator_found) {
18211 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18214 parser_lex(parser);
18215 pm_accepts_block_stack_pop(parser);
18217 pop_block_exits(parser, previous_block_exits);
18218 pm_node_list_free(¤t_block_exits);
18229 multi_target = pm_multi_target_node_create(parser);
18230 pm_multi_target_node_targets_append(parser, multi_target, statement);
18233 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18242 if (match1(parser,
PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18243 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18255 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18258 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18263 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18273 pm_statements_node_body_append(parser, statements, statement,
true);
18283 pm_statements_node_body_append(parser, statements, statement,
true);
18287 if (!terminator_found && !match1(parser,
PM_TOKEN_EOF)) {
18293 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18294 pm_statements_node_body_append(parser, statements, node,
true);
18323 context_pop(parser);
18324 pm_accepts_block_stack_pop(parser);
18336 pm_multi_target_node_targets_append(parser, multi_target, statement);
18338 statement = (
pm_node_t *) multi_target;
18350 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18354 pop_block_exits(parser, previous_block_exits);
18355 pm_node_list_free(¤t_block_exits);
18357 pm_void_statements_check(parser, statements,
true);
18371 pm_accepts_block_stack_push(parser,
true);
18372 parser_lex(parser);
18377 if (current_hash_keys != NULL) {
18378 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18381 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18382 pm_static_literals_free(&hash_keys);
18388 pm_accepts_block_stack_pop(parser);
18390 pm_hash_node_closing_loc_set(node, &parser->
previous);
18395 parser_lex(parser);
18406 pm_node_t *node = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18407 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18412 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18418 parser_lex(parser);
18421 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18422 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18428 parser_lex(parser);
18440 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18441 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18446 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18449 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18455 parser_lex(parser);
18461 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18462 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18470 parser_lex(parser);
18472 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));
18479 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18482 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18485 parser_lex(parser);
18488 parser_lex(parser);
18489 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18491 parser_lex(parser);
18494 parser_lex(parser);
18495 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18497 parser_lex(parser);
18500 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18501 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18507 parser_lex(parser);
18510 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18511 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18517 parser_lex(parser);
18520 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18521 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18528 parser_lex(parser);
18530 pm_node_t *node = parse_variable_call(parser);
18540 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18550 if (arguments.
block != NULL) {
18572 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18573 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18579 parse_target_implicit_parameter(parser, node);
18587 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18588 parse_target_implicit_parameter(parser, node);
18591 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18595 pm_node_destroy(parser, node);
18600 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18601 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18612 size_t common_whitespace = (size_t) -1;
18615 parser_lex(parser);
18627 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18634 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18647 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18650 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18654 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18659 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18660 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18670 pm_node_list_append(&parts, part);
18673 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18674 pm_node_list_append(&parts, part);
18680 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18682 cast->
parts = parts;
18685 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18691 pm_node_list_free(&parts);
18694 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18702 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18704 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18710 parse_heredoc_dedent(parser, nodes, common_whitespace);
18715 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18721 parser_lex(parser);
18724 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18725 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18732 parser_lex(parser);
18737 parser_lex(parser);
18738 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18742 parser_lex(parser);
18743 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18747 parser_lex(parser);
18748 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18751 parser_lex(parser);
18752 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18754 parser_lex(parser);
18757 parser_lex(parser);
18760 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18761 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18764 parser_lex(parser);
18767 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18768 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18776 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18779 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18782 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18787 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18792 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18796 size_t opening_newline_index = token_newline_index(parser);
18797 parser_lex(parser);
18803 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18810 }
else if (!token_begins_expression_p(parser->
current.type)) {
18813 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18818 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18819 parser_lex(parser);
18821 pop_block_exits(parser, previous_block_exits);
18822 pm_node_list_free(¤t_block_exits);
18824 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18825 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18830 pm_token_t end_keyword = not_provided(parser);
18834 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18841 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18842 parser_lex(parser);
18845 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18850 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18852 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18853 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18857 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18858 pm_when_node_conditions_append(when_node, condition);
18869 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18872 pm_when_clause_static_literals_add(parser, &literals, condition);
18878 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18882 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18887 if (statements != NULL) {
18888 pm_when_node_statements_set(when_node, statements);
18892 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18898 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18901 pm_static_literals_free(&literals);
18904 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18908 if (predicate == NULL) {
18909 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18916 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18921 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18923 parser_lex(parser);
18928 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));
18931 pm_constant_id_list_free(&captures);
18938 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18939 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
18942 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18943 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
18954 then_keyword = not_provided(parser);
18972 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
18973 pm_case_match_node_condition_append(case_node, condition);
18979 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18991 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18993 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18997 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
19003 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
19012 pop_block_exits(parser, previous_block_exits);
19013 pm_node_list_free(¤t_block_exits);
19018 size_t opening_newline_index = token_newline_index(parser);
19019 parser_lex(parser);
19025 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19029 pm_accepts_block_stack_push(parser,
true);
19030 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19031 pm_accepts_block_stack_pop(parser);
19035 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19036 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19040 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19042 pop_block_exits(parser, previous_block_exits);
19043 pm_node_list_free(¤t_block_exits);
19049 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19051 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19052 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19055 parser_lex(parser);
19065 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19068 flush_block_exits(parser, previous_block_exits);
19069 pm_node_list_free(¤t_block_exits);
19071 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19076 parser_lex(parser);
19082 token_begins_expression_p(parser->
current.type) ||
19085 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19087 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19088 parse_arguments(parser, &arguments,
false,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
19092 switch (keyword.
type) {
19105 parse_return(parser, node);
19109 assert(
false &&
"unreachable");
19114 parser_lex(parser);
19118 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19125 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19128 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19131 parser_lex(parser);
19135 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19141 if (arguments.
block != NULL) {
19142 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19143 pm_node_destroy(parser, arguments.
block);
19144 arguments.
block = NULL;
19153 size_t opening_newline_index = token_newline_index(parser);
19154 parser_lex(parser);
19157 pm_do_loop_stack_push(parser,
false);
19160 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19164 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));
19166 pm_parser_scope_push(parser,
true);
19173 pm_accepts_block_stack_push(parser,
true);
19175 pm_accepts_block_stack_pop(parser);
19180 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));
19182 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19190 pm_parser_scope_pop(parser);
19191 pm_do_loop_stack_pop(parser);
19193 flush_block_exits(parser, previous_block_exits);
19194 pm_node_list_free(¤t_block_exits);
19196 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19199 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19202 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19209 inheritance_operator = parser->
current;
19210 lex_state_set(parser, PM_LEX_STATE_BEG);
19213 parser_lex(parser);
19215 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19217 inheritance_operator = not_provided(parser);
19221 pm_parser_scope_push(parser,
true);
19231 pm_accepts_block_stack_push(parser,
true);
19233 pm_accepts_block_stack_pop(parser);
19238 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));
19240 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19245 if (context_def_p(parser)) {
19246 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19252 pm_parser_scope_pop(parser);
19253 pm_do_loop_stack_pop(parser);
19256 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19259 pop_block_exits(parser, previous_block_exits);
19260 pm_node_list_free(¤t_block_exits);
19262 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19266 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19269 size_t opening_newline_index = token_newline_index(parser);
19279 parser_lex(parser);
19283 bool valid_name =
true;
19285 switch (parser->
current.type) {
19286 case PM_CASE_OPERATOR:
19287 pm_parser_scope_push(parser,
true);
19288 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19289 parser_lex(parser);
19294 parser_lex(parser);
19297 receiver = parse_variable_call(parser);
19299 pm_parser_scope_push(parser,
true);
19300 lex_state_set(parser, PM_LEX_STATE_FNAME);
19301 parser_lex(parser);
19304 name = parse_method_definition_name(parser);
19307 pm_parser_scope_push(parser,
true);
19317 valid_name =
false;
19327 pm_parser_scope_push(parser,
true);
19328 parser_lex(parser);
19333 lex_state_set(parser, PM_LEX_STATE_FNAME);
19334 parser_lex(parser);
19337 switch (identifier.
type) {
19339 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19342 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19345 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19348 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19351 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19354 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19357 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19360 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19363 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19366 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19369 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19375 name = parse_method_definition_name(parser);
19390 context_pop(parser);
19391 parser_lex(parser);
19394 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19400 lex_state_set(parser, PM_LEX_STATE_FNAME);
19404 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
19408 pm_parser_scope_push(parser,
true);
19410 name = parse_method_definition_name(parser);
19414 pm_parser_scope_push(parser,
true);
19415 name = parse_method_definition_name(parser);
19423 switch (parser->
current.type) {
19425 parser_lex(parser);
19431 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19434 lex_state_set(parser, PM_LEX_STATE_BEG);
19437 context_pop(parser);
19447 case PM_CASE_PARAMETER: {
19451 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19454 lparen = not_provided(parser);
19455 rparen = not_provided(parser);
19456 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19458 context_pop(parser);
19462 lparen = not_provided(parser);
19463 rparen = not_provided(parser);
19466 context_pop(parser);
19476 if (token_is_setter_name(&name)) {
19477 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19482 pm_do_loop_stack_push(parser,
false);
19483 statements = (
pm_node_t *) pm_statements_node_create(parser);
19485 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));
19492 context_pop(parser);
19494 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19497 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19498 pm_do_loop_stack_pop(parser);
19499 context_pop(parser);
19500 end_keyword = not_provided(parser);
19502 equal = not_provided(parser);
19505 lex_state_set(parser, PM_LEX_STATE_BEG);
19512 pm_accepts_block_stack_push(parser,
true);
19513 pm_do_loop_stack_push(parser,
false);
19516 pm_accepts_block_stack_push(parser,
true);
19518 pm_accepts_block_stack_pop(parser);
19523 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));
19525 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19528 pm_accepts_block_stack_pop(parser);
19529 pm_do_loop_stack_pop(parser);
19537 pm_parser_scope_pop(parser);
19544 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
19546 flush_block_exits(parser, previous_block_exits);
19547 pm_node_list_free(¤t_block_exits);
19549 return (
pm_node_t *) pm_def_node_create(
19566 parser_lex(parser);
19576 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19579 rparen = not_provided(parser);
19586 lparen = not_provided(parser);
19587 rparen = not_provided(parser);
19588 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19591 context_pop(parser);
19592 return (
pm_node_t *) pm_defined_node_create(
19597 &PM_LOCATION_TOKEN_VALUE(&keyword)
19601 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19602 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19605 parser_lex(parser);
19608 if (context_def_p(parser)) {
19609 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19617 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19620 parser_lex(parser);
19623 size_t opening_newline_index = token_newline_index(parser);
19624 parser_lex(parser);
19636 if (token_begins_expression_p(parser->
current.type)) {
19637 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19640 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19641 }
else if (token_begins_expression_p(parser->
current.type)) {
19642 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19644 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19645 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19650 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19652 index = parse_target(parser, index,
false,
false);
19655 context_pop(parser);
19656 pm_do_loop_stack_push(parser,
true);
19661 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19662 pm_do_loop_stack_pop(parser);
19668 do_keyword = not_provided(parser);
19676 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19679 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19682 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19685 if (parser_end_of_line_p(parser)) {
19686 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19689 size_t opening_newline_index = token_newline_index(parser);
19691 parser_lex(parser);
19693 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19695 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19696 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19699 parser_lex(parser);
19701 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19704 pm_node_destroy(parser, name);
19706 pm_undef_node_append(undef, name);
19709 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19710 parser_lex(parser);
19711 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19714 pm_node_destroy(parser, name);
19718 pm_undef_node_append(undef, name);
19725 parser_lex(parser);
19737 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous);
19739 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19740 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19749 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19752 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19755 size_t opening_newline_index = token_newline_index(parser);
19756 parser_lex(parser);
19758 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19762 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19764 size_t opening_newline_index = token_newline_index(parser);
19765 parser_lex(parser);
19768 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19774 pop_block_exits(parser, previous_block_exits);
19775 pm_node_list_free(¤t_block_exits);
19778 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19785 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19793 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19796 pm_parser_scope_push(parser,
true);
19801 pm_accepts_block_stack_push(parser,
true);
19803 pm_accepts_block_stack_pop(parser);
19808 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));
19810 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19816 pm_parser_scope_pop(parser);
19819 if (context_def_p(parser)) {
19820 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19823 pop_block_exits(parser, previous_block_exits);
19824 pm_node_list_free(¤t_block_exits);
19826 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19829 parser_lex(parser);
19832 parser_lex(parser);
19840 parser_lex(parser);
19843 parse_retry(parser, node);
19848 parser_lex(parser);
19851 parser_lex(parser);
19854 size_t opening_newline_index = token_newline_index(parser);
19857 pm_do_loop_stack_push(parser,
true);
19859 parser_lex(parser);
19861 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19863 pm_do_loop_stack_pop(parser);
19864 context_pop(parser);
19870 do_keyword = not_provided(parser);
19876 pm_accepts_block_stack_push(parser,
true);
19877 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19878 pm_accepts_block_stack_pop(parser);
19882 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19885 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19888 size_t opening_newline_index = token_newline_index(parser);
19891 pm_do_loop_stack_push(parser,
true);
19893 parser_lex(parser);
19895 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19897 pm_do_loop_stack_pop(parser);
19898 context_pop(parser);
19904 do_keyword = not_provided(parser);
19910 pm_accepts_block_stack_push(parser,
true);
19911 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19912 pm_accepts_block_stack_pop(parser);
19916 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19919 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19922 parser_lex(parser);
19933 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19941 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19946 pm_array_node_close_set(array, &closing);
19951 parser_lex(parser);
19960 switch (parser->
current.type) {
19962 if (current == NULL) {
19968 pm_array_node_elements_append(array, current);
19972 parser_lex(parser);
19979 if (current == NULL) {
19983 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
19984 parser_lex(parser);
19990 parser_lex(parser);
20002 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
20003 parser_lex(parser);
20006 pm_interpolated_symbol_node_append(interpolated, first_string);
20007 pm_interpolated_symbol_node_append(interpolated, second_string);
20012 assert(
false &&
"unreachable");
20018 bool start_location_set =
false;
20019 if (current == NULL) {
20025 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20035 pm_interpolated_symbol_node_append(interpolated, current);
20037 start_location_set =
true;
20044 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20046 if (!start_location_set) {
20052 bool start_location_set =
false;
20053 if (current == NULL) {
20059 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20070 pm_interpolated_symbol_node_append(interpolated, current);
20072 start_location_set =
true;
20078 assert(
false &&
"unreachable");
20081 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20083 if (!start_location_set) {
20090 parser_lex(parser);
20097 pm_array_node_elements_append(array, current);
20102 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20107 pm_array_node_close_set(array, &closing);
20112 parser_lex(parser);
20128 pm_array_node_elements_append(array,
string);
20136 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20142 pm_array_node_close_set(array, &closing);
20146 parser_lex(parser);
20155 switch (parser->
current.type) {
20161 if (current == NULL) {
20168 pm_array_node_elements_append(array, current);
20172 parser_lex(parser);
20180 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20181 parser_lex(parser);
20183 if (current == NULL) {
20200 pm_interpolated_string_node_append(interpolated, current);
20201 pm_interpolated_string_node_append(interpolated,
string);
20204 assert(
false &&
"unreachable");
20210 if (current == NULL) {
20217 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20226 pm_interpolated_string_node_append(interpolated, current);
20234 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20239 if (current == NULL) {
20246 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20255 pm_interpolated_string_node_append(interpolated, current);
20262 assert(
false &&
"unreachable");
20265 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20271 parser_lex(parser);
20278 pm_array_node_elements_append(array, current);
20283 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20289 pm_array_node_close_set(array, &closing);
20294 parser_lex(parser);
20306 parser_lex(parser);
20324 parser_lex(parser);
20337 parse_regular_expression_errors(parser, node);
20340 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20346 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20359 pm_interpolated_regular_expression_node_append(interpolated, part);
20364 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20371 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20372 pm_interpolated_regular_expression_node_append(interpolated, part);
20378 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20384 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20389 parser_lex(parser);
20406 parser_lex(parser);
20407 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20419 parser_lex(parser);
20422 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20423 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20424 parser_lex(parser);
20430 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20436 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20438 pm_interpolated_xstring_node_append(node, part);
20443 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20448 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20449 pm_interpolated_xstring_node_append(node, part);
20455 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20460 pm_interpolated_xstring_node_closing_set(node, &closing);
20465 parser_lex(parser);
20470 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20471 pm_parser_err_prefix(parser, diag_id);
20478 if (token_begins_expression_p(parser->
current.type)) {
20479 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20485 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20487 return parse_target_validate(parser, splat,
true);
20491 if (binding_power > PM_BINDING_POWER_UNARY) {
20492 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20495 parser_lex(parser);
20498 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));
20499 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20501 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20505 if (binding_power > PM_BINDING_POWER_UNARY) {
20506 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20508 parser_lex(parser);
20511 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20512 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20517 if (binding_power > PM_BINDING_POWER_UNARY) {
20518 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20520 parser_lex(parser);
20523 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20524 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20529 parser_lex(parser);
20532 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20536 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20537 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20538 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20545 parse_negative_numeric(node);
20548 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20559 size_t opening_newline_index = token_newline_index(parser);
20560 pm_accepts_block_stack_push(parser,
true);
20561 parser_lex(parser);
20564 pm_parser_scope_push(parser,
false);
20568 switch (parser->
current.type) {
20571 parser_lex(parser);
20574 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20576 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20582 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20585 case PM_CASE_PARAMETER: {
20586 pm_accepts_block_stack_push(parser,
false);
20588 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20589 pm_accepts_block_stack_pop(parser);
20593 block_parameters = NULL;
20609 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20616 pm_accepts_block_stack_push(parser,
true);
20618 pm_accepts_block_stack_pop(parser);
20623 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));
20625 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20632 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20635 pm_parser_scope_pop(parser);
20636 pm_accepts_block_stack_pop(parser);
20638 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20641 if (binding_power > PM_BINDING_POWER_UNARY) {
20642 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20644 parser_lex(parser);
20647 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20648 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20653 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20656 parser_lex(parser);
20658 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20669 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20670 pm_parser_err_prefix(parser, diag_id);
20676 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20677 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20683 pm_parser_err_prefix(parser, diag_id);
20701parse_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) {
20702 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));
20710 parser_lex(parser);
20713 context_pop(parser);
20715 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20735 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20740 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20748 parse_assignment_value_local(parser, statement);
20770parse_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) {
20771 bool permitted =
true;
20772 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_USTAR)) permitted =
false;
20774 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));
20775 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20777 parse_assignment_value_local(parser, value);
20778 bool single_value =
true;
20781 single_value =
false;
20786 pm_array_node_elements_append(array, value);
20790 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20792 pm_array_node_elements_append(array, element);
20795 parse_assignment_value_local(parser, element);
20805 parser_lex(parser);
20807 bool accepts_command_call_inner =
false;
20814 accepts_command_call_inner =
true;
20819 context_pop(parser);
20821 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20837 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20842 if (call_node->
block != NULL) {
20843 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20845 call_node->
block = NULL;
20874static inline const uint8_t *
20875pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20878 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20879 uint8_t value = escape_hexadecimal_digit(*cursor);
20882 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20883 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20887 pm_buffer_append_byte(unescaped, value);
20889 pm_buffer_append_string(unescaped,
"\\x", 2);
20895static inline const uint8_t *
20896pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20897 uint8_t value = (uint8_t) (*cursor -
'0');
20900 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20901 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20904 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20905 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20910 pm_buffer_append_byte(unescaped, value);
20914static inline const uint8_t *
20915pm_named_capture_escape_unicode(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20916 const uint8_t *start = cursor - 1;
20919 if (cursor >= end) {
20920 pm_buffer_append_string(unescaped,
"\\u", 2);
20924 if (*cursor !=
'{') {
20925 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20926 uint32_t value = escape_unicode(parser, cursor, length);
20928 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20929 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20932 return cursor + length;
20937 while (cursor < end && *cursor ==
' ') cursor++;
20939 if (cursor >= end)
break;
20940 if (*cursor ==
'}') {
20945 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20946 uint32_t value = escape_unicode(parser, cursor, length);
20948 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20956pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor) {
20957 const uint8_t *end = source + length;
20958 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20961 if (++cursor >= end) {
20962 pm_buffer_append_byte(unescaped,
'\\');
20968 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20970 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20971 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20974 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
20977 pm_buffer_append_byte(unescaped,
'\\');
20981 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
20982 if (next_cursor == NULL)
break;
20984 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20985 cursor = next_cursor;
20988 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20996parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
21003 const uint8_t *source = pm_string_source(capture);
21004 size_t length = pm_string_length(capture);
21017 pm_named_capture_escape(parser, &unescaped, source, length, cursor);
21018 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21019 length = pm_buffer_length(&unescaped);
21027 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21028 pm_buffer_free(&unescaped);
21032 if (callback_data->
shared) {
21036 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
21042 void *memory =
xmalloc(length);
21043 if (memory == NULL) abort();
21045 memcpy(memory, source, length);
21046 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
21051 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21052 pm_constant_id_list_append(names, name);
21055 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21058 if (pm_local_is_keyword((
const char *) source, length)) {
21059 pm_buffer_free(&unescaped);
21065 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
21070 if (callback_data->
match == NULL) {
21071 callback_data->
match = pm_match_write_node_create(parser, call);
21076 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
21077 pm_node_list_append(&callback_data->
match->
targets, target);
21080 pm_buffer_free(&unescaped);
21093 .shared = content->
type == PM_STRING_SHARED
21100 .shared = content->
type == PM_STRING_SHARED
21103 pm_regexp_parse(parser, pm_string_source(content), pm_string_length(content), extended_mode, parse_regular_expression_named_capture, &callback_data, parse_regular_expression_error, &error_data);
21104 pm_constant_id_list_free(&callback_data.
names);
21106 if (callback_data.
match != NULL) {
21114parse_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) {
21117 switch (token.type) {
21131 case PM_CASE_WRITABLE: {
21132 parser_lex(parser);
21133 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));
21136 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21139 return parse_write(parser, node, &token, value);
21143 pm_multi_target_node_targets_append(parser, multi_target, node);
21145 parser_lex(parser);
21146 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));
21147 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
21158 parser_lex(parser);
21159 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));
21160 return parse_unwriteable_write(parser, node, &token, value);
21166 parser_lex(parser);
21167 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21175 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21178 parser_lex(parser);
21180 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));
21181 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21183 pm_node_destroy(parser, node);
21187 parser_lex(parser);
21189 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));
21192 pm_node_destroy(parser, node);
21196 parser_lex(parser);
21198 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));
21201 return parse_shareable_constant_write(parser, write);
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_AMPAMPEQ, (uint16_t) (depth + 1));
21209 pm_node_destroy(parser, node);
21210 return parse_shareable_constant_write(parser, write);
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_AMPAMPEQ, (uint16_t) (depth + 1));
21218 pm_node_destroy(parser, node);
21223 parser_lex(parser);
21225 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));
21226 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
21228 parse_target_implicit_parameter(parser, node);
21229 pm_node_destroy(parser, node);
21235 parse_target_implicit_parameter(parser, node);
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_AMPAMPEQ, (uint16_t) (depth + 1));
21244 pm_node_destroy(parser, node);
21255 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21258 parser_lex(parser);
21260 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));
21261 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21263 pm_node_destroy(parser, (
pm_node_t *) cast);
21269 parser_lex(parser);
21275 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));
21276 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21280 if (pm_call_node_writable_p(parser, cast)) {
21281 parse_write_name(parser, &cast->
name);
21283 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21286 parse_call_operator_write(parser, cast, &token);
21287 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));
21288 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21291 parser_lex(parser);
21292 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21296 parser_lex(parser);
21301 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21309 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21312 parser_lex(parser);
21314 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));
21315 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21317 pm_node_destroy(parser, node);
21321 parser_lex(parser);
21323 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));
21326 pm_node_destroy(parser, node);
21330 parser_lex(parser);
21332 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));
21335 return parse_shareable_constant_write(parser, write);
21338 parser_lex(parser);
21340 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));
21343 pm_node_destroy(parser, node);
21344 return parse_shareable_constant_write(parser, write);
21347 parser_lex(parser);
21349 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));
21352 pm_node_destroy(parser, node);
21357 parser_lex(parser);
21359 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));
21360 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
21362 parse_target_implicit_parameter(parser, node);
21363 pm_node_destroy(parser, node);
21369 parse_target_implicit_parameter(parser, node);
21373 parser_lex(parser);
21375 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));
21378 pm_node_destroy(parser, node);
21389 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21392 parser_lex(parser);
21394 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));
21395 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21397 pm_node_destroy(parser, (
pm_node_t *) cast);
21403 parser_lex(parser);
21409 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));
21410 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21414 if (pm_call_node_writable_p(parser, cast)) {
21415 parse_write_name(parser, &cast->
name);
21417 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21420 parse_call_operator_write(parser, cast, &token);
21421 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));
21422 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21425 parser_lex(parser);
21426 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21430 parser_lex(parser);
21435 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21453 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21456 parser_lex(parser);
21458 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));
21459 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21461 pm_node_destroy(parser, node);
21465 parser_lex(parser);
21467 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));
21470 pm_node_destroy(parser, node);
21474 parser_lex(parser);
21476 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));
21479 return parse_shareable_constant_write(parser, write);
21482 parser_lex(parser);
21484 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));
21487 pm_node_destroy(parser, node);
21488 return parse_shareable_constant_write(parser, write);
21491 parser_lex(parser);
21493 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));
21496 pm_node_destroy(parser, node);
21501 parser_lex(parser);
21503 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));
21504 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
21506 parse_target_implicit_parameter(parser, node);
21507 pm_node_destroy(parser, node);
21513 parse_target_implicit_parameter(parser, node);
21517 parser_lex(parser);
21519 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));
21520 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21522 pm_node_destroy(parser, node);
21526 parser_lex(parser);
21534 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21537 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));
21538 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21540 pm_node_destroy(parser, (
pm_node_t *) cast);
21548 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));
21549 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21553 if (pm_call_node_writable_p(parser, cast)) {
21554 parse_write_name(parser, &cast->
name);
21556 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21559 parse_call_operator_write(parser, cast, &token);
21560 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));
21561 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21564 parser_lex(parser);
21565 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21569 parser_lex(parser);
21580 parser_lex(parser);
21583 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21587 parser_lex(parser);
21590 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21600 parser_lex(parser);
21601 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21604 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21617 bool interpolated =
false;
21618 size_t total_length = 0;
21623 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21625 interpolated =
true;
21630 if (!interpolated && total_length > 0) {
21631 void *memory =
xmalloc(total_length);
21632 if (!memory) abort();
21634 uint8_t *cursor = memory;
21637 size_t length = pm_string_length(unescaped);
21639 memcpy(cursor, pm_string_source(unescaped), length);
21644 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21647 pm_string_free(&owned);
21679 parser_lex(parser);
21685 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21692 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21699 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21707 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21708 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21715 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21718 parser_lex(parser);
21719 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21720 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21724 parser_lex(parser);
21730 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21731 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21738 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21745 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21752 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21762 switch (parser->
current.type) {
21763 case PM_CASE_OPERATOR:
21764 case PM_CASE_KEYWORD:
21768 parser_lex(parser);
21778 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21779 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21782 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21787 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21794 parser_lex(parser);
21797 if (token_begins_expression_p(parser->
current.type)) {
21798 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21801 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21805 parser_lex(parser);
21807 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21808 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21812 parser_lex(parser);
21814 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21815 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21818 parser_lex(parser);
21820 pm_statements_node_body_append(parser, statements, node,
true);
21822 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21826 parser_lex(parser);
21828 pm_statements_node_body_append(parser, statements, node,
true);
21830 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21836 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21839 parser_lex(parser);
21841 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21853 context_pop(parser);
21854 pop_block_exits(parser, previous_block_exits);
21855 pm_node_list_free(¤t_block_exits);
21857 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21864 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21866 context_pop(parser);
21867 pop_block_exits(parser, previous_block_exits);
21868 pm_node_list_free(¤t_block_exits);
21870 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21873 parser_lex(parser);
21876 switch (parser->
current.type) {
21878 parser_lex(parser);
21894 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21895 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21898 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21902 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21903 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21908 case PM_CASE_OPERATOR:
21909 case PM_CASE_KEYWORD:
21912 parser_lex(parser);
21918 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21919 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21922 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21923 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21932 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21934 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
21938 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21944 parser_lex(parser);
21947 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21948 context_pop(parser);
21950 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
21953 parser_lex(parser);
21959 pm_accepts_block_stack_push(parser,
true);
21961 pm_accepts_block_stack_pop(parser);
21969 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21970 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21971 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21979 block = parse_block(parser, (uint16_t) (depth + 1));
21980 pm_arguments_validate_block(parser, &arguments, block);
21982 block = parse_block(parser, (uint16_t) (depth + 1));
21985 if (block != NULL) {
21986 if (arguments.
block != NULL) {
21987 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
21989 arguments.
arguments = pm_arguments_node_create(parser);
21991 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21997 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
22005 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22006 parser_lex(parser);
22009 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));
22012 pm_constant_id_list_free(&captures);
22014 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
22022 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22023 parser_lex(parser);
22026 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));
22029 pm_constant_id_list_free(&captures);
22031 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
22034 assert(
false &&
"unreachable");
22039#undef PM_PARSE_PATTERN_SINGLE
22040#undef PM_PARSE_PATTERN_TOP
22041#undef PM_PARSE_PATTERN_MULTI
22065parse_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) {
22067 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22071 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
22086 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22096 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
22104 if (pm_symbol_node_label_p(node)) {
22118 current_token_type = parser->
current.type,
22119 current_binding_powers = pm_binding_powers[current_token_type],
22120 binding_power <= current_binding_powers.
left &&
22121 current_binding_powers.
binary
22123 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
22129 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22141 if (
PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22149 if (
PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22159 if (current_binding_powers.
nonassoc) {
22162 if (match1(parser, current_token_type)) {
22180 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
22183 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
22188 if (accepts_command_call) {
22197 switch (node->
type) {
22212 cast->
block == NULL &&
22225 accepts_command_call =
false;
22233 accepts_command_call =
false;
22248 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22249 if (statements == NULL) {
22250 statements = pm_statements_node_create(parser);
22254 pm_arguments_node_arguments_append(
22256 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22259 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22262 pm_parser_constant_id_constant(parser,
"print", 5)
22266 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22267 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22268 if (statements == NULL) {
22269 statements = pm_statements_node_create(parser);
22273 pm_arguments_node_arguments_append(
22275 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22278 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22279 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22283 pm_parser_constant_id_constant(parser,
"$F", 2),
22287 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22291 pm_arguments_node_arguments_append(
22293 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22296 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22298 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22300 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22302 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22305 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22310 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22312 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22316 statements = wrapped_statements;
22331 pm_parser_scope_push(parser,
true);
22335 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22337 parser_lex(parser);
22344 assert(statements->
body.
size > 0);
22345 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22350 pm_parser_scope_pop(parser);
22355 statements = wrap_statements(parser, statements);
22357 flush_block_exits(parser, previous_block_exits);
22358 pm_node_list_free(¤t_block_exits);
22364 if (statements == NULL) {
22365 statements = pm_statements_node_create(parser);
22366 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22369 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22386pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22387 size_t little_length = strlen(little);
22389 for (
const char *big_end = big + big_length; big < big_end; big++) {
22390 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22397#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22405pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22406 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22407 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22418 const char *switches = pm_strnstr(engine,
" -", length);
22419 if (switches == NULL)
return;
22424 (
const uint8_t *) (switches + 1),
22425 length - ((
size_t) (switches - engine)) - 1,
22429 size_t encoding_length;
22430 if ((encoding_length = pm_string_length(&next_options.
encoding)) > 0) {
22431 const uint8_t *encoding_source = pm_string_source(&next_options.
encoding);
22432 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22444 assert(source != NULL);
22448 .lex_state = PM_LEX_STATE_BEG,
22449 .enclosure_nesting = 0,
22450 .lambda_enclosure_nesting = -1,
22451 .brace_nesting = 0,
22452 .do_loop_stack = 0,
22453 .accepts_block_stack = 0,
22456 .stack = {{ .mode = PM_LEX_DEFAULT }},
22460 .end = source + size,
22461 .previous = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22462 .current = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22463 .next_start = NULL,
22464 .heredoc_end = NULL,
22465 .data_loc = { .start = NULL, .end = NULL },
22466 .comment_list = { 0 },
22467 .magic_comment_list = { 0 },
22468 .warning_list = { 0 },
22469 .error_list = { 0 },
22470 .current_scope = NULL,
22471 .current_context = NULL,
22473 .encoding_changed_callback = NULL,
22474 .encoding_comment_start = source,
22475 .lex_callback = NULL,
22477 .constant_pool = { 0 },
22478 .newline_list = { 0 },
22482 .explicit_encoding = NULL,
22484 .parsing_eval =
false,
22485 .partial_script =
false,
22486 .command_start =
true,
22487 .recovering =
false,
22488 .encoding_locked =
false,
22489 .encoding_changed =
false,
22490 .pattern_matching_newlines =
false,
22491 .in_keyword_arg =
false,
22492 .current_block_exits = NULL,
22493 .semantic_token_seen =
false,
22495 .current_regular_expression_ascii_only =
false,
22496 .warn_mismatched_indentation =
true
22513 uint32_t constant_size = ((uint32_t) size) / 95;
22514 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22519 size_t newline_size = size / 22;
22520 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22523 if (options != NULL) {
22531 size_t encoding_length = pm_string_length(&options->
encoding);
22532 if (encoding_length > 0) {
22533 const uint8_t *encoding_source = pm_string_source(&options->
encoding);
22534 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22556 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22558 pm_parser_scope_push(parser, scope_index == 0);
22564 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22565 const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
22567 const uint8_t *source = pm_string_source(local);
22568 size_t length = pm_string_length(local);
22570 void *allocated =
xmalloc(length);
22571 if (allocated == NULL)
continue;
22573 memcpy(allocated, source, length);
22574 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22579 pm_accepts_block_stack_push(parser,
true);
22582 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22595 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22612 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22613 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22615 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22616 const char *engine;
22618 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22619 if (newline != NULL) {
22623 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22628 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22631 search_shebang =
false;
22633 search_shebang =
true;
22639 if (search_shebang) {
22642 bool found_shebang =
false;
22646 const uint8_t *cursor = parser->
start;
22650 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22652 while (newline != NULL) {
22653 pm_newline_list_append(&parser->
newline_list, newline);
22655 cursor = newline + 1;
22656 newline = next_newline(cursor, parser->
end - cursor);
22658 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22659 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22660 const char *engine;
22661 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22662 found_shebang =
true;
22664 if (newline != NULL) {
22665 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22670 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22678 if (found_shebang) {
22682 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22709 for (node = list->
head; node != NULL; node = next) {
22721pm_magic_comment_list_free(
pm_list_t *list) {
22724 for (node = list->
head; node != NULL; node = next) {
22737 pm_string_free(&parser->
filepath);
22738 pm_diagnostic_list_free(&parser->
error_list);
22750 pm_parser_scope_pop(parser);
22754 lex_mode_pop(parser);
22763 return parse_program(parser);
22773#define LINE_SIZE 4096
22774 char line[LINE_SIZE];
22776 while (memset(line,
'\n', LINE_SIZE), fgets(line, LINE_SIZE, stream) != NULL) {
22777 size_t length = LINE_SIZE;
22778 while (length > 0 && line[length - 1] ==
'\n') length--;
22780 if (length == LINE_SIZE) {
22785 pm_buffer_append_string(buffer, line, length);
22791 pm_buffer_append_string(buffer, line, length);
22799 if (strncmp(line,
"__END__", 7) == 0)
return false;
22802 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22805 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22824pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22827 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22828 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22844 pm_buffer_init(buffer);
22846 bool eof = pm_parse_stream_read(buffer, stream, fgets);
22847 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22851 pm_node_destroy(parser, node);
22852 eof = pm_parse_stream_read(buffer, stream, fgets);
22854 pm_parser_free(parser);
22855 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22856 node = pm_parse(parser);
22866pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22868 pm_options_read(&options, data);
22871 pm_parser_init(&parser, source, size, &options);
22874 pm_node_destroy(&parser, node);
22877 pm_parser_free(&parser);
22878 pm_options_free(&options);
22883#undef PM_CASE_KEYWORD
22884#undef PM_CASE_OPERATOR
22885#undef PM_CASE_WRITABLE
22886#undef PM_STRING_EMPTY
22887#undef PM_LOCATION_NODE_BASE_VALUE
22888#undef PM_LOCATION_NODE_VALUE
22889#undef PM_LOCATION_NULL_VALUE
22890#undef PM_LOCATION_TOKEN_VALUE
22895#ifndef PRISM_EXCLUDE_SERIALIZATION
22899 pm_buffer_append_string(buffer,
"PRISM", 5);
22911 pm_serialize_header(buffer);
22913 pm_buffer_append_byte(buffer,
'\0');
22921pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22923 pm_options_read(&options, data);
22926 pm_parser_init(&parser, source, size, &options);
22930 pm_serialize_header(buffer);
22932 pm_buffer_append_byte(buffer,
'\0');
22934 pm_node_destroy(&parser, node);
22935 pm_parser_free(&parser);
22936 pm_options_free(&options);
22947 pm_options_read(&options, data);
22950 pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, fgets, &options);
22951 pm_serialize_header(buffer);
22953 pm_buffer_append_byte(buffer,
'\0');
22955 pm_node_destroy(&parser, node);
22956 pm_buffer_free(&parser_buffer);
22957 pm_parser_free(&parser);
22958 pm_options_free(&options);
22965pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22967 pm_options_read(&options, data);
22970 pm_parser_init(&parser, source, size, &options);
22973 pm_serialize_header(buffer);
22975 pm_buffer_append_varsint(buffer, parser.
start_line);
22978 pm_node_destroy(&parser, node);
22979 pm_parser_free(&parser);
22980 pm_options_free(&options);
22992 PM_SLICE_TYPE_ERROR = -1,
22995 PM_SLICE_TYPE_NONE,
22998 PM_SLICE_TYPE_LOCAL,
23001 PM_SLICE_TYPE_CONSTANT,
23004 PM_SLICE_TYPE_METHOD_NAME
23011pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23013 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
23014 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
23017 if (length == 0)
return PM_SLICE_TYPE_NONE;
23020 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
23022 }
else if (*source ==
'_') {
23025 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
23029 return PM_SLICE_TYPE_NONE;
23033 const uint8_t *end = source + length;
23034 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
23040 while (source < end) {
23041 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
23044 }
else if (*source ==
'_') {
23047 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
23057 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
23059 result = PM_SLICE_TYPE_METHOD_NAME;
23063 return source == end ? result : PM_SLICE_TYPE_NONE;
23070pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23071 switch (pm_slice_type(source, length, encoding_name)) {
23072 case PM_SLICE_TYPE_ERROR:
23074 case PM_SLICE_TYPE_NONE:
23075 case PM_SLICE_TYPE_CONSTANT:
23076 case PM_SLICE_TYPE_METHOD_NAME:
23078 case PM_SLICE_TYPE_LOCAL:
23082 assert(
false &&
"unreachable");
23090pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23091 switch (pm_slice_type(source, length, encoding_name)) {
23092 case PM_SLICE_TYPE_ERROR:
23094 case PM_SLICE_TYPE_NONE:
23095 case PM_SLICE_TYPE_LOCAL:
23096 case PM_SLICE_TYPE_METHOD_NAME:
23098 case PM_SLICE_TYPE_CONSTANT:
23102 assert(
false &&
"unreachable");
23110pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23111#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
23112#define C1(c) (*source == c)
23113#define C2(s) (memcmp(source, s, 2) == 0)
23114#define C3(s) (memcmp(source, s, 3) == 0)
23116 switch (pm_slice_type(source, length, encoding_name)) {
23117 case PM_SLICE_TYPE_ERROR:
23119 case PM_SLICE_TYPE_NONE:
23121 case PM_SLICE_TYPE_LOCAL:
23123 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
23124 case PM_SLICE_TYPE_CONSTANT:
23126 case PM_SLICE_TYPE_METHOD_NAME:
23133 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
23135 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
23137 return B(C3(
"===") || C3(
"<=>") || C3(
"[]="));
@ PM_RANGE_FLAGS_EXCLUDE_END
... operator
@ PM_DEFINED_NODE
DefinedNode.
@ PM_PRE_EXECUTION_NODE
PreExecutionNode.
@ PM_RETRY_NODE
RetryNode.
@ PM_CONSTANT_PATH_WRITE_NODE
ConstantPathWriteNode.
@ PM_SOURCE_LINE_NODE
SourceLineNode.
@ PM_UNLESS_NODE
UnlessNode.
@ PM_GLOBAL_VARIABLE_READ_NODE
GlobalVariableReadNode.
@ PM_RATIONAL_NODE
RationalNode.
@ PM_FIND_PATTERN_NODE
FindPatternNode.
@ PM_ARRAY_NODE
ArrayNode.
@ PM_CONSTANT_PATH_TARGET_NODE
ConstantPathTargetNode.
@ PM_MULTI_WRITE_NODE
MultiWriteNode.
@ PM_INTERPOLATED_STRING_NODE
InterpolatedStringNode.
@ PM_FALSE_NODE
FalseNode.
@ PM_MATCH_PREDICATE_NODE
MatchPredicateNode.
@ PM_X_STRING_NODE
XStringNode.
@ PM_GLOBAL_VARIABLE_TARGET_NODE
GlobalVariableTargetNode.
@ PM_CONSTANT_TARGET_NODE
ConstantTargetNode.
@ PM_IT_LOCAL_VARIABLE_READ_NODE
ItLocalVariableReadNode.
@ PM_SOURCE_FILE_NODE
SourceFileNode.
@ PM_NO_KEYWORDS_PARAMETER_NODE
NoKeywordsParameterNode.
@ PM_MULTI_TARGET_NODE
MultiTargetNode.
@ PM_SPLAT_NODE
SplatNode.
@ PM_CLASS_VARIABLE_READ_NODE
ClassVariableReadNode.
@ PM_INTERPOLATED_MATCH_LAST_LINE_NODE
InterpolatedMatchLastLineNode.
@ PM_SYMBOL_NODE
SymbolNode.
@ PM_RESCUE_MODIFIER_NODE
RescueModifierNode.
@ PM_ALIAS_METHOD_NODE
AliasMethodNode.
@ PM_MATCH_REQUIRED_NODE
MatchRequiredNode.
@ PM_BACK_REFERENCE_READ_NODE
BackReferenceReadNode.
@ PM_BLOCK_ARGUMENT_NODE
BlockArgumentNode.
@ PM_MISSING_NODE
MissingNode.
@ PM_ASSOC_SPLAT_NODE
AssocSplatNode.
@ PM_RANGE_NODE
RangeNode.
@ PM_LOCAL_VARIABLE_READ_NODE
LocalVariableReadNode.
@ PM_REGULAR_EXPRESSION_NODE
RegularExpressionNode.
@ PM_CONSTANT_WRITE_NODE
ConstantWriteNode.
@ PM_HASH_PATTERN_NODE
HashPatternNode.
@ PM_UNDEF_NODE
UndefNode.
@ PM_ENSURE_NODE
EnsureNode.
@ PM_LOCAL_VARIABLE_WRITE_NODE
LocalVariableWriteNode.
@ PM_KEYWORD_HASH_NODE
KeywordHashNode.
@ PM_PARENTHESES_NODE
ParenthesesNode.
@ PM_CLASS_VARIABLE_WRITE_NODE
ClassVariableWriteNode.
@ PM_POST_EXECUTION_NODE
PostExecutionNode.
@ PM_RETURN_NODE
ReturnNode.
@ PM_ARRAY_PATTERN_NODE
ArrayPatternNode.
@ PM_MATCH_LAST_LINE_NODE
MatchLastLineNode.
@ PM_CONSTANT_PATH_NODE
ConstantPathNode.
@ PM_INTERPOLATED_SYMBOL_NODE
InterpolatedSymbolNode.
@ PM_CLASS_VARIABLE_TARGET_NODE
ClassVariableTargetNode.
@ PM_BREAK_NODE
BreakNode.
@ PM_IMAGINARY_NODE
ImaginaryNode.
@ PM_CONSTANT_READ_NODE
ConstantReadNode.
@ PM_GLOBAL_VARIABLE_WRITE_NODE
GlobalVariableWriteNode.
@ PM_SOURCE_ENCODING_NODE
SourceEncodingNode.
@ PM_BEGIN_NODE
BeginNode.
@ PM_INSTANCE_VARIABLE_READ_NODE
InstanceVariableReadNode.
@ PM_FLIP_FLOP_NODE
FlipFlopNode.
@ PM_INSTANCE_VARIABLE_WRITE_NODE
InstanceVariableWriteNode.
@ PM_INSTANCE_VARIABLE_TARGET_NODE
InstanceVariableTargetNode.
@ PM_FLOAT_NODE
FloatNode.
@ PM_ASSOC_NODE
AssocNode.
@ PM_INTEGER_NODE
IntegerNode.
@ PM_LOCAL_VARIABLE_TARGET_NODE
LocalVariableTargetNode.
@ PM_STRING_NODE
StringNode.
@ PM_ALIAS_GLOBAL_VARIABLE_NODE
AliasGlobalVariableNode.
@ PM_NUMBERED_REFERENCE_READ_NODE
NumberedReferenceReadNode.
@ PM_STATEMENTS_NODE
StatementsNode.
@ PM_BLOCK_NODE
BlockNode.
@ PM_INTERPOLATED_REGULAR_EXPRESSION_NODE
InterpolatedRegularExpressionNode.
static const pm_node_flags_t PM_NODE_FLAG_NEWLINE
We store the flags enum in every node in the tree.
@ PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING
internal bytes forced the encoding to US-ASCII
@ PM_STRING_FLAGS_FROZEN
frozen by virtue of a frozen_string_literal: true comment or --enable-frozen-string-literal
@ PM_STRING_FLAGS_FORCED_BINARY_ENCODING
internal bytes forced the encoding to binary
@ PM_STRING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING
if the arguments contain forwarding
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS
if the arguments contain keywords
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT
if the arguments contain a keyword splat
#define PM_NODE_FLAG_P(node, flag)
Return true if the given flag is set on the given node.
#define PM_NODE_TYPE_P(node, type)
Return true if the type of the given node matches the given type.
#define PM_NODE_TYPE(node)
Cast the type to an enum to allow the compiler to provide exhaustiveness checking.
@ PM_INTEGER_BASE_FLAGS_HEXADECIMAL
0x prefix
@ PM_INTEGER_BASE_FLAGS_OCTAL
0o or 0 prefix
@ PM_INTEGER_BASE_FLAGS_DECIMAL
0d or no prefix
@ PM_INTEGER_BASE_FLAGS_BINARY
0b prefix
enum pm_token_type pm_token_type_t
This enum represents every type of token in the Ruby source.
#define PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
When we're serializing to Java, we want to skip serializing the location fields as they won't be used...
@ PM_CALL_NODE_FLAGS_SAFE_NAVIGATION
&.
@ PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE
a call that is an attribute write, so the value being written should be returned
@ PM_CALL_NODE_FLAGS_VARIABLE_CALL
a call that could have been a local variable
@ PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING
internal bytes forced the encoding to US-ASCII
@ PM_REGULAR_EXPRESSION_FLAGS_EXTENDED
x - ignores whitespace and allows comments in regular expressions
uint16_t pm_node_flags_t
These are the flags embedded in the node struct.
@ PM_TOKEN_DOT_DOT_DOT
the ... range operator or forwarding parameter
@ 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 ... operator
@ 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
pm_diagnostic_id_t
The diagnostic IDs of all of the diagnostics, used to communicate the types of errors between the par...
#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.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
String literals may be frozen or mutable depending on the implementation default.
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
pm_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_scope_parameters_t
The flags about scope parameters that can be set.
uint8_t pm_shareable_constant_value_t
The type of shareable constant value that can be set.
pm_comment_type_t
This is the type of a comment that we've found while parsing.
#define PM_CONSTANT_ID_UNSET
When we allocate constants into the pool, we reserve 0 to mean that the slot is not yet filled.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
#define PM_STRING_EMPTY
Defines an empty string.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_DEPTH_MAXIMUM
When we are parsing using recursive descent, we want to protect against malicious payloads that could...
#define PM_STATIC_ASSERT(line, condition, message)
We want to be able to use static assertions, but they weren't standardized until C11.
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
#define PM_ENCODING_US_ASCII_ENTRY
This is the US-ASCII encoding.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PRISM_ENCODING_ALPHABETIC_BIT
All of the lookup tables use the first bit of each embedded byte to indicate whether the codepoint is...
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
The main header file for the prism parser.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the encoding, metadata, nodes, and constant pool.
char *() pm_parse_stream_fgets_t(char *string, int size, void *stream)
This function is used in pm_parse_stream to retrieve a line of input from a stream.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
void pm_serialize_comment_list(pm_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.
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.
struct pm_statements_node * statements
ElseNode::statements.
This struct defines the functions necessary to implement the encoding interface so we can determine h...
size_t(* alpha_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphab...
size_t(* char_width)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding.
bool(* isupper_char)(const uint8_t *b, ptrdiff_t n)
Return true if the next character is valid in the encoding and is an uppercase character.
const char * name
The name of the encoding.
size_t(* alnum_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphan...
struct pm_statements_node * statements
EnsureNode::statements.
struct pm_node * constant
FindPatternNode::constant.
pm_location_t opening_loc
FindPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
GlobalVariableTargetNode.
struct pm_node_list elements
HashNode::elements.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
HashPatternNode::closing_loc.
struct pm_node * constant
HashPatternNode::constant.
All of the information necessary to store to lexing a heredoc.
size_t ident_length
The length of the heredoc identifier.
pm_heredoc_quote_t quote
The type of quote that the heredoc uses.
pm_heredoc_indent_t indent
The type of indentation that the heredoc uses.
const uint8_t * ident_start
A pointer to the start of the heredoc identifier.
struct pm_statements_node * statements
IfNode::statements.
struct pm_node * subsequent
IfNode::subsequent.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
void(* callback)(void *data, pm_parser_t *parser, pm_token_t *token)
This is the callback that is called when a token is lexed.
void * data
This opaque pointer is used to provide whatever information the user deemed necessary to the callback...
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
enum pm_lex_mode::@91 mode
The type of this lex mode.
uint8_t terminator
This is the terminator of the list literal.
size_t nesting
This keeps track of the nesting level of the list.
bool interpolation
Whether or not interpolation is allowed in this list.
uint8_t incrementor
When lexing a list, it takes into account balancing the terminator if the terminator is one of (),...
uint8_t breakpoints[11]
This is the character set that should be used to delimit the tokens within the list.
pm_heredoc_lex_mode_t base
All of the data necessary to lex a heredoc.
bool line_continuation
True if the previous token ended with a line continuation.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
union pm_lex_mode::@92 as
The data associated with this type of lex mode.
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
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.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
The options that can be passed to the parser.
uint8_t command_line
A bitset of the various options that were set on the command line.
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
bool encoding_locked
Whether or not the encoding magic comments should be respected.
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
pm_string_t encoding
The name of the encoding that the source file is in.
int32_t line
The line within the file that the parse starts on.
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
bool partial_script
When the file being parsed is considered a "partial" script, jumps will not be marked as errors if th...
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
pm_string_t filepath
The name of the file that is currently being parsed.
pm_options_version_t version
The version of prism that we should be parsing with.
struct pm_node * left
OrNode::left.
struct pm_node * right
OrNode::right.
struct pm_node * rest
ParametersNode::rest.
struct pm_block_parameter_node * block
ParametersNode::block.
pm_node_t base
The embedded base node.
struct pm_node * keyword_rest
ParametersNode::keyword_rest.
struct pm_node * body
ParenthesesNode::body.
This struct represents the overall parser.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
pm_lex_state_t lex_state
The current state of the lexer.
uint8_t command_line
The command line flags given from the options.
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool partial_script
Whether or not we are parsing a "partial" script, which is a script that will be evaluated in the con...
bool pattern_matching_newlines
This flag indicates that we are currently parsing a pattern matching expression and impacts that calc...
const uint8_t * end
The pointer to the end of the source.
bool recovering
Whether or not we're currently recovering from a syntax error.
pm_node_flags_t integer_base
We want to add a flag to integer nodes that indicates their base.
bool warn_mismatched_indentation
By default, Ruby always warns about mismatched indentation.
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
bool in_keyword_arg
This flag indicates that we are currently parsing a keyword argument.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
pm_token_t previous
The previous token we were considering.
struct pm_parser::@97 lex_modes
A stack of lex modes.
pm_string_t current_string
This string is used to pass information from the lexer to the parser.
bool parsing_eval
Whether or not we are parsing an eval string.
bool current_regular_expression_ascii_only
True if the current regular expression being lexed contains only ASCII characters.
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
pm_location_t data_loc
An optional location that represents the location of the END marker and the rest of the content of th...
pm_context_node_t * current_context
The current parsing context.
const uint8_t * start
The pointer to the start of the source.
int enclosure_nesting
Tracks the current nesting of (), [], and {}.
pm_list_t error_list
The list of errors that have been found while parsing.
int8_t frozen_string_literal
Whether or not we have found a frozen_string_literal magic comment with a true or false value.
pm_node_list_t * current_block_exits
When parsing block exits (e.g., break, next, redo), we need to validate that they are in correct cont...
const uint8_t * encoding_comment_start
This pointer indicates where a comment must start if it is to be considered an encoding comment.
pm_lex_mode_t stack[PM_LEX_STACK_SIZE]
The stack of lexer modes.
pm_list_t warning_list
The list of warnings that have been found while parsing.
const uint8_t * heredoc_end
This field indicates the end of a heredoc whose identifier was found on the current line.
int brace_nesting
Used to track the nesting of braces to ensure we get the correct value when we are interpolating bloc...
pm_encoding_changed_callback_t encoding_changed_callback
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
int32_t start_line
The line number at the start of the parse.
bool encoding_locked
This is very specialized behavior for when you want to parse in a context that does not respect encod...
pm_lex_mode_t * current
The current mode of the lexer.
pm_list_t comment_list
The list of comments that have been found while parsing.
size_t index
The current index into the lexer mode stack.
pm_string_t filepath
This is the path of the file being parsed.
pm_scope_t * current_scope
The current local scope.
bool command_start
Whether or not we're at the beginning of a command.
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
bool semantic_token_seen
Whether or not the parser has seen a token that has semantic meaning (i.e., a token that is not a com...
uint32_t node_id
The next node identifier that will be assigned.
struct pm_node * right
RangeNode::right.
struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode::unescaped.
struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_node_t base
The embedded base node.
This struct represents a node in a linked list of scopes.
struct pm_scope * previous
A pointer to the previous scope in the linked list.
pm_node_list_t implicit_parameters
This is a list of the implicit parameters contained within the block.
pm_shareable_constant_value_t shareable_constant
The current state of constant shareability for this scope.
pm_locals_t locals
The IDs of the locals in the given scope.
pm_scope_parameters_t parameters
This is a bitfield that indicates the parameters that are being used in this scope.
bool closed
A boolean indicating whether or not this scope can see into its parent.
struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
size_t length
The length of the string in bytes of memory.
enum pm_string_t::@98 type
The type of the string.
pm_location_t value_loc
SymbolNode::value_loc.
pm_string_t unescaped
SymbolNode::unescaped.
When we're lexing certain types (strings, symbols, lists, etc.) we have string content associated wit...
pm_buffer_t buffer
The buffer that we're using to keep track of the string content.
const uint8_t * cursor
The cursor into the source string that points to how far we have currently copied into the buffer.
This struct represents a token in the Ruby source.
const uint8_t * end
A pointer to the end location of the token in the source.
const uint8_t * start
A pointer to the start location of the token in the source.
pm_token_type_t type
The type of the token.
struct pm_statements_node * statements
UnlessNode::statements.
struct pm_else_node * else_clause
UnlessNode::else_clause.