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) {
1657 }
else if (*b ==
'_') {
1659 }
else if (*b >= 0x80) {
1664 }
else if (*b < 0x80) {
1667 return pm_encoding_utf_8_char_width(b, parser->
end - b);
1676char_is_identifier_utf8(
const uint8_t *b,
const uint8_t *end) {
1680 return pm_encoding_utf_8_char_width(b, end - b);
1690char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b) {
1695 }
else if (*b ==
'_') {
1697 }
else if (*b >= 0x80) {
1703 return char_is_identifier_utf8(b, parser->
end);
1709#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1710#define PUNCT(idx) ( \
1711 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1712 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1713 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1714 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1715 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1718const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1724char_is_global_name_punctuation(const uint8_t b) {
1725 const unsigned int i = (const unsigned int) b;
1726 if (i <= 0x20 || 0x7e < i) return false;
1728 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1732token_is_setter_name(pm_token_t *token) {
1734 (token->type == PM_TOKEN_IDENTIFIER) &&
1735 (token->end - token->start >= 2) &&
1736 (token->end[-1] == '=')
1744pm_local_is_keyword(const char *source, size_t length) {
1745#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1749 switch (source[0]) {
1750 case 'd': KEYWORD("do"); return false;
1751 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1752 case 'o': KEYWORD("or"); return false;
1753 default: return false;
1756 switch (source[0]) {
1757 case 'a': KEYWORD("and"); return false;
1758 case 'd': KEYWORD("def"); return false;
1759 case 'e': KEYWORD("end"); return false;
1760 case 'f': KEYWORD("for"); return false;
1761 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1762 default: return false;
1765 switch (source[0]) {
1766 case 'c': KEYWORD("case"); return false;
1767 case 'e': KEYWORD("else"); return false;
1768 case 'n': KEYWORD("next"); return false;
1769 case 'r': KEYWORD("redo"); return false;
1770 case 's': KEYWORD("self"); return false;
1771 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1772 case 'w': KEYWORD("when"); return false;
1773 default: return false;
1776 switch (source[0]) {
1777 case 'a': KEYWORD("alias"); return false;
1778 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1779 case 'c': KEYWORD("class"); return false;
1780 case 'e': KEYWORD("elsif"); return false;
1781 case 'f': KEYWORD("false"); return false;
1782 case 'r': KEYWORD("retry"); return false;
1783 case 's': KEYWORD("super"); return false;
1784 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1785 case 'w': KEYWORD("while"); return false;
1786 case 'y': KEYWORD("yield"); return false;
1787 default: return false;
1790 switch (source[0]) {
1791 case 'e': KEYWORD("ensure"); return false;
1792 case 'm': KEYWORD("module"); return false;
1793 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1794 case 'u': KEYWORD("unless"); return false;
1795 default: return false;
1798 KEYWORD("__LINE__");
1799 KEYWORD("__FILE__");
1802 KEYWORD("__ENCODING__");
1811/******************************************************************************/
1812/* Node flag handling functions */
1813/******************************************************************************/
1819pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1820 node->flags |= flag;
1827pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1828 node->flags &= (pm_node_flags_t) ~flag;
1835pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1836 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1837 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1838 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1839 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1840 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1841 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1842 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1843 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1845 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1848/******************************************************************************/
1849/* Node creation functions */
1850/******************************************************************************/
1857#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
1862static inline pm_node_flags_t
1863pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1864 pm_node_flags_t flags = 0;
1866 if (closing->type == PM_TOKEN_REGEXP_END) {
1867 pm_buffer_t unknown_flags = { 0 };
1869 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1871 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1872 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1873 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1874 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1876 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1877 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1878 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1879 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1881 default: pm_buffer_append_byte(&unknown_flags, *flag);
1885 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1886 if (unknown_flags_length != 0) {
1887 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1888 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1890 pm_buffer_free(&unknown_flags);
1896#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1898static pm_statements_node_t *
1899pm_statements_node_create(pm_parser_t *parser);
1902pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1905pm_statements_node_body_length(pm_statements_node_t *node);
1912pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1913 void *memory = xcalloc(1, size);
1914 if (memory == NULL) {
1915 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1921#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
1922#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
1927static pm_missing_node_t *
1928pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1929 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1931 *node = (pm_missing_node_t) {{
1932 .type = PM_MISSING_NODE,
1933 .node_id = PM_NODE_IDENTIFY(parser),
1934 .location = { .start = start, .end = end }
1943static pm_alias_global_variable_node_t *
1944pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1945 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1946 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1948 *node = (pm_alias_global_variable_node_t) {
1950 .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
1951 .node_id = PM_NODE_IDENTIFY(parser),
1953 .start = keyword->start,
1954 .end = old_name->location.end
1957 .new_name = new_name,
1958 .old_name = old_name,
1959 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1968static pm_alias_method_node_t *
1969pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1970 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1971 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
1973 *node = (pm_alias_method_node_t) {
1975 .type = PM_ALIAS_METHOD_NODE,
1976 .node_id = PM_NODE_IDENTIFY(parser),
1978 .start = keyword->start,
1979 .end = old_name->location.end
1982 .new_name = new_name,
1983 .old_name = old_name,
1984 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1993static pm_alternation_pattern_node_t *
1994pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
1995 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
1997 *node = (pm_alternation_pattern_node_t) {
1999 .type = PM_ALTERNATION_PATTERN_NODE,
2000 .node_id = PM_NODE_IDENTIFY(parser),
2002 .start = left->location.start,
2003 .end = right->location.end
2008 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2017static pm_and_node_t *
2018pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2019 pm_assert_value_expression(parser, left);
2021 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2023 *node = (pm_and_node_t) {
2025 .type = PM_AND_NODE,
2026 .node_id = PM_NODE_IDENTIFY(parser),
2028 .start = left->location.start,
2029 .end = right->location.end
2033 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2043static pm_arguments_node_t *
2044pm_arguments_node_create(pm_parser_t *parser) {
2045 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2047 *node = (pm_arguments_node_t) {
2049 .type = PM_ARGUMENTS_NODE,
2050 .node_id = PM_NODE_IDENTIFY(parser),
2051 .location = PM_LOCATION_NULL_VALUE(parser)
2063pm_arguments_node_size(pm_arguments_node_t *node) {
2064 return node->arguments.size;
2071pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2072 if (pm_arguments_node_size(node) == 0) {
2073 node->base.location.start = argument->location.start;
2076 node->base.location.end = argument->location.end;
2077 pm_node_list_append(&node->arguments, argument);
2079 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2080 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2081 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2083 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2091static pm_array_node_t *
2092pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2093 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2095 *node = (pm_array_node_t) {
2097 .type = PM_ARRAY_NODE,
2098 .flags = PM_NODE_FLAG_STATIC_LITERAL,
2099 .node_id = PM_NODE_IDENTIFY(parser),
2100 .location = PM_LOCATION_TOKEN_VALUE(opening)
2102 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2103 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2114pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2115 if (!node->elements.size && !node->opening_loc.start) {
2116 node->base.location.start = element->location.start;
2119 pm_node_list_append(&node->elements, element);
2120 node->base.location.end = element->location.end;
2122 // If the element is not a static literal, then the array is not a static
2123 // literal. Turn that flag off.
2124 if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) {
2125 pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
2128 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2129 pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2137pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2138 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2139 node->base.location.end = closing->end;
2140 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2147static pm_array_pattern_node_t *
2148pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2149 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2151 *node = (pm_array_pattern_node_t) {
2153 .type = PM_ARRAY_PATTERN_NODE,
2154 .node_id = PM_NODE_IDENTIFY(parser),
2156 .start = nodes->nodes[0]->location.start,
2157 .end = nodes->nodes[nodes->size - 1]->location.end
2164 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2165 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2168 // For now we're going to just copy over each pointer manually. This could be
2169 // much more efficient, as we could instead resize the node list.
2170 bool found_rest = false;
2173 PM_NODE_LIST_FOREACH(nodes, index, child) {
2174 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2177 } else if (found_rest) {
2178 pm_node_list_append(&node->posts, child);
2180 pm_node_list_append(&node->requireds, child);
2190static pm_array_pattern_node_t *
2191pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2192 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2194 *node = (pm_array_pattern_node_t) {
2196 .type = PM_ARRAY_PATTERN_NODE,
2197 .node_id = PM_NODE_IDENTIFY(parser),
2198 .location = rest->location,
2204 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2205 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2215static pm_array_pattern_node_t *
2216pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2217 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2219 *node = (pm_array_pattern_node_t) {
2221 .type = PM_ARRAY_PATTERN_NODE,
2222 .node_id = PM_NODE_IDENTIFY(parser),
2224 .start = constant->location.start,
2228 .constant = constant,
2230 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2231 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2243static pm_array_pattern_node_t *
2244pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2245 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2247 *node = (pm_array_pattern_node_t) {
2249 .type = PM_ARRAY_PATTERN_NODE,
2250 .node_id = PM_NODE_IDENTIFY(parser),
2252 .start = opening->start,
2258 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2259 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2268pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2269 pm_node_list_append(&node->requireds, inner);
2275static pm_assoc_node_t *
2276pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2277 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2280 if (value != NULL && value->location.end > key->location.end) {
2281 end = value->location.end;
2282 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2283 end = operator->end;
2285 end = key->location.end;
2288 // Hash string keys will be frozen, so we can mark them as frozen here so
2289 // that the compiler picks them up and also when we check for static literal
2290 // on the keys it gets factored in.
2291 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2292 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2295 // If the key and value of this assoc node are both static literals, then
2296 // we can mark this node as a static literal.
2297 pm_node_flags_t flags = 0;
2299 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2300 value && !PM_NODE_TYPE_P(value, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(value, PM_HASH_NODE) && !PM_NODE_TYPE_P(value, PM_RANGE_NODE)
2302 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2305 *node = (pm_assoc_node_t) {
2307 .type = PM_ASSOC_NODE,
2309 .node_id = PM_NODE_IDENTIFY(parser),
2311 .start = key->location.start,
2316 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2326static pm_assoc_splat_node_t *
2327pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2328 assert(operator->type == PM_TOKEN_USTAR_STAR);
2329 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2331 *node = (pm_assoc_splat_node_t) {
2333 .type = PM_ASSOC_SPLAT_NODE,
2334 .node_id = PM_NODE_IDENTIFY(parser),
2336 .start = operator->start,
2337 .end = value == NULL ? operator->end : value->location.end
2341 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2350static pm_back_reference_read_node_t *
2351pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2352 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2353 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2355 *node = (pm_back_reference_read_node_t) {
2357 .type = PM_BACK_REFERENCE_READ_NODE,
2358 .node_id = PM_NODE_IDENTIFY(parser),
2359 .location = PM_LOCATION_TOKEN_VALUE(name),
2361 .name = pm_parser_constant_id_token(parser, name)
2370static pm_begin_node_t *
2371pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2372 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2374 *node = (pm_begin_node_t) {
2376 .type = PM_BEGIN_NODE,
2377 .node_id = PM_NODE_IDENTIFY(parser),
2379 .start = begin_keyword->start,
2380 .end = statements == NULL ? begin_keyword->end : statements->base.location.end
2383 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2384 .statements = statements,
2385 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2395pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2396 // If the begin keyword doesn't exist, we set the start on the begin_node
2397 if (!node->begin_keyword_loc.start) {
2398 node->base.location.start = rescue_clause->base.location.start;
2400 node->base.location.end = rescue_clause->base.location.end;
2401 node->rescue_clause = rescue_clause;
2408pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2409 node->base.location.end = else_clause->base.location.end;
2410 node->else_clause = else_clause;
2417pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2418 node->base.location.end = ensure_clause->base.location.end;
2419 node->ensure_clause = ensure_clause;
2426pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2427 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2429 node->base.location.end = end_keyword->end;
2430 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2436static pm_block_argument_node_t *
2437pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2438 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2440 *node = (pm_block_argument_node_t) {
2442 .type = PM_BLOCK_ARGUMENT_NODE,
2443 .node_id = PM_NODE_IDENTIFY(parser),
2445 .start = operator->start,
2446 .end = expression == NULL ? operator->end : expression->location.end
2449 .expression = expression,
2450 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2459static pm_block_node_t *
2460pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
2461 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2463 *node = (pm_block_node_t) {
2465 .type = PM_BLOCK_NODE,
2466 .node_id = PM_NODE_IDENTIFY(parser),
2467 .location = { .start = opening->start, .end = closing->end },
2470 .parameters = parameters,
2472 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2473 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2482static pm_block_parameter_node_t *
2483pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2484 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2485 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2487 *node = (pm_block_parameter_node_t) {
2489 .type = PM_BLOCK_PARAMETER_NODE,
2490 .node_id = PM_NODE_IDENTIFY(parser),
2492 .start = operator->start,
2493 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
2496 .name = pm_parser_optional_constant_id_token(parser, name),
2497 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2498 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2507static pm_block_parameters_node_t *
2508pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2509 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2511 const uint8_t *start;
2512 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2513 start = opening->start;
2514 } else if (parameters != NULL) {
2515 start = parameters->base.location.start;
2521 if (parameters != NULL) {
2522 end = parameters->base.location.end;
2523 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2529 *node = (pm_block_parameters_node_t) {
2531 .type = PM_BLOCK_PARAMETERS_NODE,
2532 .node_id = PM_NODE_IDENTIFY(parser),
2538 .parameters = parameters,
2539 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2540 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2551pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2552 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2554 node->base.location.end = closing->end;
2555 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2561static pm_block_local_variable_node_t *
2562pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2563 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2565 *node = (pm_block_local_variable_node_t) {
2567 .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
2568 .node_id = PM_NODE_IDENTIFY(parser),
2569 .location = PM_LOCATION_TOKEN_VALUE(name),
2571 .name = pm_parser_constant_id_token(parser, name)
2581pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2582 pm_node_list_append(&node->locals, (pm_node_t *) local);
2584 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2585 node->base.location.end = local->base.location.end;
2591static pm_break_node_t *
2592pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2593 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2594 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2596 *node = (pm_break_node_t) {
2598 .type = PM_BREAK_NODE,
2599 .node_id = PM_NODE_IDENTIFY(parser),
2601 .start = keyword->start,
2602 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
2605 .arguments = arguments,
2606 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2612// There are certain flags that we want to use internally but don't want to
2613// expose because they are not relevant beyond parsing. Therefore we'll define
2614// them here and not define them in config.yml/a header file.
2615static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
2616static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
2617static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
2618static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
2625static pm_call_node_t *
2626pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2627 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2629 *node = (pm_call_node_t) {
2631 .type = PM_CALL_NODE,
2633 .node_id = PM_NODE_IDENTIFY(parser),
2634 .location = PM_LOCATION_NULL_VALUE(parser),
2637 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2638 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2639 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2641 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2653static inline pm_node_flags_t
2654pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2655 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2662static pm_call_node_t *
2663pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2664 pm_assert_value_expression(parser, receiver);
2666 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2667 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2668 flags |= PM_CALL_NODE_FLAGS_INDEX;
2671 pm_call_node_t *node = pm_call_node_create(parser, flags);
2673 node->base.location.start = receiver->location.start;
2674 node->base.location.end = pm_arguments_end(arguments);
2676 node->receiver = receiver;
2677 node->message_loc.start = arguments->opening_loc.start;
2678 node->message_loc.end = arguments->closing_loc.end;
2680 node->opening_loc = arguments->opening_loc;
2681 node->arguments = arguments->arguments;
2682 node->closing_loc = arguments->closing_loc;
2683 node->block = arguments->block;
2685 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2692static pm_call_node_t *
2693pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_node_t *argument, pm_node_flags_t flags) {
2694 pm_assert_value_expression(parser, receiver);
2695 pm_assert_value_expression(parser, argument);
2697 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2699 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2700 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2702 node->receiver = receiver;
2703 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2705 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2706 pm_arguments_node_arguments_append(arguments, argument);
2707 node->arguments = arguments;
2709 node->name = pm_parser_constant_id_token(parser, operator);
2716static pm_call_node_t *
2717pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2718 pm_assert_value_expression(parser, receiver);
2720 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2722 node->base.location.start = receiver->location.start;
2723 const uint8_t *end = pm_arguments_end(arguments);
2727 node->base.location.end = end;
2729 node->receiver = receiver;
2730 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2731 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2732 node->opening_loc = arguments->opening_loc;
2733 node->arguments = arguments->arguments;
2734 node->closing_loc = arguments->closing_loc;
2735 node->block = arguments->block;
2737 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2738 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2741 node->name = pm_parser_constant_id_token(parser, message);
2748static pm_call_node_t *
2749pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2750 pm_call_node_t *node = pm_call_node_create(parser, 0);
2751 node->base.location.start = parser->start;
2752 node->base.location.end = parser->end;
2754 node->receiver = receiver;
2755 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2756 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2757 node->arguments = arguments;
2759 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2767static pm_call_node_t *
2768pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2769 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2771 node->base.location.start = message->start;
2772 node->base.location.end = pm_arguments_end(arguments);
2774 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2775 node->opening_loc = arguments->opening_loc;
2776 node->arguments = arguments->arguments;
2777 node->closing_loc = arguments->closing_loc;
2778 node->block = arguments->block;
2780 node->name = pm_parser_constant_id_token(parser, message);
2788static pm_call_node_t *
2789pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2790 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2792 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2793 node->arguments = arguments;
2802static pm_call_node_t *
2803pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2804 pm_assert_value_expression(parser, receiver);
2805 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2807 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2809 node->base.location.start = message->start;
2810 if (arguments->closing_loc.start != NULL) {
2811 node->base.location.end = arguments->closing_loc.end;
2813 assert(receiver != NULL);
2814 node->base.location.end = receiver->location.end;
2817 node->receiver = receiver;
2818 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2819 node->opening_loc = arguments->opening_loc;
2820 node->arguments = arguments->arguments;
2821 node->closing_loc = arguments->closing_loc;
2823 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2830static pm_call_node_t *
2831pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2832 pm_assert_value_expression(parser, receiver);
2834 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2836 node->base.location.start = receiver->location.start;
2837 node->base.location.end = pm_arguments_end(arguments);
2839 node->receiver = receiver;
2840 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2841 node->opening_loc = arguments->opening_loc;
2842 node->arguments = arguments->arguments;
2843 node->closing_loc = arguments->closing_loc;
2844 node->block = arguments->block;
2846 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2847 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2850 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2857static pm_call_node_t *
2858pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2859 pm_assert_value_expression(parser, receiver);
2861 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2863 node->base.location.start = operator->start;
2864 node->base.location.end = receiver->location.end;
2866 node->receiver = receiver;
2867 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2869 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2877static pm_call_node_t *
2878pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2879 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2881 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2882 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2884 node->name = pm_parser_constant_id_token(parser, message);
2893pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2895 (node->message_loc.start != NULL) &&
2896 (node->message_loc.end[-1] != '!') &&
2897 (node->message_loc.end[-1] != '?') &&
2898 char_is_identifier_start(parser, node->message_loc.start) &&
2899 (node->opening_loc.start == NULL) &&
2900 (node->arguments == NULL) &&
2901 (node->block == NULL)
2909pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2910 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2912 if (write_constant->length > 0) {
2913 size_t length = write_constant->length - 1;
2915 void *memory = xmalloc(length);
2916 memcpy(memory, write_constant->start, length);
2918 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2920 // We can get here if the message was missing because of a syntax error.
2921 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2928static pm_call_and_write_node_t *
2929pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2930 assert(target->block == NULL);
2931 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2932 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2934 *node = (pm_call_and_write_node_t) {
2936 .type = PM_CALL_AND_WRITE_NODE,
2937 .flags = target->base.flags,
2938 .node_id = PM_NODE_IDENTIFY(parser),
2940 .start = target->base.location.start,
2941 .end = value->location.end
2944 .receiver = target->receiver,
2945 .call_operator_loc = target->call_operator_loc,
2946 .message_loc = target->message_loc,
2948 .write_name = target->name,
2949 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2953 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2955 // Here we're going to free the target, since it is no longer necessary.
2956 // However, we don't want to call `pm_node_destroy` because we want to keep
2957 // around all of its children since we just reused them.
2968pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2969 if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
2970 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2972 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2973 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2974 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2980 if (block != NULL) {
2981 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2989static pm_index_and_write_node_t *
2990pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2991 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2992 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
2994 pm_index_arguments_check(parser, target->arguments, target->block);
2996 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2997 *node = (pm_index_and_write_node_t) {
2999 .type = PM_INDEX_AND_WRITE_NODE,
3000 .flags = target->base.flags,
3001 .node_id = PM_NODE_IDENTIFY(parser),
3003 .start = target->base.location.start,
3004 .end = value->location.end
3007 .receiver = target->receiver,
3008 .call_operator_loc = target->call_operator_loc,
3009 .opening_loc = target->opening_loc,
3010 .arguments = target->arguments,
3011 .closing_loc = target->closing_loc,
3012 .block = (pm_block_argument_node_t *) target->block,
3013 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3017 // Here we're going to free the target, since it is no longer necessary.
3018 // However, we don't want to call `pm_node_destroy` because we want to keep
3019 // around all of its children since we just reused them.
3028static pm_call_operator_write_node_t *
3029pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3030 assert(target->block == NULL);
3031 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3033 *node = (pm_call_operator_write_node_t) {
3035 .type = PM_CALL_OPERATOR_WRITE_NODE,
3036 .flags = target->base.flags,
3037 .node_id = PM_NODE_IDENTIFY(parser),
3039 .start = target->base.location.start,
3040 .end = value->location.end
3043 .receiver = target->receiver,
3044 .call_operator_loc = target->call_operator_loc,
3045 .message_loc = target->message_loc,
3047 .write_name = target->name,
3048 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3049 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3053 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3055 // Here we're going to free the target, since it is no longer necessary.
3056 // However, we don't want to call `pm_node_destroy` because we want to keep
3057 // around all of its children since we just reused them.
3066static pm_index_operator_write_node_t *
3067pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3068 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3070 pm_index_arguments_check(parser, target->arguments, target->block);
3072 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3073 *node = (pm_index_operator_write_node_t) {
3075 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3076 .flags = target->base.flags,
3077 .node_id = PM_NODE_IDENTIFY(parser),
3079 .start = target->base.location.start,
3080 .end = value->location.end
3083 .receiver = target->receiver,
3084 .call_operator_loc = target->call_operator_loc,
3085 .opening_loc = target->opening_loc,
3086 .arguments = target->arguments,
3087 .closing_loc = target->closing_loc,
3088 .block = (pm_block_argument_node_t *) target->block,
3089 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3090 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3094 // Here we're going to free the target, since it is no longer necessary.
3095 // However, we don't want to call `pm_node_destroy` because we want to keep
3096 // around all of its children since we just reused them.
3105static pm_call_or_write_node_t *
3106pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3107 assert(target->block == NULL);
3108 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3109 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3111 *node = (pm_call_or_write_node_t) {
3113 .type = PM_CALL_OR_WRITE_NODE,
3114 .flags = target->base.flags,
3115 .node_id = PM_NODE_IDENTIFY(parser),
3117 .start = target->base.location.start,
3118 .end = value->location.end
3121 .receiver = target->receiver,
3122 .call_operator_loc = target->call_operator_loc,
3123 .message_loc = target->message_loc,
3125 .write_name = target->name,
3126 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3130 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3132 // Here we're going to free the target, since it is no longer necessary.
3133 // However, we don't want to call `pm_node_destroy` because we want to keep
3134 // around all of its children since we just reused them.
3143static pm_index_or_write_node_t *
3144pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3145 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3146 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3148 pm_index_arguments_check(parser, target->arguments, target->block);
3150 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3151 *node = (pm_index_or_write_node_t) {
3153 .type = PM_INDEX_OR_WRITE_NODE,
3154 .flags = target->base.flags,
3155 .node_id = PM_NODE_IDENTIFY(parser),
3157 .start = target->base.location.start,
3158 .end = value->location.end
3161 .receiver = target->receiver,
3162 .call_operator_loc = target->call_operator_loc,
3163 .opening_loc = target->opening_loc,
3164 .arguments = target->arguments,
3165 .closing_loc = target->closing_loc,
3166 .block = (pm_block_argument_node_t *) target->block,
3167 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3171 // Here we're going to free the target, since it is no longer necessary.
3172 // However, we don't want to call `pm_node_destroy` because we want to keep
3173 // around all of its children since we just reused them.
3183static pm_call_target_node_t *
3184pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3185 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3187 *node = (pm_call_target_node_t) {
3189 .type = PM_CALL_TARGET_NODE,
3190 .flags = target->base.flags,
3191 .node_id = PM_NODE_IDENTIFY(parser),
3192 .location = target->base.location
3194 .receiver = target->receiver,
3195 .call_operator_loc = target->call_operator_loc,
3196 .name = target->name,
3197 .message_loc = target->message_loc
3200 // Here we're going to free the target, since it is no longer necessary.
3201 // However, we don't want to call `pm_node_destroy` because we want to keep
3202 // around all of its children since we just reused them.
3212static pm_index_target_node_t *
3213pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3214 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3215 pm_node_flags_t flags = target->base.flags;
3217 pm_index_arguments_check(parser, target->arguments, target->block);
3219 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3220 *node = (pm_index_target_node_t) {
3222 .type = PM_INDEX_TARGET_NODE,
3223 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3224 .node_id = PM_NODE_IDENTIFY(parser),
3225 .location = target->base.location
3227 .receiver = target->receiver,
3228 .opening_loc = target->opening_loc,
3229 .arguments = target->arguments,
3230 .closing_loc = target->closing_loc,
3231 .block = (pm_block_argument_node_t *) target->block,
3234 // Here we're going to free the target, since it is no longer necessary.
3235 // However, we don't want to call `pm_node_destroy` because we want to keep
3236 // around all of its children since we just reused them.
3245static pm_capture_pattern_node_t *
3246pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3247 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3249 *node = (pm_capture_pattern_node_t) {
3251 .type = PM_CAPTURE_PATTERN_NODE,
3252 .node_id = PM_NODE_IDENTIFY(parser),
3254 .start = value->location.start,
3255 .end = target->base.location.end
3260 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3269static pm_case_node_t *
3270pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3271 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3273 *node = (pm_case_node_t) {
3275 .type = PM_CASE_NODE,
3276 .node_id = PM_NODE_IDENTIFY(parser),
3278 .start = case_keyword->start,
3279 .end = end_keyword->end
3282 .predicate = predicate,
3283 .else_clause = NULL,
3284 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3285 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3296pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3297 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3299 pm_node_list_append(&node->conditions, condition);
3300 node->base.location.end = condition->location.end;
3307pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3308 node->else_clause = else_clause;
3309 node->base.location.end = else_clause->base.location.end;
3316pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3317 node->base.location.end = end_keyword->end;
3318 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3324static pm_case_match_node_t *
3325pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3326 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3328 *node = (pm_case_match_node_t) {
3330 .type = PM_CASE_MATCH_NODE,
3331 .node_id = PM_NODE_IDENTIFY(parser),
3333 .start = case_keyword->start,
3334 .end = end_keyword->end
3337 .predicate = predicate,
3338 .else_clause = NULL,
3339 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3340 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3351pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3352 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3354 pm_node_list_append(&node->conditions, condition);
3355 node->base.location.end = condition->location.end;
3362pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3363 node->else_clause = else_clause;
3364 node->base.location.end = else_clause->base.location.end;
3371pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3372 node->base.location.end = end_keyword->end;
3373 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3379static pm_class_node_t *
3380pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, pm_node_t *constant_path, const pm_token_t *name, const pm_token_t *inheritance_operator, pm_node_t *superclass, pm_node_t *body, const pm_token_t *end_keyword) {
3381 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3383 *node = (pm_class_node_t) {
3385 .type = PM_CLASS_NODE,
3386 .node_id = PM_NODE_IDENTIFY(parser),
3387 .location = { .start = class_keyword->start, .end = end_keyword->end },
3390 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3391 .constant_path = constant_path,
3392 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3393 .superclass = superclass,
3395 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3396 .name = pm_parser_constant_id_token(parser, name)
3405static pm_class_variable_and_write_node_t *
3406pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3407 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3408 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3410 *node = (pm_class_variable_and_write_node_t) {
3412 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3413 .node_id = PM_NODE_IDENTIFY(parser),
3415 .start = target->base.location.start,
3416 .end = value->location.end
3419 .name = target->name,
3420 .name_loc = target->base.location,
3421 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3431static pm_class_variable_operator_write_node_t *
3432pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3433 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3435 *node = (pm_class_variable_operator_write_node_t) {
3437 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3438 .node_id = PM_NODE_IDENTIFY(parser),
3440 .start = target->base.location.start,
3441 .end = value->location.end
3444 .name = target->name,
3445 .name_loc = target->base.location,
3446 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3448 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3457static pm_class_variable_or_write_node_t *
3458pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3459 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3460 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3462 *node = (pm_class_variable_or_write_node_t) {
3464 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3465 .node_id = PM_NODE_IDENTIFY(parser),
3467 .start = target->base.location.start,
3468 .end = value->location.end
3471 .name = target->name,
3472 .name_loc = target->base.location,
3473 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3483static pm_class_variable_read_node_t *
3484pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3485 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3486 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3488 *node = (pm_class_variable_read_node_t) {
3490 .type = PM_CLASS_VARIABLE_READ_NODE,
3491 .node_id = PM_NODE_IDENTIFY(parser),
3492 .location = PM_LOCATION_TOKEN_VALUE(token)
3494 .name = pm_parser_constant_id_token(parser, token)
3506static inline pm_node_flags_t
3507pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3508 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3517static pm_class_variable_write_node_t *
3518pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
3519 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3521 *node = (pm_class_variable_write_node_t) {
3523 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3524 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3525 .node_id = PM_NODE_IDENTIFY(parser),
3527 .start = read_node->base.location.start,
3528 .end = value->location.end
3531 .name = read_node->name,
3532 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3533 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3543static pm_constant_path_and_write_node_t *
3544pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3545 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3546 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3548 *node = (pm_constant_path_and_write_node_t) {
3550 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3551 .node_id = PM_NODE_IDENTIFY(parser),
3553 .start = target->base.location.start,
3554 .end = value->location.end
3558 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3568static pm_constant_path_operator_write_node_t *
3569pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3570 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3572 *node = (pm_constant_path_operator_write_node_t) {
3574 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3575 .node_id = PM_NODE_IDENTIFY(parser),
3577 .start = target->base.location.start,
3578 .end = value->location.end
3582 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3584 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3593static pm_constant_path_or_write_node_t *
3594pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3595 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3596 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3598 *node = (pm_constant_path_or_write_node_t) {
3600 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3601 .node_id = PM_NODE_IDENTIFY(parser),
3603 .start = target->base.location.start,
3604 .end = value->location.end
3608 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3618static pm_constant_path_node_t *
3619pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3620 pm_assert_value_expression(parser, parent);
3621 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3623 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3624 if (name_token->type == PM_TOKEN_CONSTANT) {
3625 name = pm_parser_constant_id_token(parser, name_token);
3628 *node = (pm_constant_path_node_t) {
3630 .type = PM_CONSTANT_PATH_NODE,
3631 .node_id = PM_NODE_IDENTIFY(parser),
3633 .start = parent == NULL ? delimiter->start : parent->location.start,
3634 .end = name_token->end
3639 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3640 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3649static pm_constant_path_write_node_t *
3650pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3651 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3653 *node = (pm_constant_path_write_node_t) {
3655 .type = PM_CONSTANT_PATH_WRITE_NODE,
3656 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3657 .node_id = PM_NODE_IDENTIFY(parser),
3659 .start = target->base.location.start,
3660 .end = value->location.end
3664 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3674static pm_constant_and_write_node_t *
3675pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3676 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3677 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3679 *node = (pm_constant_and_write_node_t) {
3681 .type = PM_CONSTANT_AND_WRITE_NODE,
3682 .node_id = PM_NODE_IDENTIFY(parser),
3684 .start = target->base.location.start,
3685 .end = value->location.end
3688 .name = target->name,
3689 .name_loc = target->base.location,
3690 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3700static pm_constant_operator_write_node_t *
3701pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3702 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3704 *node = (pm_constant_operator_write_node_t) {
3706 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3707 .node_id = PM_NODE_IDENTIFY(parser),
3709 .start = target->base.location.start,
3710 .end = value->location.end
3713 .name = target->name,
3714 .name_loc = target->base.location,
3715 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3717 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3726static pm_constant_or_write_node_t *
3727pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3728 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3729 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3731 *node = (pm_constant_or_write_node_t) {
3733 .type = PM_CONSTANT_OR_WRITE_NODE,
3734 .node_id = PM_NODE_IDENTIFY(parser),
3736 .start = target->base.location.start,
3737 .end = value->location.end
3740 .name = target->name,
3741 .name_loc = target->base.location,
3742 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3752static pm_constant_read_node_t *
3753pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3754 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3755 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3757 *node = (pm_constant_read_node_t) {
3759 .type = PM_CONSTANT_READ_NODE,
3760 .node_id = PM_NODE_IDENTIFY(parser),
3761 .location = PM_LOCATION_TOKEN_VALUE(name)
3763 .name = pm_parser_constant_id_token(parser, name)
3772static pm_constant_write_node_t *
3773pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3774 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3776 *node = (pm_constant_write_node_t) {
3778 .type = PM_CONSTANT_WRITE_NODE,
3779 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3780 .node_id = PM_NODE_IDENTIFY(parser),
3782 .start = target->base.location.start,
3783 .end = value->location.end
3786 .name = target->name,
3787 .name_loc = target->base.location,
3788 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3799pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3800 switch (PM_NODE_TYPE(node)) {
3801 case PM_BEGIN_NODE: {
3802 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3803 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3806 case PM_PARENTHESES_NODE: {
3807 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3808 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3811 case PM_STATEMENTS_NODE: {
3812 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3813 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3818 case PM_IMAGINARY_NODE:
3819 case PM_INTEGER_NODE:
3820 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3821 case PM_INTERPOLATED_STRING_NODE:
3822 case PM_INTERPOLATED_SYMBOL_NODE:
3823 case PM_INTERPOLATED_X_STRING_NODE:
3824 case PM_RATIONAL_NODE:
3825 case PM_REGULAR_EXPRESSION_NODE:
3826 case PM_SOURCE_ENCODING_NODE:
3827 case PM_SOURCE_FILE_NODE:
3828 case PM_SOURCE_LINE_NODE:
3829 case PM_STRING_NODE:
3830 case PM_SYMBOL_NODE:
3831 case PM_X_STRING_NODE:
3832 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3842static pm_def_node_t *
3844 pm_parser_t *parser,
3845 pm_constant_id_t name,
3846 const pm_token_t *name_loc,
3847 pm_node_t *receiver,
3848 pm_parameters_node_t *parameters,
3850 pm_constant_id_list_t *locals,
3851 const pm_token_t *def_keyword,
3852 const pm_token_t *operator,
3853 const pm_token_t *lparen,
3854 const pm_token_t *rparen,
3855 const pm_token_t *equal,
3856 const pm_token_t *end_keyword
3858 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3861 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3862 end = body->location.end;
3864 end = end_keyword->end;
3867 if ((receiver != NULL) && PM_NODE_TYPE_P(receiver, PM_PARENTHESES_NODE)) {
3868 pm_def_node_receiver_check(parser, receiver);
3871 *node = (pm_def_node_t) {
3873 .type = PM_DEF_NODE,
3874 .node_id = PM_NODE_IDENTIFY(parser),
3875 .location = { .start = def_keyword->start, .end = end },
3878 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3879 .receiver = receiver,
3880 .parameters = parameters,
3883 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3884 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3885 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3886 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3887 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3888 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3897static pm_defined_node_t *
3898pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_location_t *keyword_loc) {
3899 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3901 *node = (pm_defined_node_t) {
3903 .type = PM_DEFINED_NODE,
3904 .node_id = PM_NODE_IDENTIFY(parser),
3906 .start = keyword_loc->start,
3907 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3910 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3912 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3913 .keyword_loc = *keyword_loc
3922static pm_else_node_t *
3923pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3924 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3925 const uint8_t *end = NULL;
3926 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3927 end = statements->base.location.end;
3929 end = end_keyword->end;
3932 *node = (pm_else_node_t) {
3934 .type = PM_ELSE_NODE,
3935 .node_id = PM_NODE_IDENTIFY(parser),
3937 .start = else_keyword->start,
3941 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3942 .statements = statements,
3943 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3952static pm_embedded_statements_node_t *
3953pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3954 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3956 *node = (pm_embedded_statements_node_t) {
3958 .type = PM_EMBEDDED_STATEMENTS_NODE,
3959 .node_id = PM_NODE_IDENTIFY(parser),
3961 .start = opening->start,
3965 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3966 .statements = statements,
3967 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3976static pm_embedded_variable_node_t *
3977pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3978 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3980 *node = (pm_embedded_variable_node_t) {
3982 .type = PM_EMBEDDED_VARIABLE_NODE,
3983 .node_id = PM_NODE_IDENTIFY(parser),
3985 .start = operator->start,
3986 .end = variable->location.end
3989 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3990 .variable = variable
3999static pm_ensure_node_t *
4000pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4001 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4003 *node = (pm_ensure_node_t) {
4005 .type = PM_ENSURE_NODE,
4006 .node_id = PM_NODE_IDENTIFY(parser),
4008 .start = ensure_keyword->start,
4009 .end = end_keyword->end
4012 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4013 .statements = statements,
4014 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4023static pm_false_node_t *
4024pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4025 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4026 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4028 *node = (pm_false_node_t) {{
4029 .type = PM_FALSE_NODE,
4030 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4031 .node_id = PM_NODE_IDENTIFY(parser),
4032 .location = PM_LOCATION_TOKEN_VALUE(token)
4042static pm_find_pattern_node_t *
4043pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4044 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4046 pm_node_t *left = nodes->nodes[0];
4047 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4048 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4052 if (nodes->size == 1) {
4053 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4055 right = nodes->nodes[nodes->size - 1];
4056 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4059#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4060 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4061 // The resulting AST will anyway be ignored, but this file still needs to compile.
4062 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4064 pm_node_t *right_splat_node = right;
4066 *node = (pm_find_pattern_node_t) {
4068 .type = PM_FIND_PATTERN_NODE,
4069 .node_id = PM_NODE_IDENTIFY(parser),
4071 .start = left->location.start,
4072 .end = right->location.end,
4076 .left = left_splat_node,
4077 .right = right_splat_node,
4079 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4080 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4083 // For now we're going to just copy over each pointer manually. This could be
4084 // much more efficient, as we could instead resize the node list to only point
4086 for (size_t index = 1; index < nodes->size - 1; index++) {
4087 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4098pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4099 ptrdiff_t diff = token->end - token->start;
4100 if (diff <= 0) return 0.0;
4102 // First, get a buffer of the content.
4103 size_t length = (size_t) diff;
4104 char *buffer = xmalloc(sizeof(char) * (length + 1));
4105 memcpy((void *) buffer, token->start, length);
4107 // Next, determine if we need to replace the decimal point because of
4108 // locale-specific options, and then normalize them if we have to.
4109 char decimal_point = *localeconv()->decimal_point;
4110 if (decimal_point != '.') {
4111 for (size_t index = 0; index < length; index++) {
4112 if (buffer[index] == '.') buffer[index] = decimal_point;
4116 // Next, handle underscores by removing them from the buffer.
4117 for (size_t index = 0; index < length; index++) {
4118 if (buffer[index] == '_') {
4119 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4124 // Null-terminate the buffer so that strtod cannot read off the end.
4125 buffer[length] = '\0';
4127 // Now, call strtod to parse the value. Note that CRuby has their own
4128 // version of strtod which avoids locales. We're okay using the locale-aware
4129 // version because we've already validated through the parser that the token
4130 // is in a valid format.
4133 double value = strtod(buffer, &eptr);
4135 // This should never happen, because we've already checked that the token
4136 // is in a valid format. However it's good to be safe.
4137 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4138 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4139 xfree((void *) buffer);
4143 // If errno is set, then it should only be ERANGE. At this point we need to
4144 // check if it's infinity (it should be).
4145 if (errno == ERANGE && PRISM_ISINF(value)) {
4147 const char *ellipsis;
4153 warn_width = (int) length;
4157 pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
4158 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4161 // Finally we can free the buffer and return the value.
4162 xfree((void *) buffer);
4169static pm_float_node_t *
4170pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4171 assert(token->type == PM_TOKEN_FLOAT);
4172 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4174 *node = (pm_float_node_t) {
4176 .type = PM_FLOAT_NODE,
4177 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4178 .node_id = PM_NODE_IDENTIFY(parser),
4179 .location = PM_LOCATION_TOKEN_VALUE(token)
4181 .value = pm_double_parse(parser, token)
4190static pm_imaginary_node_t *
4191pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4192 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4194 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4195 *node = (pm_imaginary_node_t) {
4197 .type = PM_IMAGINARY_NODE,
4198 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4199 .node_id = PM_NODE_IDENTIFY(parser),
4200 .location = PM_LOCATION_TOKEN_VALUE(token)
4202 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4203 .type = PM_TOKEN_FLOAT,
4204 .start = token->start,
4205 .end = token->end - 1
4215static pm_rational_node_t *
4216pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4217 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4219 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4220 *node = (pm_rational_node_t) {
4222 .type = PM_RATIONAL_NODE,
4223 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4224 .node_id = PM_NODE_IDENTIFY(parser),
4225 .location = PM_LOCATION_TOKEN_VALUE(token)
4228 .denominator = { 0 }
4231 const uint8_t *start = token->start;
4232 const uint8_t *end = token->end - 1; // r
4234 while (start < end && *start == '0') start++; // 0.1 -> .1
4235 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4237 size_t length = (size_t) (end - start);
4239 node->denominator.value = 1;
4243 const uint8_t *point = memchr(start, '.', length);
4244 assert(point && "should have a decimal point");
4246 uint8_t *digits = malloc(length);
4247 if (digits == NULL) {
4248 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4252 memcpy(digits, start, (unsigned long) (point - start));
4253 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4254 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4257 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4258 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4261 pm_integers_reduce(&node->numerator, &node->denominator);
4269static pm_imaginary_node_t *
4270pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4271 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4273 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4274 *node = (pm_imaginary_node_t) {
4276 .type = PM_IMAGINARY_NODE,
4277 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4278 .node_id = PM_NODE_IDENTIFY(parser),
4279 .location = PM_LOCATION_TOKEN_VALUE(token)
4281 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4282 .type = PM_TOKEN_FLOAT_RATIONAL,
4283 .start = token->start,
4284 .end = token->end - 1
4294static pm_for_node_t *
4296 pm_parser_t *parser,
4298 pm_node_t *collection,
4299 pm_statements_node_t *statements,
4300 const pm_token_t *for_keyword,
4301 const pm_token_t *in_keyword,
4302 const pm_token_t *do_keyword,
4303 const pm_token_t *end_keyword
4305 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4307 *node = (pm_for_node_t) {
4309 .type = PM_FOR_NODE,
4310 .node_id = PM_NODE_IDENTIFY(parser),
4312 .start = for_keyword->start,
4313 .end = end_keyword->end
4317 .collection = collection,
4318 .statements = statements,
4319 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4320 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4321 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4322 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4331static pm_forwarding_arguments_node_t *
4332pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4333 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4334 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4336 *node = (pm_forwarding_arguments_node_t) {{
4337 .type = PM_FORWARDING_ARGUMENTS_NODE,
4338 .node_id = PM_NODE_IDENTIFY(parser),
4339 .location = PM_LOCATION_TOKEN_VALUE(token)
4348static pm_forwarding_parameter_node_t *
4349pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4350 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4351 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4353 *node = (pm_forwarding_parameter_node_t) {{
4354 .type = PM_FORWARDING_PARAMETER_NODE,
4355 .node_id = PM_NODE_IDENTIFY(parser),
4356 .location = PM_LOCATION_TOKEN_VALUE(token)
4365static pm_forwarding_super_node_t *
4366pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4367 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4368 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4369 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4371 pm_block_node_t *block = NULL;
4372 if (arguments->block != NULL) {
4373 block = (pm_block_node_t *) arguments->block;
4376 *node = (pm_forwarding_super_node_t) {
4378 .type = PM_FORWARDING_SUPER_NODE,
4379 .node_id = PM_NODE_IDENTIFY(parser),
4381 .start = token->start,
4382 .end = block != NULL ? block->base.location.end : token->end
4395static pm_hash_pattern_node_t *
4396pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4397 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4399 *node = (pm_hash_pattern_node_t) {
4401 .type = PM_HASH_PATTERN_NODE,
4402 .node_id = PM_NODE_IDENTIFY(parser),
4404 .start = opening->start,
4409 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4410 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4421static pm_hash_pattern_node_t *
4422pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4423 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4425 const uint8_t *start;
4428 if (elements->size > 0) {
4430 start = elements->nodes[0]->location.start;
4431 end = rest->location.end;
4433 start = elements->nodes[0]->location.start;
4434 end = elements->nodes[elements->size - 1]->location.end;
4437 assert(rest != NULL);
4438 start = rest->location.start;
4439 end = rest->location.end;
4442 *node = (pm_hash_pattern_node_t) {
4444 .type = PM_HASH_PATTERN_NODE,
4445 .node_id = PM_NODE_IDENTIFY(parser),
4454 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4455 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4459 PM_NODE_LIST_FOREACH(elements, index, element) {
4460 pm_node_list_append(&node->elements, element);
4469static pm_constant_id_t
4470pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4471 switch (PM_NODE_TYPE(target)) {
4472 case PM_GLOBAL_VARIABLE_READ_NODE:
4473 return ((pm_global_variable_read_node_t *) target)->name;
4474 case PM_BACK_REFERENCE_READ_NODE:
4475 return ((pm_back_reference_read_node_t *) target)->name;
4476 case PM_NUMBERED_REFERENCE_READ_NODE:
4477 // This will only ever happen in the event of a syntax error, but we
4478 // still need to provide something for the node.
4479 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4481 assert(false && "unreachable");
4482 return (pm_constant_id_t) -1;
4489static pm_global_variable_and_write_node_t *
4490pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4491 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4492 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4494 *node = (pm_global_variable_and_write_node_t) {
4496 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4497 .node_id = PM_NODE_IDENTIFY(parser),
4499 .start = target->location.start,
4500 .end = value->location.end
4503 .name = pm_global_variable_write_name(parser, target),
4504 .name_loc = target->location,
4505 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4515static pm_global_variable_operator_write_node_t *
4516pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4517 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4519 *node = (pm_global_variable_operator_write_node_t) {
4521 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4522 .node_id = PM_NODE_IDENTIFY(parser),
4524 .start = target->location.start,
4525 .end = value->location.end
4528 .name = pm_global_variable_write_name(parser, target),
4529 .name_loc = target->location,
4530 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4532 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4541static pm_global_variable_or_write_node_t *
4542pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4543 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4544 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4546 *node = (pm_global_variable_or_write_node_t) {
4548 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4549 .node_id = PM_NODE_IDENTIFY(parser),
4551 .start = target->location.start,
4552 .end = value->location.end
4555 .name = pm_global_variable_write_name(parser, target),
4556 .name_loc = target->location,
4557 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4567static pm_global_variable_read_node_t *
4568pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4569 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4571 *node = (pm_global_variable_read_node_t) {
4573 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4574 .node_id = PM_NODE_IDENTIFY(parser),
4575 .location = PM_LOCATION_TOKEN_VALUE(name),
4577 .name = pm_parser_constant_id_token(parser, name)
4586static pm_global_variable_read_node_t *
4587pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4588 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4590 *node = (pm_global_variable_read_node_t) {
4592 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4593 .node_id = PM_NODE_IDENTIFY(parser),
4594 .location = PM_LOCATION_NULL_VALUE(parser)
4605static pm_global_variable_write_node_t *
4606pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4607 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4609 *node = (pm_global_variable_write_node_t) {
4611 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4612 .node_id = PM_NODE_IDENTIFY(parser),
4613 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4615 .start = target->location.start,
4616 .end = value->location.end
4619 .name = pm_global_variable_write_name(parser, target),
4620 .name_loc = PM_LOCATION_NODE_VALUE(target),
4621 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4631static pm_global_variable_write_node_t *
4632pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4633 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4635 *node = (pm_global_variable_write_node_t) {
4637 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4638 .node_id = PM_NODE_IDENTIFY(parser),
4639 .location = PM_LOCATION_NULL_VALUE(parser)
4642 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4643 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4653static pm_hash_node_t *
4654pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4655 assert(opening != NULL);
4656 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4658 *node = (pm_hash_node_t) {
4660 .type = PM_HASH_NODE,
4661 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4662 .node_id = PM_NODE_IDENTIFY(parser),
4663 .location = PM_LOCATION_TOKEN_VALUE(opening)
4665 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4666 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4677pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4678 pm_node_list_append(&hash->elements, element);
4680 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4681 if (static_literal) {
4682 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4683 static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE);
4684 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4685 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4688 if (!static_literal) {
4689 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4694pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4695 hash->base.location.end = token->end;
4696 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4702static pm_if_node_t *
4703pm_if_node_create(pm_parser_t *parser,
4704 const pm_token_t *if_keyword,
4705 pm_node_t *predicate,
4706 const pm_token_t *then_keyword,
4707 pm_statements_node_t *statements,
4708 pm_node_t *subsequent,
4709 const pm_token_t *end_keyword
4711 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4712 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4715 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4716 end = end_keyword->end;
4717 } else if (subsequent != NULL) {
4718 end = subsequent->location.end;
4719 } else if (pm_statements_node_body_length(statements) != 0) {
4720 end = statements->base.location.end;
4722 end = predicate->location.end;
4725 *node = (pm_if_node_t) {
4728 .flags = PM_NODE_FLAG_NEWLINE,
4729 .node_id = PM_NODE_IDENTIFY(parser),
4731 .start = if_keyword->start,
4735 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4736 .predicate = predicate,
4737 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4738 .statements = statements,
4739 .subsequent = subsequent,
4740 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4749static pm_if_node_t *
4750pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4751 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4752 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4754 pm_statements_node_t *statements = pm_statements_node_create(parser);
4755 pm_statements_node_body_append(parser, statements, statement, true);
4757 *node = (pm_if_node_t) {
4760 .flags = PM_NODE_FLAG_NEWLINE,
4761 .node_id = PM_NODE_IDENTIFY(parser),
4763 .start = statement->location.start,
4764 .end = predicate->location.end
4767 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4768 .predicate = predicate,
4769 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4770 .statements = statements,
4772 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4781static pm_if_node_t *
4782pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_token_t *qmark, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
4783 pm_assert_value_expression(parser, predicate);
4784 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4786 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4787 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4789 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4790 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4792 pm_token_t end_keyword = not_provided(parser);
4793 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4795 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4797 *node = (pm_if_node_t) {
4800 .flags = PM_NODE_FLAG_NEWLINE,
4801 .node_id = PM_NODE_IDENTIFY(parser),
4803 .start = predicate->location.start,
4804 .end = false_expression->location.end,
4807 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4808 .predicate = predicate,
4809 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4810 .statements = if_statements,
4811 .subsequent = (pm_node_t *) else_node,
4812 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4820pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4821 node->base.location.end = keyword->end;
4822 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4826pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4827 node->base.location.end = keyword->end;
4828 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4834static pm_implicit_node_t *
4835pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4836 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4838 *node = (pm_implicit_node_t) {
4840 .type = PM_IMPLICIT_NODE,
4841 .node_id = PM_NODE_IDENTIFY(parser),
4842 .location = value->location
4853static pm_implicit_rest_node_t *
4854pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4855 assert(token->type == PM_TOKEN_COMMA);
4857 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4859 *node = (pm_implicit_rest_node_t) {
4861 .type = PM_IMPLICIT_REST_NODE,
4862 .node_id = PM_NODE_IDENTIFY(parser),
4863 .location = PM_LOCATION_TOKEN_VALUE(token)
4873static pm_integer_node_t *
4874pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4875 assert(token->type == PM_TOKEN_INTEGER);
4876 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4878 *node = (pm_integer_node_t) {
4880 .type = PM_INTEGER_NODE,
4881 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4882 .node_id = PM_NODE_IDENTIFY(parser),
4883 .location = PM_LOCATION_TOKEN_VALUE(token)
4888 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4890 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4891 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4892 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4893 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4894 default: assert(false && "unreachable"); break;
4897 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4905static pm_imaginary_node_t *
4906pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4907 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4909 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4910 *node = (pm_imaginary_node_t) {
4912 .type = PM_IMAGINARY_NODE,
4913 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4914 .node_id = PM_NODE_IDENTIFY(parser),
4915 .location = PM_LOCATION_TOKEN_VALUE(token)
4917 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4918 .type = PM_TOKEN_INTEGER,
4919 .start = token->start,
4920 .end = token->end - 1
4931static pm_rational_node_t *
4932pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4933 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4935 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4936 *node = (pm_rational_node_t) {
4938 .type = PM_RATIONAL_NODE,
4939 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4940 .node_id = PM_NODE_IDENTIFY(parser),
4941 .location = PM_LOCATION_TOKEN_VALUE(token)
4944 .denominator = { .value = 1, 0 }
4947 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4949 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4950 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4951 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4952 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4953 default: assert(false && "unreachable"); break;
4956 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4965static pm_imaginary_node_t *
4966pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4967 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4969 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4970 *node = (pm_imaginary_node_t) {
4972 .type = PM_IMAGINARY_NODE,
4973 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4974 .node_id = PM_NODE_IDENTIFY(parser),
4975 .location = PM_LOCATION_TOKEN_VALUE(token)
4977 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4978 .type = PM_TOKEN_INTEGER_RATIONAL,
4979 .start = token->start,
4980 .end = token->end - 1
4990static pm_in_node_t *
4991pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t *statements, const pm_token_t *in_keyword, const pm_token_t *then_keyword) {
4992 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4995 if (statements != NULL) {
4996 end = statements->base.location.end;
4997 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4998 end = then_keyword->end;
5000 end = pattern->location.end;
5003 *node = (pm_in_node_t) {
5006 .node_id = PM_NODE_IDENTIFY(parser),
5008 .start = in_keyword->start,
5013 .statements = statements,
5014 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5015 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5024static pm_instance_variable_and_write_node_t *
5025pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5026 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5027 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5029 *node = (pm_instance_variable_and_write_node_t) {
5031 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5032 .node_id = PM_NODE_IDENTIFY(parser),
5034 .start = target->base.location.start,
5035 .end = value->location.end
5038 .name = target->name,
5039 .name_loc = target->base.location,
5040 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5050static pm_instance_variable_operator_write_node_t *
5051pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5052 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5054 *node = (pm_instance_variable_operator_write_node_t) {
5056 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5057 .node_id = PM_NODE_IDENTIFY(parser),
5059 .start = target->base.location.start,
5060 .end = value->location.end
5063 .name = target->name,
5064 .name_loc = target->base.location,
5065 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5067 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5076static pm_instance_variable_or_write_node_t *
5077pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5078 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5079 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5081 *node = (pm_instance_variable_or_write_node_t) {
5083 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5084 .node_id = PM_NODE_IDENTIFY(parser),
5086 .start = target->base.location.start,
5087 .end = value->location.end
5090 .name = target->name,
5091 .name_loc = target->base.location,
5092 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5102static pm_instance_variable_read_node_t *
5103pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5104 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5105 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5107 *node = (pm_instance_variable_read_node_t) {
5109 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5110 .node_id = PM_NODE_IDENTIFY(parser),
5111 .location = PM_LOCATION_TOKEN_VALUE(token)
5113 .name = pm_parser_constant_id_token(parser, token)
5123static pm_instance_variable_write_node_t *
5124pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
5125 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5126 *node = (pm_instance_variable_write_node_t) {
5128 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5129 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5130 .node_id = PM_NODE_IDENTIFY(parser),
5132 .start = read_node->base.location.start,
5133 .end = value->location.end
5136 .name = read_node->name,
5137 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5138 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5151pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5152 switch (PM_NODE_TYPE(part)) {
5153 case PM_STRING_NODE:
5154 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5156 case PM_EMBEDDED_STATEMENTS_NODE: {
5157 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5158 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5160 if (embedded == NULL) {
5161 // If there are no statements or more than one statement, then
5162 // we lose the static literal flag.
5163 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5164 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5165 // If the embedded statement is a string, then we can keep the
5166 // static literal flag and mark the string as frozen.
5167 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5168 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5169 // If the embedded statement is an interpolated string and it's
5170 // a static literal, then we can keep the static literal flag.
5172 // Otherwise we lose the static literal flag.
5173 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5178 case PM_EMBEDDED_VARIABLE_NODE:
5179 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5182 assert(false && "unexpected node type");
5186 pm_node_list_append(parts, part);
5192static pm_interpolated_regular_expression_node_t *
5193pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5194 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5196 *node = (pm_interpolated_regular_expression_node_t) {
5198 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5199 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5200 .node_id = PM_NODE_IDENTIFY(parser),
5202 .start = opening->start,
5206 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5207 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5215pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5216 if (node->base.location.start > part->location.start) {
5217 node->base.location.start = part->location.start;
5219 if (node->base.location.end < part->location.end) {
5220 node->base.location.end = part->location.end;
5223 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5227pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5228 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5229 node->base.location.end = closing->end;
5230 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5257pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5258#define CLEAR_FLAGS(node) \
5259 node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
5261#define MUTABLE_FLAGS(node) \
5262 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5264 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5265 node->base.location.start = part->location.start;
5268 node->base.location.end = MAX(node->base.location.end, part->location.end);
5270 switch (PM_NODE_TYPE(part)) {
5271 case PM_STRING_NODE:
5272 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5274 case PM_INTERPOLATED_STRING_NODE:
5275 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5276 // If the string that we're concatenating is a static literal,
5277 // then we can keep the static literal flag for this string.
5279 // Otherwise, we lose the static literal flag here and we should
5280 // also clear the mutability flags.
5284 case PM_EMBEDDED_STATEMENTS_NODE: {
5285 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5286 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5288 if (embedded == NULL) {
5289 // If we're embedding multiple statements or no statements, then
5290 // the string is not longer a static literal.
5292 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5293 // If the embedded statement is a string, then we can make that
5294 // string as frozen and static literal, and not touch the static
5295 // literal status of this string.
5296 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5298 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5299 MUTABLE_FLAGS(node);
5301 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5302 // If the embedded statement is an interpolated string, but that
5303 // string is marked as static literal, then we can keep our
5304 // static literal status for this string.
5305 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5306 MUTABLE_FLAGS(node);
5309 // In all other cases, we lose the static literal flag here and
5316 case PM_EMBEDDED_VARIABLE_NODE:
5317 // Embedded variables clear static literal, which means we also
5318 // should clear the mutability flags.
5322 assert(false && "unexpected node type");
5326 pm_node_list_append(&node->parts, part);
5335static pm_interpolated_string_node_t *
5336pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5337 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5338 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5340 switch (parser->frozen_string_literal) {
5341 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5342 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5344 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5345 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5349 *node = (pm_interpolated_string_node_t) {
5351 .type = PM_INTERPOLATED_STRING_NODE,
5353 .node_id = PM_NODE_IDENTIFY(parser),
5355 .start = opening->start,
5356 .end = closing->end,
5359 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5360 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5364 if (parts != NULL) {
5366 PM_NODE_LIST_FOREACH(parts, index, part) {
5367 pm_interpolated_string_node_append(node, part);
5378pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5379 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5380 node->base.location.end = closing->end;
5384pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5385 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5386 node->base.location.start = part->location.start;
5389 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5390 node->base.location.end = MAX(node->base.location.end, part->location.end);
5394pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5395 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5396 node->base.location.end = closing->end;
5402static pm_interpolated_symbol_node_t *
5403pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5404 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5406 *node = (pm_interpolated_symbol_node_t) {
5408 .type = PM_INTERPOLATED_SYMBOL_NODE,
5409 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5410 .node_id = PM_NODE_IDENTIFY(parser),
5412 .start = opening->start,
5413 .end = closing->end,
5416 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5417 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5421 if (parts != NULL) {
5423 PM_NODE_LIST_FOREACH(parts, index, part) {
5424 pm_interpolated_symbol_node_append(node, part);
5434static pm_interpolated_x_string_node_t *
5435pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5436 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5438 *node = (pm_interpolated_x_string_node_t) {
5440 .type = PM_INTERPOLATED_X_STRING_NODE,
5441 .node_id = PM_NODE_IDENTIFY(parser),
5443 .start = opening->start,
5447 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5448 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5456pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5457 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5458 node->base.location.end = part->location.end;
5462pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5463 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5464 node->base.location.end = closing->end;
5470static pm_it_local_variable_read_node_t *
5471pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5472 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5474 *node = (pm_it_local_variable_read_node_t) {
5476 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5477 .node_id = PM_NODE_IDENTIFY(parser),
5478 .location = PM_LOCATION_TOKEN_VALUE(name)
5488static pm_it_parameters_node_t *
5489pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5490 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5492 *node = (pm_it_parameters_node_t) {
5494 .type = PM_IT_PARAMETERS_NODE,
5495 .node_id = PM_NODE_IDENTIFY(parser),
5497 .start = opening->start,
5509static pm_keyword_hash_node_t *
5510pm_keyword_hash_node_create(pm_parser_t *parser) {
5511 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5513 *node = (pm_keyword_hash_node_t) {
5515 .type = PM_KEYWORD_HASH_NODE,
5516 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5517 .node_id = PM_NODE_IDENTIFY(parser),
5518 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5530pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5531 // If the element being added is not an AssocNode or does not have a symbol
5532 // key, then we want to turn the SYMBOL_KEYS flag off.
5533 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5534 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5537 pm_node_list_append(&hash->elements, element);
5538 if (hash->base.location.start == NULL) {
5539 hash->base.location.start = element->location.start;
5541 hash->base.location.end = element->location.end;
5547static pm_required_keyword_parameter_node_t *
5548pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5549 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5551 *node = (pm_required_keyword_parameter_node_t) {
5553 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5554 .node_id = PM_NODE_IDENTIFY(parser),
5556 .start = name->start,
5560 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5561 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5570static pm_optional_keyword_parameter_node_t *
5571pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5572 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5574 *node = (pm_optional_keyword_parameter_node_t) {
5576 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5577 .node_id = PM_NODE_IDENTIFY(parser),
5579 .start = name->start,
5580 .end = value->location.end
5583 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5584 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5594static pm_keyword_rest_parameter_node_t *
5595pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5596 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5598 *node = (pm_keyword_rest_parameter_node_t) {
5600 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5601 .node_id = PM_NODE_IDENTIFY(parser),
5603 .start = operator->start,
5604 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5607 .name = pm_parser_optional_constant_id_token(parser, name),
5608 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5609 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5618static pm_lambda_node_t *
5619pm_lambda_node_create(
5620 pm_parser_t *parser,
5621 pm_constant_id_list_t *locals,
5622 const pm_token_t *operator,
5623 const pm_token_t *opening,
5624 const pm_token_t *closing,
5625 pm_node_t *parameters,
5628 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5630 *node = (pm_lambda_node_t) {
5632 .type = PM_LAMBDA_NODE,
5633 .node_id = PM_NODE_IDENTIFY(parser),
5635 .start = operator->start,
5640 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5641 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5642 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5643 .parameters = parameters,
5653static pm_local_variable_and_write_node_t *
5654pm_local_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
5655 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5656 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5657 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5659 *node = (pm_local_variable_and_write_node_t) {
5661 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5662 .node_id = PM_NODE_IDENTIFY(parser),
5664 .start = target->location.start,
5665 .end = value->location.end
5668 .name_loc = target->location,
5669 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5681static pm_local_variable_operator_write_node_t *
5682pm_local_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
5683 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5685 *node = (pm_local_variable_operator_write_node_t) {
5687 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5688 .node_id = PM_NODE_IDENTIFY(parser),
5690 .start = target->location.start,
5691 .end = value->location.end
5694 .name_loc = target->location,
5695 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5698 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5708static pm_local_variable_or_write_node_t *
5709pm_local_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
5710 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5711 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5712 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5714 *node = (pm_local_variable_or_write_node_t) {
5716 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5717 .node_id = PM_NODE_IDENTIFY(parser),
5719 .start = target->location.start,
5720 .end = value->location.end
5723 .name_loc = target->location,
5724 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5736static pm_local_variable_read_node_t *
5737pm_local_variable_read_node_create_constant_id(pm_parser_t *parser, const pm_token_t *name, pm_constant_id_t name_id, uint32_t depth, bool missing) {
5738 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5740 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5742 *node = (pm_local_variable_read_node_t) {
5744 .type = PM_LOCAL_VARIABLE_READ_NODE,
5745 .node_id = PM_NODE_IDENTIFY(parser),
5746 .location = PM_LOCATION_TOKEN_VALUE(name)
5758static pm_local_variable_read_node_t *
5759pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5760 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5761 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5768static pm_local_variable_read_node_t *
5769pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5770 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5771 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5777static pm_local_variable_write_node_t *
5778pm_local_variable_write_node_create(pm_parser_t *parser, pm_constant_id_t name, uint32_t depth, pm_node_t *value, const pm_location_t *name_loc, const pm_token_t *operator) {
5779 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5781 *node = (pm_local_variable_write_node_t) {
5783 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5784 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5785 .node_id = PM_NODE_IDENTIFY(parser),
5787 .start = name_loc->start,
5788 .end = value->location.end
5794 .name_loc = *name_loc,
5795 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5805pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5806 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5814pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5815 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5823pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5824 if (pm_token_is_numbered_parameter(start, end)) {
5825 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5833static pm_local_variable_target_node_t *
5834pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5835 pm_refute_numbered_parameter(parser, location->start, location->end);
5836 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5838 *node = (pm_local_variable_target_node_t) {
5840 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5841 .node_id = PM_NODE_IDENTIFY(parser),
5842 .location = *location
5854static pm_match_predicate_node_t *
5855pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5856 pm_assert_value_expression(parser, value);
5858 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5860 *node = (pm_match_predicate_node_t) {
5862 .type = PM_MATCH_PREDICATE_NODE,
5863 .node_id = PM_NODE_IDENTIFY(parser),
5865 .start = value->location.start,
5866 .end = pattern->location.end
5871 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5880static pm_match_required_node_t *
5881pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5882 pm_assert_value_expression(parser, value);
5884 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5886 *node = (pm_match_required_node_t) {
5888 .type = PM_MATCH_REQUIRED_NODE,
5889 .node_id = PM_NODE_IDENTIFY(parser),
5891 .start = value->location.start,
5892 .end = pattern->location.end
5897 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5906static pm_match_write_node_t *
5907pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5908 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5910 *node = (pm_match_write_node_t) {
5912 .type = PM_MATCH_WRITE_NODE,
5913 .node_id = PM_NODE_IDENTIFY(parser),
5914 .location = call->base.location
5926static pm_module_node_t *
5927pm_module_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *module_keyword, pm_node_t *constant_path, const pm_token_t *name, pm_node_t *body, const pm_token_t *end_keyword) {
5928 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5930 *node = (pm_module_node_t) {
5932 .type = PM_MODULE_NODE,
5933 .node_id = PM_NODE_IDENTIFY(parser),
5935 .start = module_keyword->start,
5936 .end = end_keyword->end
5939 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5940 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5941 .constant_path = constant_path,
5943 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5944 .name = pm_parser_constant_id_token(parser, name)
5953static pm_multi_target_node_t *
5954pm_multi_target_node_create(pm_parser_t *parser) {
5955 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5957 *node = (pm_multi_target_node_t) {
5959 .type = PM_MULTI_TARGET_NODE,
5960 .node_id = PM_NODE_IDENTIFY(parser),
5961 .location = { .start = NULL, .end = NULL }
5966 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5967 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5977pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5978 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5979 if (node->rest == NULL) {
5980 node->rest = target;
5982 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5983 pm_node_list_append(&node->rights, target);
5985 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5986 if (node->rest == NULL) {
5987 node->rest = target;
5989 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5990 pm_node_list_append(&node->rights, target);
5992 } else if (node->rest == NULL) {
5993 pm_node_list_append(&node->lefts, target);
5995 pm_node_list_append(&node->rights, target);
5998 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
5999 node->base.location.start = target->location.start;
6002 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6003 node->base.location.end = target->location.end;
6011pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6012 node->base.location.start = lparen->start;
6013 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6020pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6021 node->base.location.end = rparen->end;
6022 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6028static pm_multi_write_node_t *
6029pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6030 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6032 *node = (pm_multi_write_node_t) {
6034 .type = PM_MULTI_WRITE_NODE,
6035 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6036 .node_id = PM_NODE_IDENTIFY(parser),
6038 .start = target->base.location.start,
6039 .end = value->location.end
6042 .lefts = target->lefts,
6043 .rest = target->rest,
6044 .rights = target->rights,
6045 .lparen_loc = target->lparen_loc,
6046 .rparen_loc = target->rparen_loc,
6047 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6051 // Explicitly do not call pm_node_destroy here because we want to keep
6052 // around all of the information within the MultiWriteNode node.
6061static pm_next_node_t *
6062pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6063 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6064 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6066 *node = (pm_next_node_t) {
6068 .type = PM_NEXT_NODE,
6069 .node_id = PM_NODE_IDENTIFY(parser),
6071 .start = keyword->start,
6072 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6075 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6076 .arguments = arguments
6085static pm_nil_node_t *
6086pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6087 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6088 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6090 *node = (pm_nil_node_t) {{
6091 .type = PM_NIL_NODE,
6092 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6093 .node_id = PM_NODE_IDENTIFY(parser),
6094 .location = PM_LOCATION_TOKEN_VALUE(token)
6103static pm_no_keywords_parameter_node_t *
6104pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6105 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6106 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6107 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6109 *node = (pm_no_keywords_parameter_node_t) {
6111 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6112 .node_id = PM_NODE_IDENTIFY(parser),
6114 .start = operator->start,
6118 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6119 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6128static pm_numbered_parameters_node_t *
6129pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6130 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6132 *node = (pm_numbered_parameters_node_t) {
6134 .type = PM_NUMBERED_PARAMETERS_NODE,
6135 .node_id = PM_NODE_IDENTIFY(parser),
6136 .location = *location
6148#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6157pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6158 const uint8_t *start = token->start + 1;
6159 const uint8_t *end = token->end;
6161 ptrdiff_t diff = end - start;
6162 assert(diff > 0 && ((unsigned long) diff < SIZE_MAX));
6163 size_t length = (size_t) diff;
6165 char *digits = xcalloc(length + 1, sizeof(char));
6166 memcpy(digits, start, length);
6167 digits[length] = '\0';
6171 unsigned long value = strtoul(digits, &endptr, 10);
6173 if ((digits == endptr) || (*endptr != '\0')) {
6174 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6180 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6181 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6185 return (uint32_t) value;
6193static pm_numbered_reference_read_node_t *
6194pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6195 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6196 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6198 *node = (pm_numbered_reference_read_node_t) {
6200 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6201 .node_id = PM_NODE_IDENTIFY(parser),
6202 .location = PM_LOCATION_TOKEN_VALUE(name),
6204 .number = pm_numbered_reference_read_node_number(parser, name)
6213static pm_optional_parameter_node_t *
6214pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6215 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6217 *node = (pm_optional_parameter_node_t) {
6219 .type = PM_OPTIONAL_PARAMETER_NODE,
6220 .node_id = PM_NODE_IDENTIFY(parser),
6222 .start = name->start,
6223 .end = value->location.end
6226 .name = pm_parser_constant_id_token(parser, name),
6227 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6228 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6238static pm_or_node_t *
6239pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6240 pm_assert_value_expression(parser, left);
6242 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6244 *node = (pm_or_node_t) {
6247 .node_id = PM_NODE_IDENTIFY(parser),
6249 .start = left->location.start,
6250 .end = right->location.end
6255 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6264static pm_parameters_node_t *
6265pm_parameters_node_create(pm_parser_t *parser) {
6266 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6268 *node = (pm_parameters_node_t) {
6270 .type = PM_PARAMETERS_NODE,
6271 .node_id = PM_NODE_IDENTIFY(parser),
6272 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6275 .keyword_rest = NULL,
6290pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6291 if (params->base.location.start == NULL) {
6292 params->base.location.start = param->location.start;
6294 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6297 if (params->base.location.end == NULL) {
6298 params->base.location.end = param->location.end;
6300 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6308pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6309 pm_parameters_node_location_set(params, param);
6310 pm_node_list_append(¶ms->requireds, param);
6317pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6318 pm_parameters_node_location_set(params, (pm_node_t *) param);
6319 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6326pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6327 pm_parameters_node_location_set(params, param);
6328 pm_node_list_append(¶ms->posts, param);
6335pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6336 pm_parameters_node_location_set(params, param);
6337 params->rest = param;
6344pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6345 pm_parameters_node_location_set(params, param);
6346 pm_node_list_append(¶ms->keywords, param);
6353pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6354 assert(params->keyword_rest == NULL);
6355 pm_parameters_node_location_set(params, param);
6356 params->keyword_rest = param;
6363pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6364 assert(params->block == NULL);
6365 pm_parameters_node_location_set(params, (pm_node_t *) param);
6366 params->block = param;
6372static pm_program_node_t *
6373pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6374 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6376 *node = (pm_program_node_t) {
6378 .type = PM_PROGRAM_NODE,
6379 .node_id = PM_NODE_IDENTIFY(parser),
6381 .start = statements == NULL ? parser->start : statements->base.location.start,
6382 .end = statements == NULL ? parser->end : statements->base.location.end
6386 .statements = statements
6395static pm_parentheses_node_t *
6396pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
6397 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6399 *node = (pm_parentheses_node_t) {
6401 .type = PM_PARENTHESES_NODE,
6402 .node_id = PM_NODE_IDENTIFY(parser),
6404 .start = opening->start,
6409 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6410 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6419static pm_pinned_expression_node_t *
6420pm_pinned_expression_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *operator, const pm_token_t *lparen, const pm_token_t *rparen) {
6421 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6423 *node = (pm_pinned_expression_node_t) {
6425 .type = PM_PINNED_EXPRESSION_NODE,
6426 .node_id = PM_NODE_IDENTIFY(parser),
6428 .start = operator->start,
6432 .expression = expression,
6433 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6434 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6435 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6444static pm_pinned_variable_node_t *
6445pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6446 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6448 *node = (pm_pinned_variable_node_t) {
6450 .type = PM_PINNED_VARIABLE_NODE,
6451 .node_id = PM_NODE_IDENTIFY(parser),
6453 .start = operator->start,
6454 .end = variable->location.end
6457 .variable = variable,
6458 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6467static pm_post_execution_node_t *
6468pm_post_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
6469 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6471 *node = (pm_post_execution_node_t) {
6473 .type = PM_POST_EXECUTION_NODE,
6474 .node_id = PM_NODE_IDENTIFY(parser),
6476 .start = keyword->start,
6480 .statements = statements,
6481 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6482 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6483 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6492static pm_pre_execution_node_t *
6493pm_pre_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
6494 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6496 *node = (pm_pre_execution_node_t) {
6498 .type = PM_PRE_EXECUTION_NODE,
6499 .node_id = PM_NODE_IDENTIFY(parser),
6501 .start = keyword->start,
6505 .statements = statements,
6506 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6507 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6508 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6517static pm_range_node_t *
6518pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6519 pm_assert_value_expression(parser, left);
6520 pm_assert_value_expression(parser, right);
6522 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6523 pm_node_flags_t flags = 0;
6525 // Indicate that this node is an exclusive range if the operator is `...`.
6526 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6527 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6530 // Indicate that this node is a static literal (i.e., can be compiled with
6531 // a putobject in CRuby) if the left and right are implicit nil, explicit
6532 // nil, or integers.
6534 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6535 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6537 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6540 *node = (pm_range_node_t) {
6542 .type = PM_RANGE_NODE,
6544 .node_id = PM_NODE_IDENTIFY(parser),
6546 .start = (left == NULL ? operator->start : left->location.start),
6547 .end = (right == NULL ? operator->end : right->location.end)
6552 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6561static pm_redo_node_t *
6562pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6563 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6564 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6566 *node = (pm_redo_node_t) {{
6567 .type = PM_REDO_NODE,
6568 .node_id = PM_NODE_IDENTIFY(parser),
6569 .location = PM_LOCATION_TOKEN_VALUE(token)
6579static pm_regular_expression_node_t *
6580pm_regular_expression_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
6581 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6583 *node = (pm_regular_expression_node_t) {
6585 .type = PM_REGULAR_EXPRESSION_NODE,
6586 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6587 .node_id = PM_NODE_IDENTIFY(parser),
6589 .start = MIN(opening->start, closing->start),
6590 .end = MAX(opening->end, closing->end)
6593 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6594 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6595 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6596 .unescaped = *unescaped
6605static inline pm_regular_expression_node_t *
6606pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6607 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6613static pm_required_parameter_node_t *
6614pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6615 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6617 *node = (pm_required_parameter_node_t) {
6619 .type = PM_REQUIRED_PARAMETER_NODE,
6620 .node_id = PM_NODE_IDENTIFY(parser),
6621 .location = PM_LOCATION_TOKEN_VALUE(token)
6623 .name = pm_parser_constant_id_token(parser, token)
6632static pm_rescue_modifier_node_t *
6633pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6634 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6636 *node = (pm_rescue_modifier_node_t) {
6638 .type = PM_RESCUE_MODIFIER_NODE,
6639 .node_id = PM_NODE_IDENTIFY(parser),
6641 .start = expression->location.start,
6642 .end = rescue_expression->location.end
6645 .expression = expression,
6646 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6647 .rescue_expression = rescue_expression
6656static pm_rescue_node_t *
6657pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6658 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6660 *node = (pm_rescue_node_t) {
6662 .type = PM_RESCUE_NODE,
6663 .node_id = PM_NODE_IDENTIFY(parser),
6664 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6666 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6667 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6678pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6679 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6686pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6687 node->reference = reference;
6688 node->base.location.end = reference->location.end;
6695pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6696 node->statements = statements;
6697 if (pm_statements_node_body_length(statements) > 0) {
6698 node->base.location.end = statements->base.location.end;
6706pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6707 node->subsequent = subsequent;
6708 node->base.location.end = subsequent->base.location.end;
6715pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6716 pm_node_list_append(&node->exceptions, exception);
6717 node->base.location.end = exception->location.end;
6723static pm_rest_parameter_node_t *
6724pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6725 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6727 *node = (pm_rest_parameter_node_t) {
6729 .type = PM_REST_PARAMETER_NODE,
6730 .node_id = PM_NODE_IDENTIFY(parser),
6732 .start = operator->start,
6733 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6736 .name = pm_parser_optional_constant_id_token(parser, name),
6737 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6738 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6747static pm_retry_node_t *
6748pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6749 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6750 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6752 *node = (pm_retry_node_t) {{
6753 .type = PM_RETRY_NODE,
6754 .node_id = PM_NODE_IDENTIFY(parser),
6755 .location = PM_LOCATION_TOKEN_VALUE(token)
6764static pm_return_node_t *
6765pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6766 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6768 *node = (pm_return_node_t) {
6770 .type = PM_RETURN_NODE,
6771 .node_id = PM_NODE_IDENTIFY(parser),
6773 .start = keyword->start,
6774 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6777 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6778 .arguments = arguments
6787static pm_self_node_t *
6788pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6789 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6790 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6792 *node = (pm_self_node_t) {{
6793 .type = PM_SELF_NODE,
6794 .node_id = PM_NODE_IDENTIFY(parser),
6795 .location = PM_LOCATION_TOKEN_VALUE(token)
6804static pm_shareable_constant_node_t *
6805pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6806 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6808 *node = (pm_shareable_constant_node_t) {
6810 .type = PM_SHAREABLE_CONSTANT_NODE,
6811 .flags = (pm_node_flags_t) value,
6812 .node_id = PM_NODE_IDENTIFY(parser),
6813 .location = PM_LOCATION_NODE_VALUE(write)
6824static pm_singleton_class_node_t *
6825pm_singleton_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, const pm_token_t *operator, pm_node_t *expression, pm_node_t *body, const pm_token_t *end_keyword) {
6826 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6828 *node = (pm_singleton_class_node_t) {
6830 .type = PM_SINGLETON_CLASS_NODE,
6831 .node_id = PM_NODE_IDENTIFY(parser),
6833 .start = class_keyword->start,
6834 .end = end_keyword->end
6838 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6839 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6840 .expression = expression,
6842 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6851static pm_source_encoding_node_t *
6852pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6853 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6854 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6856 *node = (pm_source_encoding_node_t) {{
6857 .type = PM_SOURCE_ENCODING_NODE,
6858 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6859 .node_id = PM_NODE_IDENTIFY(parser),
6860 .location = PM_LOCATION_TOKEN_VALUE(token)
6869static pm_source_file_node_t*
6870pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6871 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6872 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6874 pm_node_flags_t flags = 0;
6876 switch (parser->frozen_string_literal) {
6877 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6878 flags |= PM_STRING_FLAGS_MUTABLE;
6880 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6881 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6885 *node = (pm_source_file_node_t) {
6887 .type = PM_SOURCE_FILE_NODE,
6889 .node_id = PM_NODE_IDENTIFY(parser),
6890 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6892 .filepath = parser->filepath
6901static pm_source_line_node_t *
6902pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6903 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6904 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6906 *node = (pm_source_line_node_t) {{
6907 .type = PM_SOURCE_LINE_NODE,
6908 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6909 .node_id = PM_NODE_IDENTIFY(parser),
6910 .location = PM_LOCATION_TOKEN_VALUE(token)
6919static pm_splat_node_t *
6920pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6921 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6923 *node = (pm_splat_node_t) {
6925 .type = PM_SPLAT_NODE,
6926 .node_id = PM_NODE_IDENTIFY(parser),
6928 .start = operator->start,
6929 .end = (expression == NULL ? operator->end : expression->location.end)
6932 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6933 .expression = expression
6942static pm_statements_node_t *
6943pm_statements_node_create(pm_parser_t *parser) {
6944 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6946 *node = (pm_statements_node_t) {
6948 .type = PM_STATEMENTS_NODE,
6949 .node_id = PM_NODE_IDENTIFY(parser),
6950 .location = PM_LOCATION_NULL_VALUE(parser)
6962pm_statements_node_body_length(pm_statements_node_t *node) {
6963 return node && node->body.size;
6970pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6971 node->base.location = (pm_location_t) { .start = start, .end = end };
6979pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6980 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6981 node->base.location.start = statement->location.start;
6984 if (statement->location.end > node->base.location.end) {
6985 node->base.location.end = statement->location.end;
6993pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6994 pm_statements_node_body_update(node, statement);
6996 if (node->body.size > 0) {
6997 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6999 switch (PM_NODE_TYPE(previous)) {
7004 case PM_RETURN_NODE:
7005 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7012 pm_node_list_append(&node->body, statement);
7013 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7020pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7021 pm_statements_node_body_update(node, statement);
7022 pm_node_list_prepend(&node->body, statement);
7023 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7029static inline pm_string_node_t *
7030pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *string) {
7031 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7032 pm_node_flags_t flags = 0;
7034 switch (parser->frozen_string_literal) {
7035 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7036 flags = PM_STRING_FLAGS_MUTABLE;
7038 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7039 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7043 *node = (pm_string_node_t) {
7045 .type = PM_STRING_NODE,
7047 .node_id = PM_NODE_IDENTIFY(parser),
7049 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7050 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7053 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7054 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7055 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7056 .unescaped = *string
7065static pm_string_node_t *
7066pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7067 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7074static pm_string_node_t *
7075pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7076 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7077 parser->current_string = PM_STRING_EMPTY;
7084static pm_super_node_t *
7085pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7086 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7087 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7089 const uint8_t *end = pm_arguments_end(arguments);
7091 assert(false && "unreachable");
7094 *node = (pm_super_node_t) {
7096 .type = PM_SUPER_NODE,
7097 .node_id = PM_NODE_IDENTIFY(parser),
7099 .start = keyword->start,
7103 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7104 .lparen_loc = arguments->opening_loc,
7105 .arguments = arguments->arguments,
7106 .rparen_loc = arguments->closing_loc,
7107 .block = arguments->block
7118pm_ascii_only_p(const pm_string_t *contents) {
7119 const size_t length = pm_string_length(contents);
7120 const uint8_t *source = pm_string_source(contents);
7122 for (size_t index = 0; index < length; index++) {
7123 if (source[index] & 0x80) return false;
7133parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7134 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7135 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7138 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7151parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7152 const pm_encoding_t *encoding = parser->encoding;
7154 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7155 size_t width = encoding->char_width(cursor, end - cursor);
7158 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7175static inline pm_node_flags_t
7176parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7177 if (parser->explicit_encoding != NULL) {
7178 // A Symbol may optionally have its encoding explicitly set. This will
7179 // happen if an escape sequence results in a non-ASCII code point.
7180 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7181 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7182 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7183 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7184 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7185 } else if (validate) {
7186 parse_symbol_encoding_validate_other(parser, location, contents);
7188 } else if (pm_ascii_only_p(contents)) {
7189 // Ruby stipulates that all source files must use an ASCII-compatible
7190 // encoding. Thus, all symbols appearing in source are eligible for
7191 // "downgrading" to US-ASCII.
7192 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7193 } else if (validate) {
7194 parse_symbol_encoding_validate_other(parser, location, contents);
7200static pm_node_flags_t
7201parse_and_validate_regular_expression_encoding_modifier(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags, char modifier, const pm_encoding_t *modifier_encoding) {
7202 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7203 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7204 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7205 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7207 // There's special validation logic used if a string does not contain any character escape sequences.
7208 if (parser->explicit_encoding == NULL) {
7209 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7210 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7211 // the US-ASCII encoding.
7213 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7216 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7218 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7220 } else if (parser->encoding != modifier_encoding) {
7221 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7223 if (modifier == 'n' && !ascii_only) {
7224 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) pm_string_length(source), (const char *) pm_string_source(source));
7231 // TODO (nirvdrum 21-Feb-2024): To validate regexp sources with character escape sequences we need to know whether hex or Unicode escape sequences were used and Prism doesn't currently provide that data. We handle a subset of unambiguous cases in the meanwhile.
7232 bool mixed_encoding = false;
7234 if (mixed_encoding) {
7235 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7236 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7237 // TODO (nirvdrum 21-Feb-2024): Validate the content is valid in the modifier encoding. Do this on-demand so we don't pay the cost of computation unnecessarily.
7238 bool valid_string_in_modifier_encoding = true;
7240 if (!valid_string_in_modifier_encoding) {
7241 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7243 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7244 // TODO (nirvdrum 21-Feb-2024): There's currently no way to tell if the source used hex or Unicode character escapes from `explicit_encoding` alone. If the source encoding was already UTF-8, both character escape types would set `explicit_encoding` to UTF-8, but need to be processed differently. Skip for now.
7245 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7246 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, (int) pm_string_length(source), (const char *) pm_string_source(source));
7250 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7260static pm_node_flags_t
7261parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7262 // TODO (nirvdrum 22-Feb-2024): CRuby reports a special Regexp-specific error for invalid Unicode ranges. We either need to scan again or modify the "invalid Unicode escape sequence" message we already report.
7263 bool valid_unicode_range = true;
7264 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7265 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INVALID_UNICODE_RANGE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7269 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7270 // to multi-byte characters are allowed.
7271 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7272 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7273 // following error message appearing twice. We do the same for compatibility.
7274 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7285 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7286 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7289 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7290 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7293 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7294 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7297 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7298 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7301 // At this point no encoding modifiers will be present on the regular expression as they would have already
7302 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7303 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7305 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7308 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7309 // or by specifying a modifier.
7311 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7312 if (parser->explicit_encoding != NULL) {
7313 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7314 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7315 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7316 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7327static pm_symbol_node_t *
7328pm_symbol_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing, const pm_string_t *unescaped, pm_node_flags_t flags) {
7329 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7331 *node = (pm_symbol_node_t) {
7333 .type = PM_SYMBOL_NODE,
7334 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7335 .node_id = PM_NODE_IDENTIFY(parser),
7337 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7338 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7341 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7342 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7343 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7344 .unescaped = *unescaped
7353static inline pm_symbol_node_t *
7354pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7355 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7361static pm_symbol_node_t *
7362pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7363 pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, value, &parser->current_string, false));
7364 parser->current_string = PM_STRING_EMPTY;
7371static pm_symbol_node_t *
7372pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7373 pm_symbol_node_t *node;
7375 switch (token->type) {
7376 case PM_TOKEN_LABEL: {
7377 pm_token_t opening = not_provided(parser);
7378 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7380 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7381 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7383 assert((label.end - label.start) >= 0);
7384 pm_string_shared_init(&node->unescaped, label.start, label.end);
7385 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7389 case PM_TOKEN_MISSING: {
7390 pm_token_t opening = not_provided(parser);
7391 pm_token_t closing = not_provided(parser);
7393 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7394 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7398 assert(false && "unreachable");
7409static pm_symbol_node_t *
7410pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7411 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7413 *node = (pm_symbol_node_t) {
7415 .type = PM_SYMBOL_NODE,
7416 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7417 .node_id = PM_NODE_IDENTIFY(parser),
7418 .location = PM_LOCATION_NULL_VALUE(parser)
7420 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7424 pm_string_constant_init(&node->unescaped, content, strlen(content));
7432pm_symbol_node_label_p(pm_node_t *node) {
7433 const uint8_t *end = NULL;
7435 switch (PM_NODE_TYPE(node)) {
7436 case PM_SYMBOL_NODE:
7437 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7439 case PM_INTERPOLATED_SYMBOL_NODE:
7440 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7446 return (end != NULL) && (end[-1] == ':');
7452static pm_symbol_node_t *
7453pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7454 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7456 *new_node = (pm_symbol_node_t) {
7458 .type = PM_SYMBOL_NODE,
7459 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7460 .node_id = PM_NODE_IDENTIFY(parser),
7462 .start = opening->start,
7466 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7467 .value_loc = node->content_loc,
7468 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7469 .unescaped = node->unescaped
7472 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7473 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7475 // We are explicitly _not_ using pm_node_destroy here because we don't want
7476 // to trash the unescaped string. We could instead copy the string if we
7477 // know that it is owned, but we're taking the fast path for now.
7486static pm_string_node_t *
7487pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7488 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7489 pm_node_flags_t flags = 0;
7491 switch (parser->frozen_string_literal) {
7492 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7493 flags = PM_STRING_FLAGS_MUTABLE;
7495 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7496 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7500 *new_node = (pm_string_node_t) {
7502 .type = PM_STRING_NODE,
7504 .node_id = PM_NODE_IDENTIFY(parser),
7505 .location = node->base.location
7507 .opening_loc = node->opening_loc,
7508 .content_loc = node->value_loc,
7509 .closing_loc = node->closing_loc,
7510 .unescaped = node->unescaped
7513 // We are explicitly _not_ using pm_node_destroy here because we don't want
7514 // to trash the unescaped string. We could instead copy the string if we
7515 // know that it is owned, but we're taking the fast path for now.
7524static pm_true_node_t *
7525pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7526 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7527 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7529 *node = (pm_true_node_t) {{
7530 .type = PM_TRUE_NODE,
7531 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7532 .node_id = PM_NODE_IDENTIFY(parser),
7533 .location = PM_LOCATION_TOKEN_VALUE(token)
7542static pm_true_node_t *
7543pm_true_node_synthesized_create(pm_parser_t *parser) {
7544 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7546 *node = (pm_true_node_t) {{
7547 .type = PM_TRUE_NODE,
7548 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7549 .node_id = PM_NODE_IDENTIFY(parser),
7550 .location = { .start = parser->start, .end = parser->end }
7559static pm_undef_node_t *
7560pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7561 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7562 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7564 *node = (pm_undef_node_t) {
7566 .type = PM_UNDEF_NODE,
7567 .node_id = PM_NODE_IDENTIFY(parser),
7568 .location = PM_LOCATION_TOKEN_VALUE(token),
7570 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7581pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7582 node->base.location.end = name->location.end;
7583 pm_node_list_append(&node->names, name);
7589static pm_unless_node_t *
7590pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, const pm_token_t *then_keyword, pm_statements_node_t *statements) {
7591 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7592 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7595 if (statements != NULL) {
7596 end = statements->base.location.end;
7598 end = predicate->location.end;
7601 *node = (pm_unless_node_t) {
7603 .type = PM_UNLESS_NODE,
7604 .flags = PM_NODE_FLAG_NEWLINE,
7605 .node_id = PM_NODE_IDENTIFY(parser),
7607 .start = keyword->start,
7611 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7612 .predicate = predicate,
7613 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7614 .statements = statements,
7615 .else_clause = NULL,
7616 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7625static pm_unless_node_t *
7626pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7627 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7628 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7630 pm_statements_node_t *statements = pm_statements_node_create(parser);
7631 pm_statements_node_body_append(parser, statements, statement, true);
7633 *node = (pm_unless_node_t) {
7635 .type = PM_UNLESS_NODE,
7636 .flags = PM_NODE_FLAG_NEWLINE,
7637 .node_id = PM_NODE_IDENTIFY(parser),
7639 .start = statement->location.start,
7640 .end = predicate->location.end
7643 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7644 .predicate = predicate,
7645 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7646 .statements = statements,
7647 .else_clause = NULL,
7648 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7655pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7656 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7657 node->base.location.end = end_keyword->end;
7666pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7667 assert(parser->current_block_exits != NULL);
7669 // All of the block exits that we want to remove should be within the
7670 // statements, and since we are modifying the statements, we shouldn't have
7671 // to check the end location.
7672 const uint8_t *start = statements->base.location.start;
7674 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7675 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7676 if (block_exit->location.start < start) break;
7678 // Implicitly remove from the list by lowering the size.
7679 parser->current_block_exits->size--;
7686static pm_until_node_t *
7687pm_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) {
7688 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7689 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7691 *node = (pm_until_node_t) {
7693 .type = PM_UNTIL_NODE,
7695 .node_id = PM_NODE_IDENTIFY(parser),
7697 .start = keyword->start,
7698 .end = closing->end,
7701 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7702 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7703 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7704 .predicate = predicate,
7705 .statements = statements
7714static pm_until_node_t *
7715pm_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) {
7716 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7717 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7718 pm_loop_modifier_block_exits(parser, statements);
7720 *node = (pm_until_node_t) {
7722 .type = PM_UNTIL_NODE,
7724 .node_id = PM_NODE_IDENTIFY(parser),
7726 .start = statements->base.location.start,
7727 .end = predicate->location.end,
7730 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7731 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7732 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7733 .predicate = predicate,
7734 .statements = statements
7743static pm_when_node_t *
7744pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7745 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7747 *node = (pm_when_node_t) {
7749 .type = PM_WHEN_NODE,
7750 .node_id = PM_NODE_IDENTIFY(parser),
7752 .start = keyword->start,
7756 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7758 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7769pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7770 node->base.location.end = condition->location.end;
7771 pm_node_list_append(&node->conditions, condition);
7778pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7779 node->base.location.end = then_keyword->end;
7780 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7787pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7788 if (statements->base.location.end > node->base.location.end) {
7789 node->base.location.end = statements->base.location.end;
7792 node->statements = statements;
7798static pm_while_node_t *
7799pm_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) {
7800 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7801 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7803 *node = (pm_while_node_t) {
7805 .type = PM_WHILE_NODE,
7807 .node_id = PM_NODE_IDENTIFY(parser),
7809 .start = keyword->start,
7813 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7814 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7815 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7816 .predicate = predicate,
7817 .statements = statements
7826static pm_while_node_t *
7827pm_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) {
7828 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7829 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7830 pm_loop_modifier_block_exits(parser, statements);
7832 *node = (pm_while_node_t) {
7834 .type = PM_WHILE_NODE,
7836 .node_id = PM_NODE_IDENTIFY(parser),
7838 .start = statements->base.location.start,
7839 .end = predicate->location.end
7842 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7843 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7844 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7845 .predicate = predicate,
7846 .statements = statements
7855static pm_while_node_t *
7856pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7857 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7859 *node = (pm_while_node_t) {
7861 .type = PM_WHILE_NODE,
7862 .node_id = PM_NODE_IDENTIFY(parser),
7863 .location = PM_LOCATION_NULL_VALUE(parser)
7865 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7866 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7867 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7868 .predicate = predicate,
7869 .statements = statements
7879static pm_x_string_node_t *
7880pm_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) {
7881 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7883 *node = (pm_x_string_node_t) {
7885 .type = PM_X_STRING_NODE,
7886 .flags = PM_STRING_FLAGS_FROZEN,
7887 .node_id = PM_NODE_IDENTIFY(parser),
7889 .start = opening->start,
7893 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7894 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7895 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7896 .unescaped = *unescaped
7905static inline pm_x_string_node_t *
7906pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7907 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7913static pm_yield_node_t *
7914pm_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) {
7915 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7918 if (rparen_loc->start != NULL) {
7919 end = rparen_loc->end;
7920 } else if (arguments != NULL) {
7921 end = arguments->base.location.end;
7922 } else if (lparen_loc->start != NULL) {
7923 end = lparen_loc->end;
7928 *node = (pm_yield_node_t) {
7930 .type = PM_YIELD_NODE,
7931 .node_id = PM_NODE_IDENTIFY(parser),
7933 .start = keyword->start,
7937 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7938 .lparen_loc = *lparen_loc,
7939 .arguments = arguments,
7940 .rparen_loc = *rparen_loc
7947#undef PM_NODE_IDENTIFY
7954pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7955 pm_scope_t *scope = parser->current_scope;
7958 while (scope != NULL) {
7959 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7960 if (scope->closed) break;
7962 scope = scope->previous;
7975pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7976 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7983pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7984 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7990static pm_constant_id_t
7991pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7992 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7993 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8000static inline pm_constant_id_t
8001pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8002 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8008static pm_constant_id_t
8009pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8010 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8011 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8018static pm_constant_id_t
8019pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8020 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8021 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8033pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8034 // We want to check whether the parameter name is a numbered parameter or
8036 pm_refute_numbered_parameter(parser, name->start, name->end);
8038 // Otherwise we'll fetch the constant id for the parameter name and check
8039 // whether it's already in the current scope.
8040 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8042 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8043 // Add an error if the parameter doesn't start with _ and has been seen before
8044 if ((name->start < name->end) && (*name->start != '_')) {
8045 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8056pm_parser_scope_pop(pm_parser_t *parser) {
8057 pm_scope_t *scope = parser->current_scope;
8058 parser->current_scope = scope->previous;
8059 pm_locals_free(&scope->locals);
8060 pm_node_list_free(&scope->implicit_parameters);
8064/******************************************************************************/
8066/******************************************************************************/
8072pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8073 *stack = (*stack << 1) | (value & 1);
8080pm_state_stack_pop(pm_state_stack_t *stack) {
8088pm_state_stack_p(const pm_state_stack_t *stack) {
8093pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8094 // Use the negation of the value to prevent stack overflow.
8095 pm_state_stack_push(&parser->accepts_block_stack, !value);
8099pm_accepts_block_stack_pop(pm_parser_t *parser) {
8100 pm_state_stack_pop(&parser->accepts_block_stack);
8104pm_accepts_block_stack_p(pm_parser_t *parser) {
8105 return !pm_state_stack_p(&parser->accepts_block_stack);
8109pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8110 pm_state_stack_push(&parser->do_loop_stack, value);
8114pm_do_loop_stack_pop(pm_parser_t *parser) {
8115 pm_state_stack_pop(&parser->do_loop_stack);
8119pm_do_loop_stack_p(pm_parser_t *parser) {
8120 return pm_state_stack_p(&parser->do_loop_stack);
8123/******************************************************************************/
8124/* Lexer check helpers */
8125/******************************************************************************/
8131static inline uint8_t
8132peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8133 if (cursor < parser->end) {
8145static inline uint8_t
8146peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8147 return peek_at(parser, parser->current.end + offset);
8154static inline uint8_t
8155peek(const pm_parser_t *parser) {
8156 return peek_at(parser, parser->current.end);
8164match(pm_parser_t *parser, uint8_t value) {
8165 if (peek(parser) == value) {
8166 parser->current.end++;
8177match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8178 if (peek_at(parser, cursor) == '\n') {
8181 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8193match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8194 return match_eol_at(parser, parser->current.end + offset);
8203match_eol(pm_parser_t *parser) {
8204 return match_eol_at(parser, parser->current.end);
8210static inline const uint8_t *
8211next_newline(const uint8_t *cursor, ptrdiff_t length) {
8212 assert(length >= 0);
8214 // Note that it's okay for us to use memchr here to look for \n because none
8215 // of the encodings that we support have \n as a component of a multi-byte
8217 return memchr(cursor, '\n', (size_t) length);
8224ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8225 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));
8233parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8234 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8236 if (encoding != NULL) {
8237 if (parser->encoding != encoding) {
8238 parser->encoding = encoding;
8239 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8242 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8254parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8255 const uint8_t *cursor = parser->current.start + 1;
8256 const uint8_t *end = parser->current.end;
8258 bool separator = false;
8260 if (end - cursor <= 6) return;
8261 switch (cursor[6]) {
8262 case 'C': case 'c': cursor += 6; continue;
8263 case 'O': case 'o': cursor += 5; continue;
8264 case 'D': case 'd': cursor += 4; continue;
8265 case 'I': case 'i': cursor += 3; continue;
8266 case 'N': case 'n': cursor += 2; continue;
8267 case 'G': case 'g': cursor += 1; continue;
8274 if (pm_char_is_whitespace(*cursor)) break;
8277 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8283 if (++cursor >= end) return;
8284 } while (pm_char_is_whitespace(*cursor));
8286 if (separator) break;
8287 if (*cursor != '=' && *cursor != ':') return;
8293 const uint8_t *value_start = cursor;
8294 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8296 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8297 // If we were unable to parse the encoding value, then we've got an
8298 // issue because we didn't understand the encoding that the user was
8299 // trying to use. In this case we'll keep using the default encoding but
8300 // add an error to the parser to indicate an unsuccessful parse.
8301 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8306 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8307 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8308 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8309} pm_magic_comment_boolean_value_t;
8315static pm_magic_comment_boolean_value_t
8316parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8317 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8318 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8319 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8320 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8322 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8327pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8328 return b == '\'' || b == '"' || b == ':' || b == ';';
8336static inline const uint8_t *
8337parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8338 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8339 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8358parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8361 const uint8_t *start = parser->
current.start + 1;
8362 const uint8_t *end = parser->
current.end;
8363 if (end - start <= 7)
return false;
8365 const uint8_t *cursor;
8366 bool indicator =
false;
8368 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8371 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8382 while (cursor < end) {
8383 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8385 const uint8_t *key_start = cursor;
8386 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8388 const uint8_t *key_end = cursor;
8389 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8390 if (cursor == end)
break;
8392 if (*cursor ==
':') {
8395 if (!indicator)
return false;
8399 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8400 if (cursor == end)
break;
8402 const uint8_t *value_start;
8403 const uint8_t *value_end;
8405 if (*cursor ==
'"') {
8406 value_start = ++cursor;
8407 for (; cursor < end && *cursor !=
'"'; cursor++) {
8408 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8411 if (*cursor ==
'"') cursor++;
8413 value_start = cursor;
8414 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8419 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8421 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8422 if (cursor != end)
return false;
8428 const size_t key_length = (size_t) (key_end - key_start);
8432 pm_string_shared_init(&key, key_start, key_end);
8434 uint8_t *buffer =
xmalloc(key_length);
8435 if (buffer == NULL)
break;
8437 memcpy(buffer, key_start, key_length);
8438 buffer[dash - key_start] =
'_';
8440 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8441 buffer[dash - key_start] =
'_';
8444 pm_string_owned_init(&key, buffer, key_length);
8449 const uint8_t *key_source = pm_string_source(&key);
8450 uint32_t value_length = (uint32_t) (value_end - value_start);
8456 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8457 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8459 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8463 if (key_length == 11) {
8464 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8465 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8466 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8467 PM_PARSER_WARN_TOKEN_FORMAT(
8470 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8472 (
const char *) key_source,
8474 (
const char *) value_start
8477 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8480 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8485 }
else if (key_length == 21) {
8486 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8489 if (semantic_token_seen) {
8490 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8492 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8493 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8494 PM_PARSER_WARN_TOKEN_FORMAT(
8497 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8499 (
const char *) key_source,
8501 (
const char *) value_start
8504 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8507 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8513 }
else if (key_length == 24) {
8514 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8515 const uint8_t *cursor = parser->
current.start;
8516 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8518 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8519 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8520 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8521 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8522 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8523 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8524 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8525 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8526 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8527 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8529 PM_PARSER_WARN_TOKEN_FORMAT(
8532 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8534 (
const char *) key_source,
8536 (
const char *) value_start
8544 pm_string_free(&key);
8653 while (context_node != NULL) {
8654 if (context_terminator(context_node->
context, token))
return context_node->
context;
8655 context_node = context_node->
prev;
8664 if (context_node == NULL)
return false;
8689 while (context_node != NULL) {
8690 if (context_node->
context == context)
return true;
8691 context_node = context_node->
prev;
8701 while (context_node != NULL) {
8702 switch (context_node->
context) {
8723 context_node = context_node->
prev;
8738 assert(
false &&
"unreachable");
8795 assert(
false &&
"unreachable");
8804pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8805 if (invalid != NULL) {
8806 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8807 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8812pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8813 const uint8_t *invalid = NULL;
8814 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8815 pm_strspn_number_validate(parser,
string, length, invalid);
8820pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8821 const uint8_t *invalid = NULL;
8822 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8823 pm_strspn_number_validate(parser,
string, length, invalid);
8828pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8829 const uint8_t *invalid = NULL;
8830 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8831 pm_strspn_number_validate(parser,
string, length, invalid);
8836pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8837 const uint8_t *invalid = NULL;
8838 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8839 pm_strspn_number_validate(parser,
string, length, invalid);
8844lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8849 if (peek(parser) ==
'.') {
8850 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8852 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8863 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8864 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8867 if (pm_char_is_decimal_digit(peek(parser))) {
8869 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8871 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8873 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8875 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8888lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8892 if (peek_offset(parser, -1) ==
'0') {
8893 switch (*parser->
current.end) {
8898 if (pm_char_is_decimal_digit(peek(parser))) {
8899 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8902 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8911 if (pm_char_is_binary_digit(peek(parser))) {
8912 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8915 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8925 if (pm_char_is_octal_digit(peek(parser))) {
8926 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8929 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8945 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8953 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8954 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8957 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8965 type = lex_optional_float_suffix(parser, seen_e);
8972 type = lex_optional_float_suffix(parser, seen_e);
8979 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8982 type = lex_optional_float_suffix(parser, seen_e);
8988 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8989 const uint8_t *fraction_start = parser->
current.end;
8990 const uint8_t *fraction_end = parser->
current.end + 2;
8991 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8992 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9004 bool seen_e =
false;
9005 type = lex_numeric_prefix(parser, &seen_e);
9007 const uint8_t *end = parser->
current.end;
9011 if (match(parser,
'r')) {
9014 if (match(parser,
'i')) {
9017 }
else if (match(parser,
'i')) {
9021 if (!seen_e && match(parser,
'r')) {
9024 if (match(parser,
'i')) {
9027 }
else if (match(parser,
'i')) {
9032 const uint8_t b = peek(parser);
9033 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9046 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9052 bool allow_multiple =
true;
9054 switch (*parser->
current.end) {
9085 if (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0) {
9088 }
while (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0);
9092 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9112 allow_multiple =
false;
9117 if ((width = char_is_identifier(parser, parser->
current.end)) > 0) {
9120 }
while (allow_multiple && parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0);
9121 }
else if (pm_char_is_whitespace(peek(parser))) {
9124 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9130 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9152 if (memcmp(current_start, value, vlen) == 0) {
9155 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9156 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9158 lex_state_set(parser, state);
9159 if (state == PM_LEX_STATE_BEG) {
9163 if ((modifier_type !=
PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9164 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9165 return modifier_type;
9176lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9179 const uint8_t *end = parser->
end;
9180 const uint8_t *current_start = parser->
current.start;
9181 const uint8_t *current_end = parser->
current.end;
9184 if (encoding_changed) {
9185 while (current_end < end && (width = char_is_identifier(parser, current_end)) > 0) {
9186 current_end += width;
9189 while (current_end < end && (width = char_is_identifier_utf8(current_end, end)) > 0) {
9190 current_end += width;
9193 parser->
current.end = current_end;
9197 width = (size_t) (current_end - current_start);
9199 if (current_end < end) {
9200 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9206 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9207 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9211 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9212 (void) match(parser,
':');
9216 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9225 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,
'=')) {
9232 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9233 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9237 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9238 (void) match(parser,
':');
9243 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9248 if (pm_do_loop_stack_p(parser)) {
9309 if (encoding_changed) {
9339lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9342 if (pound + 1 >= parser->
end) {
9343 parser->
current.end = pound + 1;
9353 if (pound + 2 >= parser->
end) {
9354 parser->
current.end = pound + 1;
9360 const uint8_t *variable = pound + 2;
9361 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9363 if (char_is_identifier_start(parser, variable)) {
9367 if (pound > parser->
current.start) {
9374 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9375 parser->
current.end = pound + 1;
9382 parser->
current.end = pound + 1;
9388 if (pound + 2 >= parser->
end) {
9389 parser->
current.end = pound + 1;
9396 const uint8_t *check = pound + 2;
9398 if (pound[2] ==
'-') {
9399 if (pound + 3 >= parser->
end) {
9400 parser->
current.end = pound + 2;
9412 char_is_identifier_start(parser, check) ||
9413 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9418 if (pound > parser->
current.start) {
9425 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9426 parser->
current.end = pound + 1;
9432 parser->
current.end = pound + 1;
9438 if (pound > parser->
current.start) {
9447 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9448 parser->
current.end = pound + 2;
9450 pm_do_loop_stack_push(parser,
false);
9456 parser->
current.end = pound + 1;
9461static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9462static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9463static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9464static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9465static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9470static const bool ascii_printable_chars[] = {
9471 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9472 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9473 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9474 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9475 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9476 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9477 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9482char_is_ascii_printable(
const uint8_t b) {
9483 return (b < 0x80) && ascii_printable_chars[b];
9490static inline uint8_t
9491escape_hexadecimal_digit(
const uint8_t value) {
9492 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9500static inline uint32_t
9501escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9503 for (
size_t index = 0; index < length; index++) {
9504 if (index != 0) value <<= 4;
9505 value |= escape_hexadecimal_digit(
string[index]);
9510 if (value >= 0xD800 && value <= 0xDFFF) {
9511 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9521static inline uint8_t
9522escape_byte(uint8_t value,
const uint8_t flags) {
9523 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9524 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9532escape_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) {
9536 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9544 if (value <= 0x7F) {
9545 pm_buffer_append_byte(buffer, (uint8_t) value);
9546 }
else if (value <= 0x7FF) {
9547 pm_buffer_append_byte(buffer, (uint8_t) (0xC0 | (value >> 6)));
9548 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
9549 }
else if (value <= 0xFFFF) {
9550 pm_buffer_append_byte(buffer, (uint8_t) (0xE0 | (value >> 12)));
9551 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 6) & 0x3F)));
9552 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
9553 }
else if (value <= 0x10FFFF) {
9554 pm_buffer_append_byte(buffer, (uint8_t) (0xF0 | (value >> 18)));
9555 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 12) & 0x3F)));
9556 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 6) & 0x3F)));
9557 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
9559 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9560 pm_buffer_append_byte(buffer, 0xEF);
9561 pm_buffer_append_byte(buffer, 0xBF);
9562 pm_buffer_append_byte(buffer, 0xBD);
9574 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9580 pm_buffer_append_byte(buffer,
byte);
9592 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9597 width = (width == 0) ? 1 : width;
9599 for (
size_t index = 0; index < width; index++) {
9600 escape_write_byte_encoded(parser, buffer, *parser->
current.end);
9622 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9623 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9626 escape_write_byte_encoded(parser, buffer,
byte);
9635escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9636#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9638 PM_PARSER_WARN_TOKEN_FORMAT(
9641 PM_WARN_INVALID_CHARACTER,
9655 switch (peek(parser)) {
9658 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9663 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9668 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9673 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9678 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9683 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9688 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9693 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9698 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9703 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9708 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9711 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9712 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9715 if (pm_char_is_octal_digit(peek(parser))) {
9716 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9719 if (pm_char_is_octal_digit(peek(parser))) {
9720 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9725 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9729 const uint8_t *start = parser->
current.end - 1;
9732 uint8_t
byte = peek(parser);
9734 if (pm_char_is_hexadecimal_digit(
byte)) {
9735 uint8_t value = escape_hexadecimal_digit(
byte);
9738 byte = peek(parser);
9739 if (pm_char_is_hexadecimal_digit(
byte)) {
9740 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9744 value = escape_byte(value, flags);
9745 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9746 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9747 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9749 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9753 escape_write_byte_encoded(parser, buffer, value);
9755 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9761 const uint8_t *start = parser->
current.end - 1;
9765 const uint8_t *start = parser->
current.end - 2;
9766 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9767 }
else if (peek(parser) ==
'{') {
9768 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9773 if ((whitespace = pm_strspn_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9774 parser->
current.end += whitespace;
9775 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9786 const uint8_t *extra_codepoints_start = NULL;
9787 int codepoints_count = 0;
9790 const uint8_t *unicode_start = parser->
current.end;
9791 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9793 if (hexadecimal_length > 6) {
9795 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9796 }
else if (hexadecimal_length == 0) {
9799 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9803 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9805 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9806 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9812 parser->
current.end += hexadecimal_length;
9814 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9815 extra_codepoints_start = unicode_start;
9818 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9819 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9826 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9827 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9831 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9832 }
else if (peek(parser) ==
'}') {
9835 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9839 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9841 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9845 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9846 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9849 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9852 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9853 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9855 const uint8_t *start = parser->
current.end - 2;
9856 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9858 }
else if (length == 4) {
9859 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9861 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9862 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9865 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9868 parser->
current.end += length;
9870 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9874 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9876 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9885 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9886 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9890 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9894 uint8_t peeked = peek(parser);
9898 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9904 if (match(parser,
'u') || match(parser,
'U')) {
9905 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9909 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9913 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9914 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9918 escape_read_warn(parser, flags, 0,
"\\t");
9919 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9922 if (!char_is_ascii_printable(peeked)) {
9923 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9928 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9935 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9936 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9939 if (peek(parser) !=
'-') {
9941 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9947 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9951 uint8_t peeked = peek(parser);
9955 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9961 if (match(parser,
'u') || match(parser,
'U')) {
9962 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9966 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9970 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9971 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9975 escape_read_warn(parser, flags, 0,
"\\t");
9976 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9979 if (!char_is_ascii_printable(peeked)) {
9981 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9986 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9993 if (flags & PM_ESCAPE_FLAG_META) {
9994 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9997 if (peek(parser) !=
'-') {
9999 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10005 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10009 uint8_t peeked = peek(parser);
10014 if (match(parser,
'u') || match(parser,
'U')) {
10015 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10019 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10023 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10024 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10028 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10029 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10032 if (!char_is_ascii_printable(peeked)) {
10034 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10039 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10044 if (peek_offset(parser, 1) ==
'\n') {
10046 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10053 escape_write_escape_encoded(parser, buffer);
10055 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10089 if (lex_state_end_p(parser)) {
10090 lex_state_set(parser, PM_LEX_STATE_BEG);
10095 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10100 if (pm_char_is_whitespace(*parser->
current.end)) {
10101 lex_state_set(parser, PM_LEX_STATE_BEG);
10105 lex_state_set(parser, PM_LEX_STATE_BEG);
10107 if (match(parser,
'\\')) {
10108 lex_state_set(parser, PM_LEX_STATE_END);
10111 pm_buffer_init_capacity(&buffer, 3);
10113 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10125 (parser->
current.end + encoding_width >= parser->
end) ||
10126 !char_is_identifier(parser, parser->
current.end + encoding_width)
10129 lex_state_set(parser, PM_LEX_STATE_END);
10130 parser->
current.end += encoding_width;
10148 if (parser->
current.end < parser->
end && (width = char_is_identifier_start(parser, parser->
current.end)) > 0) {
10149 parser->
current.end += width;
10151 while (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0) {
10152 parser->
current.end += width;
10154 }
else if (parser->
current.end < parser->
end && pm_char_is_decimal_digit(*parser->
current.end)) {
10161 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10164 pm_parser_err_token(parser, &parser->
current, diag_id);
10170 lex_mode_pop(parser);
10192 if (comment == NULL)
return NULL;
10210 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10212 if (newline == NULL) {
10215 pm_newline_list_append(&parser->
newline_list, newline);
10216 parser->
current.end = newline + 1;
10220 parser_lex_callback(parser);
10223 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10228 while (parser->
current.end + 4 <= parser->
end) {
10234 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10237 pm_char_is_whitespace(parser->
current.end[4]) ||
10238 (parser->
current.end[4] ==
'\0') ||
10239 (parser->
current.end[4] ==
'\004') ||
10240 (parser->
current.end[4] ==
'\032')
10243 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10245 if (newline == NULL) {
10248 pm_newline_list_append(&parser->
newline_list, newline);
10249 parser->
current.end = newline + 1;
10253 parser_lex_callback(parser);
10263 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10265 if (newline == NULL) {
10268 pm_newline_list_append(&parser->
newline_list, newline);
10269 parser->
current.end = newline + 1;
10273 parser_lex_callback(parser);
10276 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10292 parser_lex_callback(parser);
10316 const uint8_t *cursor = parser->
current.end;
10318 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10319 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10382 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10393static inline size_t
10399 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10404 return (width == 0 ? 1 : width);
10412 size_t width = parser_char_width(parser);
10413 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10414 parser->
current.end += width;
10419 size_t width = parser_char_width(parser);
10420 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10422 parser->
current.end += width;
10426pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10427 for (
size_t index = 0; index < length; index++) {
10428 if (value[index] & 0x80)
return false;
10442 pm_string_owned_init(&parser->
current_string, (uint8_t *) pm_buffer_value(&token_buffer->
buffer), pm_buffer_length(&token_buffer->
buffer));
10463 if (token_buffer->
cursor == NULL) {
10466 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10467 pm_token_buffer_copy(parser, token_buffer);
10479 pm_regexp_token_buffer_copy(parser, token_buffer);
10483#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10495 const uint8_t *start;
10496 if (token_buffer->
cursor == NULL) {
10497 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10498 start = parser->
current.start;
10500 start = token_buffer->
cursor;
10503 const uint8_t *end = parser->
current.end - 1;
10504 assert(end >= start);
10505 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10507 token_buffer->
cursor = end;
10512 const uint8_t *start;
10514 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10515 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10516 start = parser->
current.start;
10521 const uint8_t *end = parser->
current.end - 1;
10522 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10523 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10528#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10534static inline size_t
10536 size_t whitespace = 0;
10539 case PM_HEREDOC_INDENT_NONE:
10544 case PM_HEREDOC_INDENT_DASH:
10546 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10548 case PM_HEREDOC_INDENT_TILDE:
10551 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10552 if (**cursor ==
'\t') {
10553 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10572 size_t eol_length = match_eol(parser);
10579 parser_flush_heredoc_end(parser);
10585 uint8_t delimiter = *parser->
current.end;
10589 if (eol_length == 2) {
10590 delimiter = *(parser->
current.end + 1);
10593 parser->
current.end += eol_length;
10597 return *parser->
current.end++;
10604#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10623 bool lexed_comment =
false;
10631 case PM_LEX_DEFAULT:
10632 case PM_LEX_EMBEXPR:
10633 case PM_LEX_EMBVAR:
10649 bool space_seen =
false;
10653 bool chomping =
true;
10654 while (parser->
current.end < parser->
end && chomping) {
10655 switch (*parser->
current.end) {
10664 if (match_eol_offset(parser, 1)) {
10667 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10673 size_t eol_length = match_eol_offset(parser, 1);
10679 parser->
current.end += eol_length + 1;
10683 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10716 switch (*parser->
current.end++) {
10724 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10725 parser->
current.end = ending == NULL ? parser->
end : ending;
10730 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10733 if (ending) parser->
current.end++;
10735 parser_lex_callback(parser);
10747 parser_lex_magic_comment_encoding(parser);
10751 lexed_comment =
true;
10757 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10769 if (!lexed_comment) {
10770 parser->
current.end += eol_length - 1;
10779 parser_flush_heredoc_end(parser);
10784 switch (lex_state_ignored_p(parser)) {
10785 case PM_IGNORED_NEWLINE_NONE:
10787 case PM_IGNORED_NEWLINE_PATTERN:
10789 if (!lexed_comment) parser_lex_ignored_newline(parser);
10790 lex_state_set(parser, PM_LEX_STATE_BEG);
10796 case PM_IGNORED_NEWLINE_ALL:
10797 if (!lexed_comment) parser_lex_ignored_newline(parser);
10798 lexed_comment =
false;
10799 goto lex_next_token;
10807 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10809 if (next_content < parser->end) {
10815 if (next_content[0] ==
'#') {
10817 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10819 while (following && (following + 1 < parser->
end)) {
10821 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10825 if (peek_at(parser, following) !=
'#')
break;
10829 following = next_newline(following, parser->
end - following);
10835 lex_state_ignored_p(parser) ||
10837 (peek_at(parser, following) ==
'.') ||
10838 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10841 if (!lexed_comment) parser_lex_ignored_newline(parser);
10842 lexed_comment =
false;
10843 goto lex_next_token;
10849 if (next_content[0] ==
'.') {
10853 if (peek_at(parser, next_content + 1) ==
'.') {
10854 if (!lexed_comment) parser_lex_ignored_newline(parser);
10855 lex_state_set(parser, PM_LEX_STATE_BEG);
10861 if (!lexed_comment) parser_lex_ignored_newline(parser);
10862 lex_state_set(parser, PM_LEX_STATE_DOT);
10863 parser->
current.start = next_content;
10864 parser->
current.end = next_content + 1;
10871 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10872 if (!lexed_comment) parser_lex_ignored_newline(parser);
10873 lex_state_set(parser, PM_LEX_STATE_DOT);
10874 parser->
current.start = next_content;
10875 parser->
current.end = next_content + 2;
10883 lex_state_set(parser, PM_LEX_STATE_BEG);
10886 if (!lexed_comment) parser_lex_callback(parser);
10896 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10903 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10908 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10909 pm_do_loop_stack_push(parser,
false);
10916 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10917 pm_do_loop_stack_pop(parser);
10922 lex_state_set(parser, PM_LEX_STATE_BEG);
10931 if (lex_state_operator_p(parser)) {
10932 if (match(parser,
']')) {
10934 lex_state_set(parser, PM_LEX_STATE_ARG);
10938 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10942 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10946 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10947 pm_do_loop_stack_push(parser,
false);
10953 lex_state_set(parser, PM_LEX_STATE_END);
10954 pm_do_loop_stack_pop(parser);
10964 lex_state_set(parser, PM_LEX_STATE_BEG);
10966 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10968 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10969 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10972 lex_state_set(parser, PM_LEX_STATE_BEG);
10973 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10976 lex_state_set(parser, PM_LEX_STATE_BEG);
10979 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10984 pm_do_loop_stack_push(parser,
false);
10992 pm_do_loop_stack_pop(parser);
10995 lex_mode_pop(parser);
11000 lex_state_set(parser, PM_LEX_STATE_END);
11005 if (match(parser,
'*')) {
11006 if (match(parser,
'=')) {
11007 lex_state_set(parser, PM_LEX_STATE_BEG);
11013 if (lex_state_spcarg_p(parser, space_seen)) {
11014 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11016 }
else if (lex_state_beg_p(parser)) {
11018 }
else if (ambiguous_operator_p(parser, space_seen)) {
11019 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11022 if (lex_state_operator_p(parser)) {
11023 lex_state_set(parser, PM_LEX_STATE_ARG);
11025 lex_state_set(parser, PM_LEX_STATE_BEG);
11031 if (match(parser,
'=')) {
11032 lex_state_set(parser, PM_LEX_STATE_BEG);
11038 if (lex_state_spcarg_p(parser, space_seen)) {
11039 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11041 }
else if (lex_state_beg_p(parser)) {
11043 }
else if (ambiguous_operator_p(parser, space_seen)) {
11044 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11047 if (lex_state_operator_p(parser)) {
11048 lex_state_set(parser, PM_LEX_STATE_ARG);
11050 lex_state_set(parser, PM_LEX_STATE_BEG);
11058 if (lex_state_operator_p(parser)) {
11059 lex_state_set(parser, PM_LEX_STATE_ARG);
11060 if (match(parser,
'@')) {
11064 lex_state_set(parser, PM_LEX_STATE_BEG);
11067 if (match(parser,
'=')) {
11071 if (match(parser,
'~')) {
11080 current_token_starts_line(parser) &&
11082 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11083 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11090 goto lex_next_token;
11093 if (lex_state_operator_p(parser)) {
11094 lex_state_set(parser, PM_LEX_STATE_ARG);
11096 lex_state_set(parser, PM_LEX_STATE_BEG);
11099 if (match(parser,
'>')) {
11103 if (match(parser,
'~')) {
11107 if (match(parser,
'=')) {
11115 if (match(parser,
'<')) {
11117 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11118 !lex_state_end_p(parser) &&
11119 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11121 const uint8_t *end = parser->
current.end;
11126 if (match(parser,
'-')) {
11127 indent = PM_HEREDOC_INDENT_DASH;
11129 else if (match(parser,
'~')) {
11130 indent = PM_HEREDOC_INDENT_TILDE;
11133 if (match(parser,
'`')) {
11134 quote = PM_HEREDOC_QUOTE_BACKTICK;
11136 else if (match(parser,
'"')) {
11137 quote = PM_HEREDOC_QUOTE_DOUBLE;
11139 else if (match(parser,
'\'')) {
11140 quote = PM_HEREDOC_QUOTE_SINGLE;
11143 const uint8_t *ident_start = parser->
current.end;
11148 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end)) == 0) {
11151 if (quote == PM_HEREDOC_QUOTE_NONE) {
11152 parser->
current.end += width;
11154 while ((parser->
current.end < parser->
end) && (width = char_is_identifier(parser, parser->
current.end))) {
11155 parser->
current.end += width;
11161 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11166 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11167 bool ident_error =
false;
11169 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11170 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11171 ident_error =
true;
11176 .mode = PM_LEX_HEREDOC,
11179 .ident_start = ident_start,
11180 .ident_length = ident_length,
11184 .next_start = parser->
current.end,
11186 .line_continuation =
false
11191 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11193 if (body_start == NULL) {
11198 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11199 body_start = parser->
end;
11203 pm_newline_list_append(&parser->
newline_list, body_start);
11216 if (match(parser,
'=')) {
11217 lex_state_set(parser, PM_LEX_STATE_BEG);
11221 if (ambiguous_operator_p(parser, space_seen)) {
11222 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11225 if (lex_state_operator_p(parser)) {
11226 lex_state_set(parser, PM_LEX_STATE_ARG);
11228 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11229 lex_state_set(parser, PM_LEX_STATE_BEG);
11235 if (lex_state_operator_p(parser)) {
11236 lex_state_set(parser, PM_LEX_STATE_ARG);
11238 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11239 lex_state_set(parser, PM_LEX_STATE_BEG);
11242 if (match(parser,
'=')) {
11243 if (match(parser,
'>')) {
11254 if (match(parser,
'>')) {
11255 if (lex_state_operator_p(parser)) {
11256 lex_state_set(parser, PM_LEX_STATE_ARG);
11258 lex_state_set(parser, PM_LEX_STATE_BEG);
11263 if (lex_state_operator_p(parser)) {
11264 lex_state_set(parser, PM_LEX_STATE_ARG);
11266 lex_state_set(parser, PM_LEX_STATE_BEG);
11273 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11274 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11280 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11281 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11285 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11286 if (previous_command_start) {
11287 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11289 lex_state_set(parser, PM_LEX_STATE_ARG);
11295 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11301 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11302 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11308 LEX(lex_question_mark(parser));
11312 if (match(parser,
'&')) {
11313 lex_state_set(parser, PM_LEX_STATE_BEG);
11315 if (match(parser,
'=')) {
11322 if (match(parser,
'=')) {
11323 lex_state_set(parser, PM_LEX_STATE_BEG);
11327 if (match(parser,
'.')) {
11328 lex_state_set(parser, PM_LEX_STATE_DOT);
11333 if (lex_state_spcarg_p(parser, space_seen)) {
11334 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11335 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11337 const uint8_t delim = peek_offset(parser, 1);
11339 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1)) {
11340 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11345 }
else if (lex_state_beg_p(parser)) {
11347 }
else if (ambiguous_operator_p(parser, space_seen)) {
11348 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11351 if (lex_state_operator_p(parser)) {
11352 lex_state_set(parser, PM_LEX_STATE_ARG);
11354 lex_state_set(parser, PM_LEX_STATE_BEG);
11362 if (match(parser,
'|')) {
11363 if (match(parser,
'=')) {
11364 lex_state_set(parser, PM_LEX_STATE_BEG);
11368 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11373 lex_state_set(parser, PM_LEX_STATE_BEG);
11377 if (match(parser,
'=')) {
11378 lex_state_set(parser, PM_LEX_STATE_BEG);
11382 if (lex_state_operator_p(parser)) {
11383 lex_state_set(parser, PM_LEX_STATE_ARG);
11385 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11392 if (lex_state_operator_p(parser)) {
11393 lex_state_set(parser, PM_LEX_STATE_ARG);
11395 if (match(parser,
'@')) {
11402 if (match(parser,
'=')) {
11403 lex_state_set(parser, PM_LEX_STATE_BEG);
11408 lex_state_beg_p(parser) ||
11409 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) :
false)
11411 lex_state_set(parser, PM_LEX_STATE_BEG);
11413 if (pm_char_is_decimal_digit(peek(parser))) {
11416 lex_state_set(parser, PM_LEX_STATE_END);
11423 if (ambiguous_operator_p(parser, space_seen)) {
11424 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11427 lex_state_set(parser, PM_LEX_STATE_BEG);
11433 if (lex_state_operator_p(parser)) {
11434 lex_state_set(parser, PM_LEX_STATE_ARG);
11436 if (match(parser,
'@')) {
11443 if (match(parser,
'=')) {
11444 lex_state_set(parser, PM_LEX_STATE_BEG);
11448 if (match(parser,
'>')) {
11449 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11453 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11454 bool is_beg = lex_state_beg_p(parser);
11455 if (!is_beg && spcarg) {
11456 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11459 if (is_beg || spcarg) {
11460 lex_state_set(parser, PM_LEX_STATE_BEG);
11464 if (ambiguous_operator_p(parser, space_seen)) {
11465 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11468 lex_state_set(parser, PM_LEX_STATE_BEG);
11474 bool beg_p = lex_state_beg_p(parser);
11476 if (match(parser,
'.')) {
11477 if (match(parser,
'.')) {
11480 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11481 lex_state_set(parser, PM_LEX_STATE_BEG);
11483 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11489 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11492 lex_state_set(parser, PM_LEX_STATE_BEG);
11496 lex_state_set(parser, PM_LEX_STATE_BEG);
11500 lex_state_set(parser, PM_LEX_STATE_DOT);
11516 lex_state_set(parser, PM_LEX_STATE_END);
11522 if (match(parser,
':')) {
11523 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)) {
11524 lex_state_set(parser, PM_LEX_STATE_BEG);
11528 lex_state_set(parser, PM_LEX_STATE_DOT);
11532 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11533 lex_state_set(parser, PM_LEX_STATE_BEG);
11537 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11538 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11542 lex_state_set(parser, PM_LEX_STATE_FNAME);
11547 if (lex_state_beg_p(parser)) {
11548 lex_mode_push_regexp(parser,
'\0',
'/');
11552 if (match(parser,
'=')) {
11553 lex_state_set(parser, PM_LEX_STATE_BEG);
11557 if (lex_state_spcarg_p(parser, space_seen)) {
11558 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11559 lex_mode_push_regexp(parser,
'\0',
'/');
11563 if (ambiguous_operator_p(parser, space_seen)) {
11564 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11567 if (lex_state_operator_p(parser)) {
11568 lex_state_set(parser, PM_LEX_STATE_ARG);
11570 lex_state_set(parser, PM_LEX_STATE_BEG);
11577 if (lex_state_operator_p(parser)) {
11578 lex_state_set(parser, PM_LEX_STATE_ARG);
11580 lex_state_set(parser, PM_LEX_STATE_BEG);
11586 if (lex_state_operator_p(parser)) {
11587 (void) match(parser,
'@');
11588 lex_state_set(parser, PM_LEX_STATE_ARG);
11590 lex_state_set(parser, PM_LEX_STATE_BEG);
11601 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11602 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11606 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11607 lex_state_set(parser, PM_LEX_STATE_BEG);
11610 lex_state_beg_p(parser) ||
11611 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11612 lex_state_spcarg_p(parser, space_seen)
11615 if (*parser->
current.end >= 0x80) {
11616 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11619 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11620 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11626 uint8_t delimiter = peek_offset(parser, 1);
11628 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11629 goto lex_next_token;
11632 switch (peek(parser)) {
11637 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11639 lex_mode_push_list_eof(parser);
11648 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11650 lex_mode_push_list_eof(parser);
11659 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11660 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11662 lex_mode_push_regexp(parser,
'\0',
'\0');
11671 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11672 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11674 lex_mode_push_string_eof(parser);
11683 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11684 lex_mode_push_string(parser,
true,
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,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11697 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11699 lex_mode_push_string_eof(parser);
11708 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11710 lex_mode_push_list_eof(parser);
11719 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11721 lex_mode_push_list_eof(parser);
11730 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11731 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11733 lex_mode_push_string_eof(parser);
11743 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11744 goto lex_next_token;
11748 if (ambiguous_operator_p(parser, space_seen)) {
11749 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11752 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11763 lex_mode_pop(parser);
11766 lex_state_set(parser, PM_LEX_STATE_END);
11772 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11773 LEX(lex_at_variable(parser));
11776 if (*parser->
current.start !=
'_') {
11777 size_t width = char_is_identifier_start(parser, parser->
current.start);
11784 if (*parser->
current.start >= 0x80) {
11785 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11786 }
else if (*parser->
current.start ==
'\\') {
11787 switch (peek_at(parser, parser->
current.start + 1)) {
11790 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11794 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11798 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11802 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11805 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11807 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11812 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11815 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11816 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11818 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11821 goto lex_next_token;
11835 current_token_starts_line(parser) &&
11836 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11837 (parser->
current.end == parser->
end || match_eol(parser))
11842 const uint8_t *cursor = parser->
current.end;
11843 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11844 pm_newline_list_append(&parser->
newline_list, cursor++);
11849 parser_lex_callback(parser);
11860 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11861 if (previous_command_start) {
11862 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11864 lex_state_set(parser, PM_LEX_STATE_ARG);
11866 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11867 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11869 lex_state_set(parser, PM_LEX_STATE_END);
11874 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11876 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11877 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11879 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11886 case PM_LEX_LIST: {
11900 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11901 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11908 if (whitespace > 0) {
11909 parser->
current.end += whitespace;
11910 if (peek_offset(parser, -1) ==
'\n') {
11912 parser_flush_heredoc_end(parser);
11926 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11927 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11933 while (breakpoint != NULL) {
11936 if (pm_char_is_whitespace(*breakpoint)) {
11937 parser->
current.end = breakpoint;
11938 pm_token_buffer_flush(parser, &token_buffer);
11948 parser->
current.end = breakpoint + 1;
11949 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11956 if (breakpoint > parser->
current.start) {
11957 parser->
current.end = breakpoint;
11958 pm_token_buffer_flush(parser, &token_buffer);
11964 parser->
current.end = breakpoint + 1;
11965 lex_mode_pop(parser);
11966 lex_state_set(parser, PM_LEX_STATE_END);
11971 if (*breakpoint ==
'\0') {
11972 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11979 if (*breakpoint ==
'\\') {
11980 parser->
current.end = breakpoint + 1;
11989 pm_token_buffer_escape(parser, &token_buffer);
11990 uint8_t peeked = peek(parser);
11998 pm_token_buffer_push_byte(&token_buffer, peeked);
12003 if (peek(parser) !=
'\n') {
12004 pm_token_buffer_push_byte(&token_buffer,
'\r');
12009 pm_token_buffer_push_byte(&token_buffer,
'\n');
12015 parser_flush_heredoc_end(parser);
12016 pm_token_buffer_copy(parser, &token_buffer);
12027 pm_token_buffer_push_byte(&token_buffer, peeked);
12030 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12032 pm_token_buffer_push_byte(&token_buffer,
'\\');
12033 pm_token_buffer_push_escaped(&token_buffer, parser);
12040 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12045 if (*breakpoint ==
'#') {
12053 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12058 pm_token_buffer_flush(parser, &token_buffer);
12067 parser->
current.end = breakpoint + 1;
12068 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12074 pm_token_buffer_flush(parser, &token_buffer);
12081 pm_token_buffer_flush(parser, &token_buffer);
12084 case PM_LEX_REGEXP: {
12106 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12107 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12110 while (breakpoint != NULL) {
12112 bool is_terminator = (*breakpoint == term);
12117 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12118 if (term ==
'\n') {
12119 is_terminator =
true;
12125 if (term ==
'\r') {
12126 is_terminator =
false;
12132 if (is_terminator) {
12134 parser->
current.end = breakpoint + 1;
12135 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12143 if (breakpoint > parser->
current.start) {
12144 parser->
current.end = breakpoint;
12145 pm_regexp_token_buffer_flush(parser, &token_buffer);
12150 size_t eol_length = match_eol_at(parser, breakpoint);
12152 parser->
current.end = breakpoint + eol_length;
12155 parser->
current.end = breakpoint + 1;
12162 lex_mode_pop(parser);
12163 lex_state_set(parser, PM_LEX_STATE_END);
12169 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12170 parser->
current.end = breakpoint + 1;
12171 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12176 switch (*breakpoint) {
12179 parser->
current.end = breakpoint + 1;
12180 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12183 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12184 parser->
current.end = breakpoint + 1;
12185 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12190 parser->
current.end = breakpoint;
12191 pm_regexp_token_buffer_escape(parser, &token_buffer);
12199 pm_newline_list_append(&parser->
newline_list, breakpoint);
12200 parser->
current.end = breakpoint + 1;
12201 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12205 parser->
current.end = breakpoint + 1;
12206 parser_flush_heredoc_end(parser);
12207 pm_regexp_token_buffer_flush(parser, &token_buffer);
12213 parser->
current.end = breakpoint + 1;
12222 pm_regexp_token_buffer_escape(parser, &token_buffer);
12223 uint8_t peeked = peek(parser);
12228 if (peek(parser) !=
'\n') {
12230 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12232 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12233 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12242 parser_flush_heredoc_end(parser);
12243 pm_regexp_token_buffer_copy(parser, &token_buffer);
12265 case '$':
case ')':
case '*':
case '+':
12266 case '.':
case '>':
case '?':
case ']':
12267 case '^':
case '|':
case '}':
12268 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12274 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12275 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12280 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12281 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12286 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12299 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12304 pm_regexp_token_buffer_flush(parser, &token_buffer);
12310 assert(
false &&
"unreachable");
12316 pm_regexp_token_buffer_flush(parser, &token_buffer);
12323 pm_regexp_token_buffer_flush(parser, &token_buffer);
12326 case PM_LEX_STRING: {
12345 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12346 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12352 while (breakpoint != NULL) {
12357 parser->
current.end = breakpoint + 1;
12358 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12363 bool is_terminator = (*breakpoint == term);
12368 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12369 if (term ==
'\n') {
12370 is_terminator =
true;
12376 if (term ==
'\r') {
12377 is_terminator =
false;
12384 if (is_terminator) {
12388 parser->
current.end = breakpoint + 1;
12389 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12396 if (breakpoint > parser->
current.start) {
12397 parser->
current.end = breakpoint;
12398 pm_token_buffer_flush(parser, &token_buffer);
12404 size_t eol_length = match_eol_at(parser, breakpoint);
12406 parser->
current.end = breakpoint + eol_length;
12409 parser->
current.end = breakpoint + 1;
12412 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12414 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12415 lex_mode_pop(parser);
12419 lex_state_set(parser, PM_LEX_STATE_END);
12420 lex_mode_pop(parser);
12424 switch (*breakpoint) {
12427 parser->
current.end = breakpoint + 1;
12428 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12431 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12432 parser->
current.end = breakpoint + 1;
12433 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12440 parser->
current.end = breakpoint;
12441 pm_token_buffer_escape(parser, &token_buffer);
12442 token_buffer.
cursor = breakpoint;
12451 pm_newline_list_append(&parser->
newline_list, breakpoint);
12452 parser->
current.end = breakpoint + 1;
12453 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12457 parser->
current.end = breakpoint + 1;
12458 parser_flush_heredoc_end(parser);
12459 pm_token_buffer_flush(parser, &token_buffer);
12463 parser->
current.end = breakpoint + 1;
12472 pm_token_buffer_escape(parser, &token_buffer);
12473 uint8_t peeked = peek(parser);
12477 pm_token_buffer_push_byte(&token_buffer,
'\\');
12482 if (peek(parser) !=
'\n') {
12484 pm_token_buffer_push_byte(&token_buffer,
'\\');
12486 pm_token_buffer_push_byte(&token_buffer,
'\r');
12492 pm_token_buffer_push_byte(&token_buffer,
'\\');
12493 pm_token_buffer_push_byte(&token_buffer,
'\n');
12500 parser_flush_heredoc_end(parser);
12501 pm_token_buffer_copy(parser, &token_buffer);
12512 pm_token_buffer_push_byte(&token_buffer, peeked);
12515 pm_token_buffer_push_byte(&token_buffer, peeked);
12518 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12520 pm_token_buffer_push_byte(&token_buffer,
'\\');
12521 pm_token_buffer_push_escaped(&token_buffer, parser);
12528 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12539 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12544 pm_token_buffer_flush(parser, &token_buffer);
12550 assert(
false &&
"unreachable");
12555 pm_token_buffer_flush(parser, &token_buffer);
12562 pm_token_buffer_flush(parser, &token_buffer);
12565 case PM_LEX_HEREDOC: {
12592 lex_state_set(parser, PM_LEX_STATE_END);
12593 lex_mode_pop(parser);
12597 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12602 if (current_token_starts_line(parser)) {
12603 const uint8_t *start = parser->
current.start;
12605 if (!line_continuation && (start + ident_length <= parser->end)) {
12606 const uint8_t *newline = next_newline(start, parser->
end - start);
12607 const uint8_t *ident_end = newline;
12608 const uint8_t *terminator_end = newline;
12610 if (newline == NULL) {
12611 terminator_end = parser->
end;
12612 ident_end = parser->
end;
12615 if (newline[-1] ==
'\r') {
12620 const uint8_t *terminator_start = ident_end - ident_length;
12621 const uint8_t *cursor = start;
12623 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12624 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12630 (cursor == terminator_start) &&
12631 (memcmp(terminator_start, ident_start, ident_length) == 0)
12633 if (newline != NULL) {
12634 pm_newline_list_append(&parser->
newline_list, newline);
12637 parser->
current.end = terminator_end;
12645 lex_state_set(parser, PM_LEX_STATE_END);
12646 lex_mode_pop(parser);
12651 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12653 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12656 peek_at(parser, start) !=
'\n'
12665 uint8_t breakpoints[] =
"\r\n\\#";
12668 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12669 breakpoints[3] =
'\0';
12672 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12674 bool was_line_continuation =
false;
12676 while (breakpoint != NULL) {
12677 switch (*breakpoint) {
12680 parser->
current.end = breakpoint + 1;
12681 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12684 parser->
current.end = breakpoint + 1;
12686 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12687 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12694 pm_token_buffer_escape(parser, &token_buffer);
12695 token_buffer.
cursor = breakpoint;
12700 parser_flush_heredoc_end(parser);
12701 parser->
current.end = breakpoint + 1;
12702 pm_token_buffer_flush(parser, &token_buffer);
12706 pm_newline_list_append(&parser->
newline_list, breakpoint);
12710 const uint8_t *start = breakpoint + 1;
12712 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12715 const uint8_t *newline = next_newline(start, parser->
end - start);
12717 if (newline == NULL) {
12718 newline = parser->
end;
12719 }
else if (newline[-1] ==
'\r') {
12724 const uint8_t *terminator_start = newline - ident_length;
12728 const uint8_t *cursor = start;
12730 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12731 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12737 cursor == terminator_start &&
12738 (memcmp(terminator_start, ident_start, ident_length) == 0)
12740 parser->
current.end = breakpoint + 1;
12741 pm_token_buffer_flush(parser, &token_buffer);
12746 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12753 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12758 parser->
current.end = breakpoint + 1;
12759 pm_token_buffer_flush(parser, &token_buffer);
12765 parser->
current.end = breakpoint + 1;
12766 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12776 parser->
current.end = breakpoint + 1;
12785 pm_token_buffer_escape(parser, &token_buffer);
12786 uint8_t peeked = peek(parser);
12788 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12792 if (peek(parser) !=
'\n') {
12793 pm_token_buffer_push_byte(&token_buffer,
'\\');
12794 pm_token_buffer_push_byte(&token_buffer,
'\r');
12799 pm_token_buffer_push_byte(&token_buffer,
'\\');
12800 pm_token_buffer_push_byte(&token_buffer,
'\n');
12802 breakpoint = parser->
current.end;
12805 pm_token_buffer_push_byte(&token_buffer,
'\\');
12806 pm_token_buffer_push_escaped(&token_buffer, parser);
12813 if (peek(parser) !=
'\n') {
12814 pm_token_buffer_push_byte(&token_buffer,
'\r');
12822 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12823 const uint8_t *end = parser->
current.end;
12828 parser->
current.end = breakpoint;
12829 pm_token_buffer_flush(parser, &token_buffer);
12833 parser->
current.end = end + 1;
12838 was_line_continuation =
true;
12840 breakpoint = parser->
current.end;
12843 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12849 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12861 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12866 pm_token_buffer_flush(parser, &token_buffer);
12872 assert(
false &&
"unreachable");
12875 was_line_continuation =
false;
12880 pm_token_buffer_flush(parser, &token_buffer);
12887 pm_token_buffer_flush(parser, &token_buffer);
12892 assert(
false &&
"unreachable");
12910 PM_BINDING_POWER_UNSET = 0,
12911 PM_BINDING_POWER_STATEMENT = 2,
12912 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12913 PM_BINDING_POWER_MODIFIER = 6,
12914 PM_BINDING_POWER_COMPOSITION = 8,
12915 PM_BINDING_POWER_NOT = 10,
12916 PM_BINDING_POWER_MATCH = 12,
12917 PM_BINDING_POWER_DEFINED = 14,
12918 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12919 PM_BINDING_POWER_ASSIGNMENT = 18,
12920 PM_BINDING_POWER_TERNARY = 20,
12921 PM_BINDING_POWER_RANGE = 22,
12922 PM_BINDING_POWER_LOGICAL_OR = 24,
12923 PM_BINDING_POWER_LOGICAL_AND = 26,
12924 PM_BINDING_POWER_EQUALITY = 28,
12925 PM_BINDING_POWER_COMPARISON = 30,
12926 PM_BINDING_POWER_BITWISE_OR = 32,
12927 PM_BINDING_POWER_BITWISE_AND = 34,
12928 PM_BINDING_POWER_SHIFT = 36,
12929 PM_BINDING_POWER_TERM = 38,
12930 PM_BINDING_POWER_FACTOR = 40,
12931 PM_BINDING_POWER_UMINUS = 42,
12932 PM_BINDING_POWER_EXPONENT = 44,
12933 PM_BINDING_POWER_UNARY = 46,
12934 PM_BINDING_POWER_INDEX = 48,
12935 PM_BINDING_POWER_CALL = 50,
12936 PM_BINDING_POWER_MAX = 52
12937} pm_binding_power_t;
12960#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12961#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12962#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12963#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12964#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
13026 [
PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13030 [
PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13031 [
PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13047 [
PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13048 [
PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13051 [
PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13059 [
PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13060 [
PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13061 [
PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13068 [
PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13072#undef BINDING_POWER_ASSIGNMENT
13073#undef LEFT_ASSOCIATIVE
13074#undef RIGHT_ASSOCIATIVE
13075#undef RIGHT_ASSOCIATIVE_UNARY
13090 return match1(parser, type1) || match1(parser, type2);
13098 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13106 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13114 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13122 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);
13130 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);
13141 if (match1(parser,
type)) {
13142 parser_lex(parser);
13154 if (match2(parser, type1, type2)) {
13155 parser_lex(parser);
13174 if (accept1(parser,
type))
return;
13177 pm_parser_err(parser, location, location, diag_id);
13189 if (accept2(parser, type1, type2))
return;
13192 pm_parser_err(parser, location, location, diag_id);
13203expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13205 parser_lex(parser);
13207 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13214parse_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);
13221parse_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) {
13222 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13223 pm_assert_value_expression(parser, node);
13277 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13297 return pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET;
13306parse_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) {
13309 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13310 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13313 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13327 size_t length = constant->
length;
13328 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13329 if (name == NULL)
return;
13331 memcpy(name, constant->
start, length);
13332 name[length] =
'=';
13337 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13349 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13350 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13351 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13352 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13353 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13354 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13355 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13362 pm_node_destroy(parser, target);
13375 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13376 if (implicit_parameters->
nodes[index] == node) {
13380 if (index != implicit_parameters->
size - 1) {
13381 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13384 implicit_parameters->
size--;
13412 return parse_unwriteable_target(parser, target);
13419 if (context_def_p(parser)) {
13420 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13428 if (context_def_p(parser)) {
13429 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13438 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13447 parse_target_implicit_parameter(parser, target);
13451 uint32_t name = cast->
name;
13452 uint32_t depth = cast->
depth;
13453 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13464 parse_target_implicit_parameter(parser, target);
13465 pm_node_destroy(parser, target);
13474 if (splat_parent) {
13477 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13502 (call->
block == NULL)
13517 pm_node_destroy(parser, target);
13519 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13524 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13527 parse_write_name(parser, &call->
name);
13528 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13536 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13544 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13555 pm_node_t *result = parse_target(parser, target, multiple,
false);
13564 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13578 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13579 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13592 pm_node_destroy(parser, value);
13596 pm_node_destroy(parser, target);
13602 if (context_def_p(parser)) {
13603 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13606 return parse_shareable_constant_write(parser, node);
13611 if (context_def_p(parser)) {
13612 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13615 pm_node_destroy(parser, target);
13616 return parse_shareable_constant_write(parser, node);
13620 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13624 pm_node_destroy(parser, target);
13633 uint32_t depth = local_read->
depth;
13634 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13637 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13639 parse_target_implicit_parameter(parser, target);
13642 pm_locals_unread(&scope->
locals, name);
13643 pm_node_destroy(parser, target);
13645 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13651 parse_target_implicit_parameter(parser, target);
13652 pm_node_destroy(parser, target);
13658 pm_node_destroy(parser, target);
13671 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13673 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13687 (call->
block == NULL)
13701 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13702 pm_node_destroy(parser, target);
13705 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13707 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13725 pm_arguments_node_arguments_append(arguments, value);
13728 parse_write_name(parser, &call->
name);
13740 call->
arguments = pm_arguments_node_create(parser);
13743 pm_arguments_node_arguments_append(call->
arguments, value);
13747 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13761 pm_node_destroy(parser, value);
13768 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13782 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13783 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13784 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13785 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13786 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13787 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13788 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13795 pm_node_destroy(parser, target);
13810parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13814 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13822 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13828 if (token_begins_expression_p(parser->
current.type)) {
13829 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13830 name = parse_target(parser, name,
true,
true);
13833 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13834 pm_multi_target_node_targets_append(parser, result, splat);
13838 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13839 target = parse_target(parser, target,
true,
false);
13841 pm_multi_target_node_targets_append(parser, result, target);
13842 context_pop(parser);
13843 }
else if (token_begins_expression_p(parser->
current.type)) {
13844 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13845 target = parse_target(parser, target,
true,
false);
13847 pm_multi_target_node_targets_append(parser, result, target);
13852 pm_multi_target_node_targets_append(parser, result, rest);
13865parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13866 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13871 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13887 if (context_terminator(context, &parser->
current))
return NULL;
13893 context_push(parser, context);
13896 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13897 pm_statements_node_body_append(parser, statements, node,
true);
13914 if (context_terminator(context, &parser->
current))
break;
13924 if (context_terminator(context, &parser->
current))
break;
13937 parser_lex(parser);
13940 if (context_terminator(context, &parser->
current))
break;
13951 context_pop(parser);
13952 bool last_value =
true;
13956 last_value =
false;
13961 pm_void_statements_check(parser, statements, last_value);
13974 if (duplicated != NULL) {
13978 pm_diagnostic_list_append_format(
13982 PM_WARN_DUPLICATED_HASH_KEY,
13983 (
int) pm_buffer_length(&buffer),
13984 pm_buffer_value(&buffer),
13988 pm_buffer_free(&buffer);
14000 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14001 pm_diagnostic_list_append_format(
14005 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14018 bool contains_keyword_splat =
false;
14023 switch (parser->
current.type) {
14025 parser_lex(parser);
14035 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14036 }
else if (token_begins_expression_p(parser->
current.type)) {
14037 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14039 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14042 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14043 contains_keyword_splat =
true;
14048 parser_lex(parser);
14051 pm_hash_key_static_literals_add(parser, literals, key);
14056 if (token_begins_expression_p(parser->
current.type)) {
14057 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14061 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14066 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14067 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14069 depth = pm_parser_local_depth(parser, &identifier);
14073 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14075 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14080 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14083 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14087 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14095 pm_hash_key_static_literals_add(parser, literals, key);
14098 if (pm_symbol_node_label_p(key)) {
14099 operator = not_provided(parser);
14105 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14106 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14126 if (token_begins_expression_p(parser->
current.type))
continue;
14132 return contains_keyword_splat;
14141 arguments->
arguments = pm_arguments_node_create(parser);
14144 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14152 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].left;
14158 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14164 bool parsed_first_argument =
false;
14165 bool parsed_bare_hash =
false;
14166 bool parsed_block_argument =
false;
14167 bool parsed_forwarding_arguments =
false;
14170 if (parsed_forwarding_arguments) {
14171 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14176 switch (parser->
current.type) {
14179 if (parsed_bare_hash) {
14180 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14187 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14189 parse_arguments_append(parser, arguments, argument);
14195 pm_static_literals_free(&hash_keys);
14196 parsed_bare_hash =
true;
14201 parser_lex(parser);
14205 if (token_begins_expression_p(parser->
current.type)) {
14206 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14208 pm_parser_scope_forwarding_block_check(parser, &
operator);
14211 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14212 if (parsed_block_argument) {
14213 parse_arguments_append(parser, arguments, argument);
14215 arguments->
block = argument;
14219 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14222 parsed_block_argument =
true;
14226 parser_lex(parser);
14230 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14231 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14232 if (parsed_bare_hash) {
14233 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14236 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14238 if (parsed_bare_hash) {
14239 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14242 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14245 parse_arguments_append(parser, arguments, argument);
14249 if (accepts_forwarding) {
14250 parser_lex(parser);
14252 if (token_begins_expression_p(parser->
current.type)) {
14257 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14264 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14267 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14269 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14270 if (parsed_first_argument && terminator ==
PM_TOKEN_EOF) {
14271 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14274 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14275 parse_arguments_append(parser, arguments, argument);
14278 parsed_forwarding_arguments =
true;
14285 if (argument == NULL) {
14286 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14289 bool contains_keywords =
false;
14290 bool contains_keyword_splat =
false;
14293 if (parsed_bare_hash) {
14294 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14301 operator = not_provided(parser);
14305 contains_keywords =
true;
14309 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14312 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14313 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14315 pm_keyword_hash_node_elements_append(bare_hash, argument);
14320 token_begins_expression_p(parser->
current.type) ||
14323 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14326 pm_static_literals_free(&hash_keys);
14327 parsed_bare_hash =
true;
14330 parse_arguments_append(parser, arguments, argument);
14341 parsed_first_argument =
true;
14349 bool accepted_newline =
false;
14361 if (accepted_newline) {
14362 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14372 if (match1(parser, terminator))
break;
14387parse_required_destructured_parameter(
pm_parser_t *parser) {
14391 pm_multi_target_node_opening_set(node, &parser->
previous);
14402 pm_multi_target_node_targets_append(parser, node, param);
14403 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14408 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14415 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14416 if (pm_parser_parameter_name_check(parser, &name)) {
14417 pm_node_flag_set_repeated_parameter(value);
14419 pm_parser_local_add_token(parser, &name, 1);
14422 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14427 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14428 if (pm_parser_parameter_name_check(parser, &name)) {
14429 pm_node_flag_set_repeated_parameter(param);
14431 pm_parser_local_add_token(parser, &name, 1);
14434 pm_multi_target_node_targets_append(parser, node, param);
14439 pm_multi_target_node_closing_set(node, &parser->
previous);
14449 PM_PARAMETERS_NO_CHANGE = 0,
14450 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14451 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14452 PM_PARAMETERS_ORDER_KEYWORDS,
14453 PM_PARAMETERS_ORDER_REST,
14454 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14455 PM_PARAMETERS_ORDER_OPTIONAL,
14456 PM_PARAMETERS_ORDER_NAMED,
14457 PM_PARAMETERS_ORDER_NONE,
14458} pm_parameters_order_t;
14464 [0] = PM_PARAMETERS_NO_CHANGE,
14487 pm_parameters_order_t state = parameters_ordering[token->type];
14488 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14492 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14493 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14495 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14499 if (token->type ==
PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14500 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14502 }
else if (token->type ==
PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14503 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14505 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14507 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14511 if (state < *current) *current = state;
14521 pm_binding_power_t binding_power,
14522 bool uses_parentheses,
14523 bool allows_trailing_comma,
14524 bool allows_forwarding_parameters,
14525 bool accepts_blocks_in_defaults,
14529 pm_do_loop_stack_push(parser,
false);
14532 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14535 bool parsing =
true;
14537 switch (parser->
current.type) {
14539 update_parameter_state(parser, &parser->
current, &order);
14542 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14543 pm_parameters_node_requireds_append(params, param);
14545 pm_parameters_node_posts_append(params, param);
14551 update_parameter_state(parser, &parser->
current, &order);
14552 parser_lex(parser);
14557 bool repeated =
false;
14560 repeated = pm_parser_parameter_name_check(parser, &name);
14561 pm_parser_local_add_token(parser, &name, 1);
14563 name = not_provided(parser);
14569 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14571 if (params->
block == NULL) {
14572 pm_parameters_node_block_set(params, param);
14574 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14575 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14581 if (!allows_forwarding_parameters) {
14582 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14585 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14586 parser_lex(parser);
14595 pm_parameters_node_posts_append(params, keyword_rest);
14596 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14600 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14609 parser_lex(parser);
14612 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14615 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14618 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14621 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14624 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14630 update_parameter_state(parser, &parser->
current, &order);
14632 update_parameter_state(parser, &parser->
previous, &order);
14636 bool repeated = pm_parser_parameter_name_check(parser, &name);
14637 pm_parser_local_add_token(parser, &name, 1);
14642 parser_lex(parser);
14647 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14648 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14649 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14654 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14656 pm_parameters_node_optionals_append(params, param);
14662 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14665 context_pop(parser);
14674 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14677 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14679 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14683 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14685 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14691 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14692 update_parameter_state(parser, &parser->
current, &order);
14695 parser_lex(parser);
14702 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14703 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14704 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14707 bool repeated = pm_parser_parameter_name_check(parser, &local);
14708 pm_parser_local_add_token(parser, &local, 1);
14710 switch (parser->
current.type) {
14714 context_pop(parser);
14716 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14718 pm_node_flag_set_repeated_parameter(param);
14721 pm_parameters_node_keywords_append(params, param);
14726 context_pop(parser);
14728 if (uses_parentheses) {
14733 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14735 pm_node_flag_set_repeated_parameter(param);
14738 pm_parameters_node_keywords_append(params, param);
14744 if (token_begins_expression_p(parser->
current.type)) {
14748 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14749 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14750 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14753 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14756 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14759 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14763 pm_node_flag_set_repeated_parameter(param);
14766 context_pop(parser);
14767 pm_parameters_node_keywords_append(params, param);
14784 update_parameter_state(parser, &parser->
current, &order);
14785 parser_lex(parser);
14789 bool repeated =
false;
14793 repeated = pm_parser_parameter_name_check(parser, &name);
14794 pm_parser_local_add_token(parser, &name, 1);
14796 name = not_provided(parser);
14800 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14802 pm_node_flag_set_repeated_parameter(param);
14805 if (params->
rest == NULL) {
14806 pm_parameters_node_rest_set(params, param);
14808 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14809 pm_parameters_node_posts_append(params, param);
14816 pm_parameters_order_t previous_order = order;
14817 update_parameter_state(parser, &parser->
current, &order);
14818 parser_lex(parser);
14824 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14825 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14828 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14832 bool repeated =
false;
14835 repeated = pm_parser_parameter_name_check(parser, &name);
14836 pm_parser_local_add_token(parser, &name, 1);
14838 name = not_provided(parser);
14842 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14844 pm_node_flag_set_repeated_parameter(param);
14849 pm_parameters_node_keyword_rest_set(params, param);
14851 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14852 pm_parameters_node_posts_append(params, param);
14859 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14864 if (params->
rest == NULL) {
14865 pm_parameters_node_rest_set(params, param);
14867 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14868 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14871 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14882 if (!parsing)
break;
14884 bool accepted_newline =
false;
14885 if (uses_parentheses) {
14892 if (accepted_newline) {
14893 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14901 pm_do_loop_stack_pop(parser);
14905 pm_node_destroy(parser, (
pm_node_t *) params);
14937token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14939 const uint8_t *end = token->start;
14943 newline_index == 0 &&
14944 parser->
start[0] == 0xef &&
14945 parser->
start[1] == 0xbb &&
14946 parser->
start[2] == 0xbf
14949 int64_t column = 0;
14950 for (; cursor < end; cursor++) {
14953 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14960 if (break_on_non_space)
return -1;
14973parser_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) {
14978 size_t closing_newline_index = token_newline_index(parser);
14979 if (opening_newline_index == closing_newline_index)
return;
14984 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14985 if (!if_after_else && (opening_column == -1))
return;
14992 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14993 if ((closing_column == -1) || (opening_column == closing_column))
return;
14997 if (allow_indent && (closing_column > opening_column))
return;
15000 PM_PARSER_WARN_FORMAT(
15002 closing_token->
start,
15003 closing_token->
end,
15004 PM_WARN_INDENTATION_MISMATCH,
15005 (
int) (closing_token->
end - closing_token->
start),
15006 (
const char *) closing_token->
start,
15007 (
int) (opening_token->
end - opening_token->
start),
15008 (
const char *) opening_token->
start,
15009 ((int32_t) opening_newline_index) + parser->
start_line
15014 PM_RESCUES_BEGIN = 1,
15021} pm_rescues_type_t;
15032 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15033 parser_lex(parser);
15037 switch (parser->
current.type) {
15042 parser_lex(parser);
15043 pm_rescue_node_operator_set(rescue, &parser->
previous);
15045 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15046 reference = parse_target(parser, reference,
false,
false);
15048 pm_rescue_node_reference_set(rescue, reference);
15063 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15064 pm_rescue_node_exceptions_append(rescue, expression);
15073 pm_rescue_node_operator_set(rescue, &parser->
previous);
15075 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15076 reference = parse_target(parser, reference,
false,
false);
15078 pm_rescue_node_reference_set(rescue, reference);
15093 pm_accepts_block_stack_push(parser,
true);
15108 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15110 pm_accepts_block_stack_pop(parser);
15114 if (current == NULL) {
15115 pm_begin_node_rescue_clause_set(parent_node, rescue);
15117 pm_rescue_node_subsequent_set(current, rescue);
15126 if (current != NULL) {
15130 while (clause != NULL) {
15138 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15139 opening_newline_index = token_newline_index(parser);
15141 else_keyword = parser->
current;
15142 opening = &else_keyword;
15144 parser_lex(parser);
15149 pm_accepts_block_stack_push(parser,
true);
15163 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15164 pm_accepts_block_stack_pop(parser);
15169 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15170 pm_begin_node_else_clause_set(parent_node, else_clause);
15174 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15178 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15181 parser_lex(parser);
15186 pm_accepts_block_stack_push(parser,
true);
15200 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15201 pm_accepts_block_stack_pop(parser);
15206 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15207 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15211 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15212 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15215 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15225 pm_token_t begin_keyword = not_provided(parser);
15226 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15228 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15238parse_block_parameters(
15240 bool allows_trailing_comma,
15242 bool is_lambda_literal,
15243 bool accepts_blocks_in_defaults,
15248 parameters = parse_parameters(
15250 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15252 allows_trailing_comma,
15254 accepts_blocks_in_defaults,
15256 (uint16_t) (depth + 1)
15266 switch (parser->
current.type) {
15268 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15269 parser_lex(parser);
15272 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15273 parser_lex(parser);
15276 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15277 parser_lex(parser);
15280 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15281 parser_lex(parser);
15288 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15289 pm_parser_local_add_token(parser, &parser->
previous, 1);
15292 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15294 pm_block_parameters_node_append_local(block_parameters, local);
15299 return block_parameters;
15307outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15309 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15320static const char *
const pm_numbered_parameter_names[] = {
15321 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15335 if (parameters != NULL) {
15337 if (implicit_parameters->
size > 0) {
15341 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15343 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15345 assert(
false &&
"unreachable");
15354 if (implicit_parameters->
size == 0) {
15361 uint8_t numbered_parameter = 0;
15362 bool it_parameter =
false;
15364 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15368 if (it_parameter) {
15369 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15370 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15371 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15373 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15375 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15377 assert(
false &&
"unreachable");
15380 if (numbered_parameter > 0) {
15381 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15383 it_parameter =
true;
15388 if (numbered_parameter > 0) {
15392 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15396 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15399 if (it_parameter) {
15400 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15410parse_block(
pm_parser_t *parser, uint16_t depth) {
15414 pm_accepts_block_stack_push(parser,
true);
15415 pm_parser_scope_push(parser,
false);
15422 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15424 parser_lex(parser);
15426 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15429 expect1(parser,
PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15432 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15447 pm_accepts_block_stack_push(parser,
true);
15449 pm_accepts_block_stack_pop(parser);
15454 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));
15462 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15465 pm_parser_scope_pop(parser);
15466 pm_accepts_block_stack_pop(parser);
15468 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15477parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15478 bool found =
false;
15487 pm_accepts_block_stack_push(parser,
true);
15496 pm_accepts_block_stack_pop(parser);
15501 pm_accepts_block_stack_push(parser,
false);
15506 parse_arguments(parser, arguments, accepts_block,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
15515 pm_accepts_block_stack_pop(parser);
15521 if (accepts_block) {
15526 block = parse_block(parser, (uint16_t) (depth + 1));
15527 pm_arguments_validate_block(parser, arguments, block);
15530 block = parse_block(parser, (uint16_t) (depth + 1));
15533 if (block != NULL) {
15537 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15539 if (arguments->
block != NULL) {
15541 arguments->
arguments = pm_arguments_node_create(parser);
15543 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15559 bool in_sclass =
false;
15561 switch (context_node->
context) {
15606 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15628 assert(
false &&
"unreachable");
15633 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15644 switch (context_node->
context) {
15718 assert(
false &&
"unreachable");
15732 return previous_block_exits;
15750 default: assert(
false &&
"unreachable");
type =
"";
break;
15753 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15770 }
else if (previous_block_exits != NULL) {
15782 flush_block_exits(parser, previous_block_exits);
15790 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15796 predicate_closed =
true;
15800 if (!predicate_closed) {
15801 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15804 context_pop(parser);
15809parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15811 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15814 pm_token_t then_keyword = not_provided(parser);
15816 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15820 pm_accepts_block_stack_push(parser,
true);
15821 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15822 pm_accepts_block_stack_pop(parser);
15826 pm_token_t end_keyword = not_provided(parser);
15831 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15834 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15837 assert(
false &&
"unreachable");
15847 if (parser_end_of_line_p(parser)) {
15848 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15851 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15853 parser_lex(parser);
15855 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15856 pm_accepts_block_stack_push(parser,
true);
15859 pm_accepts_block_stack_pop(parser);
15862 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15869 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15870 opening_newline_index = token_newline_index(parser);
15872 parser_lex(parser);
15875 pm_accepts_block_stack_push(parser,
true);
15877 pm_accepts_block_stack_pop(parser);
15880 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15883 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15893 assert(
false &&
"unreachable");
15897 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15905 bool recursing =
true;
15907 while (recursing) {
15912 recursing = current != NULL;
15930 assert(
false &&
"unreachable");
15934 pop_block_exits(parser, previous_block_exits);
15935 pm_node_list_free(¤t_block_exits);
15944#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15945 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15946 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15947 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15948 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15949 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15950 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15951 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15952 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15953 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15954 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15960#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15961 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15962 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15963 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15964 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15965 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15966 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15967 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15974#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15975 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15976 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15977 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15978 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15979 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15980 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15981 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15982 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15988#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15989 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15990 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15991 case PM_TOKEN_CLASS_VARIABLE
15997#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15998 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15999 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16000 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16011parse_unescaped_encoding(
const pm_parser_t *parser) {
16033parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16034 switch (parser->
current.type) {
16046 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16048 parser_lex(parser);
16066 lex_state_set(parser, PM_LEX_STATE_BEG);
16067 parser_lex(parser);
16073 pm_accepts_block_stack_push(parser,
true);
16075 pm_accepts_block_stack_pop(parser);
16079 lex_state_set(parser, state);
16087 if (statements != NULL && statements->
body.
size == 1) {
16091 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16105 lex_state_set(parser, PM_LEX_STATE_BEG);
16106 parser_lex(parser);
16111 switch (parser->
current.type) {
16115 parser_lex(parser);
16116 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16121 parser_lex(parser);
16122 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16127 parser_lex(parser);
16128 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16133 parser_lex(parser);
16134 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16139 parser_lex(parser);
16140 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16151 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16154 parser_lex(parser);
16155 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16165static const uint8_t *
16166parse_operator_symbol_name(
const pm_token_t *name) {
16167 switch (name->type) {
16170 if (name->end[-1] ==
'@')
return name->end - 1;
16182 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16184 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16185 parser_lex(parser);
16202 if (lex_mode->
mode != PM_LEX_STRING) {
16203 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16205 switch (parser->
current.type) {
16206 case PM_CASE_OPERATOR:
16207 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16216 case PM_CASE_KEYWORD:
16217 parser_lex(parser);
16228 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16236 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16237 parser_lex(parser);
16241 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16245 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16250 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16257 if (part) pm_interpolated_symbol_node_append(symbol, part);
16260 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16261 pm_interpolated_symbol_node_append(symbol, part);
16265 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16267 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16272 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16282 parser_lex(parser);
16297 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16298 pm_interpolated_symbol_node_append(symbol, part);
16301 pm_interpolated_symbol_node_append(symbol, part);
16303 if (next_state != PM_LEX_STATE_NONE) {
16304 lex_state_set(parser, next_state);
16307 parser_lex(parser);
16310 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16315 pm_string_shared_init(&unescaped, content.
start, content.
end);
16318 if (next_state != PM_LEX_STATE_NONE) {
16319 lex_state_set(parser, next_state);
16323 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16328 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16336parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16337 switch (parser->
current.type) {
16338 case PM_CASE_OPERATOR: {
16339 const pm_token_t opening = not_provided(parser);
16340 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16342 case PM_CASE_KEYWORD:
16346 parser_lex(parser);
16353 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16359 parser_lex(parser);
16361 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16364 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16376parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16377 switch (parser->
current.type) {
16378 case PM_CASE_OPERATOR: {
16379 const pm_token_t opening = not_provided(parser);
16380 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16382 case PM_CASE_KEYWORD:
16386 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16387 parser_lex(parser);
16394 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16400 parser_lex(parser);
16402 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16405 parser_lex(parser);
16406 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16408 parser_lex(parser);
16409 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16411 parser_lex(parser);
16412 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16414 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16429 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16430 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16434 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16435 if (is_numbered_param) {
16440 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16441 for (uint8_t number = 1; number <= maximum; number++) {
16442 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16449 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16472 pm_node_t *node = parse_variable(parser);
16473 if (node != NULL)
return node;
16478 pm_node_flag_set((
pm_node_t *)node, flags);
16489parse_method_definition_name(
pm_parser_t *parser) {
16490 switch (parser->
current.type) {
16491 case PM_CASE_KEYWORD:
16494 parser_lex(parser);
16497 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16498 parser_lex(parser);
16500 case PM_CASE_OPERATOR:
16501 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16502 parser_lex(parser);
16511parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16514 pm_string_ensure_owned(
string);
16519 size_t dest_length = pm_string_length(
string);
16520 const uint8_t *source_cursor = (uint8_t *) string->
source;
16521 const uint8_t *source_end = source_cursor + dest_length;
16526 size_t trimmed_whitespace = 0;
16532 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16533 if (*source_cursor ==
'\t') {
16534 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16535 if (trimmed_whitespace > common_whitespace)
break;
16537 trimmed_whitespace++;
16544 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16545 string->length = dest_length;
16555 bool dedent_next =
true;
16560 size_t write_index = 0;
16568 nodes->
nodes[write_index++] = node;
16569 dedent_next =
false;
16575 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16579 pm_node_destroy(parser, node);
16581 nodes->
nodes[write_index++] = node;
16585 dedent_next =
true;
16588 nodes->
size = write_index;
16595parse_strings_empty_content(
const uint8_t *location) {
16605 bool concating =
false;
16613 assert(lex_mode->
mode == PM_LEX_STRING);
16615 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16618 parser_lex(parser);
16640 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16641 }
else if (!lex_interpolation) {
16649 content = not_provided(parser);
16670 pm_token_t delimiters = not_provided(parser);
16671 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16672 pm_node_list_append(&parts, part);
16675 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16676 pm_node_list_append(&parts, part);
16677 parser_lex(parser);
16681 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16683 pm_node_list_free(&parts);
16685 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16686 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16688 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16689 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16691 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16696 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16705 parser_lex(parser);
16708 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16709 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16717 if (location > parser->
start && location[-1] ==
'\n') location--;
16718 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16724 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16725 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16730 pm_token_t string_opening = not_provided(parser);
16731 pm_token_t string_closing = not_provided(parser);
16733 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16734 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16735 pm_node_list_append(&parts, part);
16738 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16739 pm_node_list_append(&parts, part);
16744 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16745 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16747 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16748 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16751 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16754 pm_node_list_free(&parts);
16764 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16765 pm_node_list_append(&parts, part);
16770 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16771 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16773 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16774 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16777 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16780 pm_node_list_free(&parts);
16783 if (current == NULL) {
16799 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16809 pm_interpolated_string_node_append(container, current);
16820#define PM_PARSE_PATTERN_SINGLE 0
16821#define PM_PARSE_PATTERN_TOP 1
16822#define PM_PARSE_PATTERN_MULTI 2
16835 if (*location->
start ==
'_')
return;
16837 if (pm_constant_id_list_includes(captures, capture)) {
16838 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16840 pm_constant_id_list_append(captures, capture);
16854 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16873 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16880 parser_lex(parser);
16885 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16896 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16912 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16913 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16928 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16929 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16944 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16945 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16959 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16960 pm_array_pattern_node_requireds_append(pattern_node, inner);
16978 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16981 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16982 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16985 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16986 name = (
pm_node_t *) pm_local_variable_target_node_create(
16988 &PM_LOCATION_TOKEN_VALUE(&identifier),
16990 (uint32_t) (depth == -1 ? 0 : depth)
16995 return pm_splat_node_create(parser, &
operator, name);
17004 parser_lex(parser);
17010 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17017 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17021 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17022 value = (
pm_node_t *) pm_local_variable_target_node_create(
17024 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17026 (uint32_t) (depth == -1 ? 0 : depth)
17030 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17038pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17039 ptrdiff_t length = end - start;
17040 if (length == 0)
return false;
17043 size_t width = char_is_identifier_start(parser, start);
17044 if (width == 0)
return false;
17050 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17055 const uint8_t *cursor = start + width;
17056 while ((cursor < end) && (width = char_is_identifier(parser, cursor))) cursor += width;
17057 return cursor == end;
17071 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17072 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17074 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17076 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17077 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);
17082 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17085 parse_pattern_capture(parser, captures, constant_id, value_loc);
17090 (uint32_t) (depth == -1 ? 0 : depth)
17103 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17122 if (pm_symbol_node_label_p(first_node)) {
17123 parse_pattern_hash_key(parser, &keys, first_node);
17129 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17133 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17137 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17139 pm_node_list_append(&assocs, assoc);
17149 pm_parser_err_node(parser, first_node, diag_id);
17153 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17155 pm_node_list_append(&assocs, assoc);
17165 if (rest != NULL) {
17166 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17173 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17175 if (rest == NULL) {
17178 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17179 pm_node_list_append(&assocs, assoc);
17185 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17188 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17189 }
else if (!pm_symbol_node_label_p(key)) {
17190 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17193 expect1(parser,
PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17197 parse_pattern_hash_key(parser, &keys, key);
17201 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17203 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17207 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17209 if (rest != NULL) {
17210 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17213 pm_node_list_append(&assocs, assoc);
17220 pm_static_literals_free(&keys);
17229 switch (parser->
current.type) {
17232 parser_lex(parser);
17236 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17240 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17241 return (
pm_node_t *) pm_local_variable_target_node_create(
17243 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17245 (uint32_t) (depth == -1 ? 0 : depth)
17250 parser_lex(parser);
17255 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17260 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17273 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17274 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17287 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17288 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17300 pm_array_pattern_node_requireds_append(node, inner);
17309 parser_lex(parser);
17314 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17318 switch (parser->
current.type) {
17320 parser_lex(parser);
17321 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17324 first_node = parse_pattern_keyword_rest(parser, captures);
17327 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17331 parser_lex(parser);
17338 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17347 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17348 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17357 parser_lex(parser);
17361 switch (parser->
current.type) {
17362 case PM_CASE_PRIMITIVE: {
17363 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17364 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17367 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17368 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17369 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17373 case PM_CASE_PRIMITIVE: {
17374 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17377 if (pm_symbol_node_label_p(node))
return node;
17386 switch (parser->
current.type) {
17387 case PM_CASE_PRIMITIVE: {
17388 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17389 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17392 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17399 parser_lex(parser);
17404 switch (parser->
current.type) {
17406 parser_lex(parser);
17409 if (variable == NULL) {
17410 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17411 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17414 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17417 parser_lex(parser);
17420 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17423 parser_lex(parser);
17426 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17429 parser_lex(parser);
17432 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17435 parser_lex(parser);
17438 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17441 parser_lex(parser);
17444 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17451 parser_lex(parser);
17453 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17458 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17463 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17464 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17465 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17471 parser_lex(parser);
17476 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17480 parser_lex(parser);
17483 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17486 pm_parser_err_current(parser, diag_id);
17502 switch (parser->
current.type) {
17511 case PM_CASE_PRIMITIVE: {
17512 if (node == NULL) {
17513 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17515 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17516 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17524 parser_lex(parser);
17526 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17531 if (node == NULL) {
17534 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17540 pm_parser_err_current(parser, diag_id);
17543 if (node == NULL) {
17546 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17563 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17567 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17570 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17572 (uint32_t) (depth == -1 ? 0 : depth)
17575 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17588 bool leading_rest =
false;
17589 bool trailing_rest =
false;
17591 switch (parser->
current.type) {
17593 parser_lex(parser);
17595 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17597 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17598 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17604 node = parse_pattern_keyword_rest(parser, captures);
17605 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17607 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17608 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17616 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17618 if (pm_symbol_node_label_p(node)) {
17619 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17621 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17622 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17628 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17632 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17633 parser_lex(parser);
17634 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17635 leading_rest =
true;
17641 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17647 if (pm_symbol_node_label_p(node)) {
17648 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17651 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser,
PM_TOKEN_COMMA)) {
17656 pm_node_list_append(&nodes, node);
17663 pm_node_list_append(&nodes, node);
17664 trailing_rest =
true;
17669 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17674 if (trailing_rest) {
17675 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17678 trailing_rest =
true;
17680 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17683 pm_node_list_append(&nodes, node);
17691 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17693 if (nodes.
size == 2) {
17694 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17697 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17699 if (leading_rest && trailing_rest) {
17700 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17705 }
else if (leading_rest) {
17708 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17720parse_negative_numeric(
pm_node_t *node) {
17745 assert(
false &&
"unreachable");
17758 case PM_ERR_HASH_KEY: {
17762 case PM_ERR_HASH_VALUE:
17763 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17767 case PM_ERR_UNARY_RECEIVER: {
17772 case PM_ERR_UNARY_DISALLOWED:
17773 case PM_ERR_EXPECT_ARGUMENT: {
17778 pm_parser_err_previous(parser, diag_id);
17788#define CONTEXT_NONE 0
17789#define CONTEXT_THROUGH_ENSURE 1
17790#define CONTEXT_THROUGH_ELSE 2
17793 int context = CONTEXT_NONE;
17795 while (context_node != NULL) {
17796 switch (context_node->
context) {
17817 if (context == CONTEXT_NONE) {
17818 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17819 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17820 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17821 }
else if (context == CONTEXT_THROUGH_ELSE) {
17822 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17834 context = CONTEXT_THROUGH_ELSE;
17845 context = CONTEXT_THROUGH_ENSURE;
17849 assert(
false &&
"unreachable");
17879 context_node = context_node->
prev;
17883#undef CONTEXT_ENSURE
17894 while (context_node != NULL) {
17895 switch (context_node->
context) {
17920 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17924 assert(
false &&
"unreachable");
17965 context_node = context_node->
prev;
17997parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18001 if (callback_data->
shared) {
18007 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18020 .shared = unescaped->
type == PM_STRING_SHARED
18030parse_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) {
18031 switch (parser->
current.type) {
18033 parser_lex(parser);
18036 pm_accepts_block_stack_push(parser,
true);
18037 bool parsed_bare_hash =
false;
18053 if (accepted_newline) {
18054 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18079 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18081 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18084 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18086 if (parsed_bare_hash) {
18087 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18090 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18094 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18097 pm_static_literals_free(&hash_keys);
18098 parsed_bare_hash =
true;
18100 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18103 if (parsed_bare_hash) {
18104 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18109 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18115 operator = not_provided(parser);
18118 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18119 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18120 pm_keyword_hash_node_elements_append(hash, assoc);
18124 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18127 pm_static_literals_free(&hash_keys);
18128 parsed_bare_hash =
true;
18132 pm_array_node_elements_append(array, element);
18144 pm_array_node_close_set(array, &parser->
previous);
18145 pm_accepts_block_stack_pop(parser);
18154 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18156 parser_lex(parser);
18164 pop_block_exits(parser, previous_block_exits);
18165 pm_node_list_free(¤t_block_exits);
18167 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous);
18172 pm_accepts_block_stack_push(parser,
true);
18174 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18175 context_pop(parser);
18181 if (terminator_found) {
18190 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18193 parser_lex(parser);
18194 pm_accepts_block_stack_pop(parser);
18196 pop_block_exits(parser, previous_block_exits);
18197 pm_node_list_free(¤t_block_exits);
18208 multi_target = pm_multi_target_node_create(parser);
18209 pm_multi_target_node_targets_append(parser, multi_target, statement);
18212 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18221 if (match1(parser,
PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18222 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18234 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18237 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18242 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18252 pm_statements_node_body_append(parser, statements, statement,
true);
18262 pm_statements_node_body_append(parser, statements, statement,
true);
18266 if (!terminator_found && !match1(parser,
PM_TOKEN_EOF)) {
18272 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18273 pm_statements_node_body_append(parser, statements, node,
true);
18302 context_pop(parser);
18303 pm_accepts_block_stack_pop(parser);
18315 pm_multi_target_node_targets_append(parser, multi_target, statement);
18317 statement = (
pm_node_t *) multi_target;
18329 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18333 pop_block_exits(parser, previous_block_exits);
18334 pm_node_list_free(¤t_block_exits);
18336 pm_void_statements_check(parser, statements,
true);
18350 pm_accepts_block_stack_push(parser,
true);
18351 parser_lex(parser);
18356 if (current_hash_keys != NULL) {
18357 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18360 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18361 pm_static_literals_free(&hash_keys);
18367 pm_accepts_block_stack_pop(parser);
18369 pm_hash_node_closing_loc_set(node, &parser->
previous);
18374 parser_lex(parser);
18385 pm_node_t *node = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18386 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18391 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18397 parser_lex(parser);
18400 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18401 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18407 parser_lex(parser);
18419 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18420 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18425 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18428 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18434 parser_lex(parser);
18440 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18441 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18449 parser_lex(parser);
18451 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));
18458 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18461 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18464 parser_lex(parser);
18467 parser_lex(parser);
18468 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18470 parser_lex(parser);
18473 parser_lex(parser);
18474 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18476 parser_lex(parser);
18479 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18480 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18486 parser_lex(parser);
18489 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18490 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18496 parser_lex(parser);
18499 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18500 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18507 parser_lex(parser);
18509 pm_node_t *node = parse_variable_call(parser);
18519 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18529 if (arguments.
block != NULL) {
18551 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18552 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18558 parse_target_implicit_parameter(parser, node);
18566 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18567 parse_target_implicit_parameter(parser, node);
18570 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
18574 pm_node_destroy(parser, node);
18579 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18580 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18591 size_t common_whitespace = (size_t) -1;
18594 parser_lex(parser);
18606 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18613 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18626 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18629 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18633 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18638 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18639 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18649 pm_node_list_append(&parts, part);
18652 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18653 pm_node_list_append(&parts, part);
18659 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18661 cast->
parts = parts;
18664 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18670 pm_node_list_free(&parts);
18673 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18681 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18683 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18689 parse_heredoc_dedent(parser, nodes, common_whitespace);
18694 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18700 parser_lex(parser);
18703 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18704 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18711 parser_lex(parser);
18716 parser_lex(parser);
18717 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18721 parser_lex(parser);
18722 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18726 parser_lex(parser);
18727 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18730 parser_lex(parser);
18731 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18733 parser_lex(parser);
18736 parser_lex(parser);
18739 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18740 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18743 parser_lex(parser);
18746 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18747 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18755 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18758 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18761 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18766 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18771 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18775 size_t opening_newline_index = token_newline_index(parser);
18776 parser_lex(parser);
18782 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18789 }
else if (!token_begins_expression_p(parser->
current.type)) {
18792 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18797 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18798 parser_lex(parser);
18800 pop_block_exits(parser, previous_block_exits);
18801 pm_node_list_free(¤t_block_exits);
18803 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18804 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18809 pm_token_t end_keyword = not_provided(parser);
18813 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18820 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18821 parser_lex(parser);
18824 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18829 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18831 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18832 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18836 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18837 pm_when_node_conditions_append(when_node, condition);
18848 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18851 pm_when_clause_static_literals_add(parser, &literals, condition);
18857 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18861 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18866 if (statements != NULL) {
18867 pm_when_node_statements_set(when_node, statements);
18871 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18877 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18880 pm_static_literals_free(&literals);
18883 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18887 if (predicate == NULL) {
18888 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18895 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18900 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18902 parser_lex(parser);
18907 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));
18910 pm_constant_id_list_free(&captures);
18917 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18918 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
18921 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18922 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
18933 then_keyword = not_provided(parser);
18951 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
18952 pm_case_match_node_condition_append(case_node, condition);
18958 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18970 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18972 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18976 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18982 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18991 pop_block_exits(parser, previous_block_exits);
18992 pm_node_list_free(¤t_block_exits);
18997 size_t opening_newline_index = token_newline_index(parser);
18998 parser_lex(parser);
19004 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19008 pm_accepts_block_stack_push(parser,
true);
19009 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19010 pm_accepts_block_stack_pop(parser);
19014 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19015 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19019 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19021 pop_block_exits(parser, previous_block_exits);
19022 pm_node_list_free(¤t_block_exits);
19028 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19030 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19031 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19034 parser_lex(parser);
19044 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19047 flush_block_exits(parser, previous_block_exits);
19048 pm_node_list_free(¤t_block_exits);
19050 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19055 parser_lex(parser);
19061 token_begins_expression_p(parser->
current.type) ||
19064 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].left;
19066 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19067 parse_arguments(parser, &arguments,
false,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
19071 switch (keyword.
type) {
19084 parse_return(parser, node);
19088 assert(
false &&
"unreachable");
19093 parser_lex(parser);
19097 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19104 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19107 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19110 parser_lex(parser);
19114 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19120 if (arguments.
block != NULL) {
19121 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19122 pm_node_destroy(parser, arguments.
block);
19123 arguments.
block = NULL;
19132 size_t opening_newline_index = token_newline_index(parser);
19133 parser_lex(parser);
19136 pm_do_loop_stack_push(parser,
false);
19139 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19143 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));
19145 pm_parser_scope_push(parser,
true);
19152 pm_accepts_block_stack_push(parser,
true);
19154 pm_accepts_block_stack_pop(parser);
19159 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));
19161 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19169 pm_parser_scope_pop(parser);
19170 pm_do_loop_stack_pop(parser);
19172 flush_block_exits(parser, previous_block_exits);
19173 pm_node_list_free(¤t_block_exits);
19175 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19178 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19181 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19188 inheritance_operator = parser->
current;
19189 lex_state_set(parser, PM_LEX_STATE_BEG);
19192 parser_lex(parser);
19194 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19196 inheritance_operator = not_provided(parser);
19200 pm_parser_scope_push(parser,
true);
19210 pm_accepts_block_stack_push(parser,
true);
19212 pm_accepts_block_stack_pop(parser);
19217 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));
19219 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19224 if (context_def_p(parser)) {
19225 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19231 pm_parser_scope_pop(parser);
19232 pm_do_loop_stack_pop(parser);
19235 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19238 pop_block_exits(parser, previous_block_exits);
19239 pm_node_list_free(¤t_block_exits);
19241 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19245 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19248 size_t opening_newline_index = token_newline_index(parser);
19258 parser_lex(parser);
19262 bool valid_name =
true;
19264 switch (parser->
current.type) {
19265 case PM_CASE_OPERATOR:
19266 pm_parser_scope_push(parser,
true);
19267 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19268 parser_lex(parser);
19273 parser_lex(parser);
19276 receiver = parse_variable_call(parser);
19278 pm_parser_scope_push(parser,
true);
19279 lex_state_set(parser, PM_LEX_STATE_FNAME);
19280 parser_lex(parser);
19283 name = parse_method_definition_name(parser);
19286 pm_parser_scope_push(parser,
true);
19296 valid_name =
false;
19306 pm_parser_scope_push(parser,
true);
19307 parser_lex(parser);
19312 lex_state_set(parser, PM_LEX_STATE_FNAME);
19313 parser_lex(parser);
19316 switch (identifier.
type) {
19318 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19321 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19324 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19327 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19330 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19333 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19336 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19339 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19342 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19345 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19348 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19354 name = parse_method_definition_name(parser);
19369 context_pop(parser);
19370 parser_lex(parser);
19373 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19379 lex_state_set(parser, PM_LEX_STATE_FNAME);
19383 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
19387 pm_parser_scope_push(parser,
true);
19389 name = parse_method_definition_name(parser);
19393 pm_parser_scope_push(parser,
true);
19394 name = parse_method_definition_name(parser);
19402 switch (parser->
current.type) {
19404 parser_lex(parser);
19410 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19413 lex_state_set(parser, PM_LEX_STATE_BEG);
19416 context_pop(parser);
19426 case PM_CASE_PARAMETER: {
19430 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19433 lparen = not_provided(parser);
19434 rparen = not_provided(parser);
19435 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19437 context_pop(parser);
19441 lparen = not_provided(parser);
19442 rparen = not_provided(parser);
19445 context_pop(parser);
19455 if (token_is_setter_name(&name)) {
19456 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19461 pm_do_loop_stack_push(parser,
false);
19462 statements = (
pm_node_t *) pm_statements_node_create(parser);
19464 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));
19470 pm_node_t *value = parse_expression(parser, binding_power,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
19471 context_pop(parser);
19473 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19476 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19477 pm_do_loop_stack_pop(parser);
19478 context_pop(parser);
19479 end_keyword = not_provided(parser);
19481 equal = not_provided(parser);
19484 lex_state_set(parser, PM_LEX_STATE_BEG);
19491 pm_accepts_block_stack_push(parser,
true);
19492 pm_do_loop_stack_push(parser,
false);
19495 pm_accepts_block_stack_push(parser,
true);
19497 pm_accepts_block_stack_pop(parser);
19502 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));
19504 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19507 pm_accepts_block_stack_pop(parser);
19508 pm_do_loop_stack_pop(parser);
19516 pm_parser_scope_pop(parser);
19523 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
19525 flush_block_exits(parser, previous_block_exits);
19526 pm_node_list_free(¤t_block_exits);
19528 return (
pm_node_t *) pm_def_node_create(
19545 parser_lex(parser);
19555 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19558 rparen = not_provided(parser);
19565 lparen = not_provided(parser);
19566 rparen = not_provided(parser);
19567 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19570 context_pop(parser);
19571 return (
pm_node_t *) pm_defined_node_create(
19576 &PM_LOCATION_TOKEN_VALUE(&keyword)
19580 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19581 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19584 parser_lex(parser);
19587 if (context_def_p(parser)) {
19588 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19596 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19599 parser_lex(parser);
19602 size_t opening_newline_index = token_newline_index(parser);
19603 parser_lex(parser);
19615 if (token_begins_expression_p(parser->
current.type)) {
19616 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19619 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19620 }
else if (token_begins_expression_p(parser->
current.type)) {
19621 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19623 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19624 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19629 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19631 index = parse_target(parser, index,
false,
false);
19634 context_pop(parser);
19635 pm_do_loop_stack_push(parser,
true);
19640 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19641 pm_do_loop_stack_pop(parser);
19647 do_keyword = not_provided(parser);
19655 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19658 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19661 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19664 if (parser_end_of_line_p(parser)) {
19665 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19668 size_t opening_newline_index = token_newline_index(parser);
19670 parser_lex(parser);
19672 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19674 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19675 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19678 parser_lex(parser);
19680 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19683 pm_node_destroy(parser, name);
19685 pm_undef_node_append(undef, name);
19688 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19689 parser_lex(parser);
19690 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19693 pm_node_destroy(parser, name);
19697 pm_undef_node_append(undef, name);
19704 parser_lex(parser);
19718 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19727 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19730 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19733 size_t opening_newline_index = token_newline_index(parser);
19734 parser_lex(parser);
19736 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19740 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19742 size_t opening_newline_index = token_newline_index(parser);
19743 parser_lex(parser);
19746 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19752 pop_block_exits(parser, previous_block_exits);
19753 pm_node_list_free(¤t_block_exits);
19756 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19763 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19771 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19774 pm_parser_scope_push(parser,
true);
19779 pm_accepts_block_stack_push(parser,
true);
19781 pm_accepts_block_stack_pop(parser);
19786 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));
19788 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19794 pm_parser_scope_pop(parser);
19797 if (context_def_p(parser)) {
19798 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19801 pop_block_exits(parser, previous_block_exits);
19802 pm_node_list_free(¤t_block_exits);
19804 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19807 parser_lex(parser);
19810 parser_lex(parser);
19818 parser_lex(parser);
19821 parse_retry(parser, node);
19826 parser_lex(parser);
19829 parser_lex(parser);
19832 size_t opening_newline_index = token_newline_index(parser);
19835 pm_do_loop_stack_push(parser,
true);
19837 parser_lex(parser);
19839 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19841 pm_do_loop_stack_pop(parser);
19842 context_pop(parser);
19848 do_keyword = not_provided(parser);
19854 pm_accepts_block_stack_push(parser,
true);
19855 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19856 pm_accepts_block_stack_pop(parser);
19860 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19863 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19866 size_t opening_newline_index = token_newline_index(parser);
19869 pm_do_loop_stack_push(parser,
true);
19871 parser_lex(parser);
19873 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19875 pm_do_loop_stack_pop(parser);
19876 context_pop(parser);
19882 do_keyword = not_provided(parser);
19888 pm_accepts_block_stack_push(parser,
true);
19889 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19890 pm_accepts_block_stack_pop(parser);
19894 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19897 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19900 parser_lex(parser);
19911 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19919 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19924 pm_array_node_close_set(array, &closing);
19929 parser_lex(parser);
19938 switch (parser->
current.type) {
19940 if (current == NULL) {
19946 pm_array_node_elements_append(array, current);
19950 parser_lex(parser);
19957 if (current == NULL) {
19961 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
19962 parser_lex(parser);
19968 parser_lex(parser);
19980 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
19981 parser_lex(parser);
19984 pm_interpolated_symbol_node_append(interpolated, first_string);
19985 pm_interpolated_symbol_node_append(interpolated, second_string);
19990 assert(
false &&
"unreachable");
19996 bool start_location_set =
false;
19997 if (current == NULL) {
20003 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20013 pm_interpolated_symbol_node_append(interpolated, current);
20015 start_location_set =
true;
20022 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20024 if (!start_location_set) {
20030 bool start_location_set =
false;
20031 if (current == NULL) {
20037 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20048 pm_interpolated_symbol_node_append(interpolated, current);
20050 start_location_set =
true;
20056 assert(
false &&
"unreachable");
20059 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20061 if (!start_location_set) {
20068 parser_lex(parser);
20075 pm_array_node_elements_append(array, current);
20080 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20085 pm_array_node_close_set(array, &closing);
20090 parser_lex(parser);
20106 pm_array_node_elements_append(array,
string);
20114 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20120 pm_array_node_close_set(array, &closing);
20124 parser_lex(parser);
20133 switch (parser->
current.type) {
20139 if (current == NULL) {
20146 pm_array_node_elements_append(array, current);
20150 parser_lex(parser);
20158 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20159 parser_lex(parser);
20161 if (current == NULL) {
20178 pm_interpolated_string_node_append(interpolated, current);
20179 pm_interpolated_string_node_append(interpolated,
string);
20182 assert(
false &&
"unreachable");
20188 if (current == NULL) {
20195 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20204 pm_interpolated_string_node_append(interpolated, current);
20212 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20217 if (current == NULL) {
20224 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20233 pm_interpolated_string_node_append(interpolated, current);
20240 assert(
false &&
"unreachable");
20243 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20249 parser_lex(parser);
20256 pm_array_node_elements_append(array, current);
20261 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20267 pm_array_node_close_set(array, &closing);
20272 parser_lex(parser);
20284 parser_lex(parser);
20302 parser_lex(parser);
20315 parse_regular_expression_errors(parser, node);
20318 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20324 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20337 pm_interpolated_regular_expression_node_append(interpolated, part);
20342 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20349 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20350 pm_interpolated_regular_expression_node_append(interpolated, part);
20356 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20362 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20367 parser_lex(parser);
20384 parser_lex(parser);
20385 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20397 parser_lex(parser);
20400 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20401 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20402 parser_lex(parser);
20408 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20414 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20416 pm_interpolated_xstring_node_append(node, part);
20421 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20426 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20427 pm_interpolated_xstring_node_append(node, part);
20433 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20438 pm_interpolated_xstring_node_closing_set(node, &closing);
20443 parser_lex(parser);
20448 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20449 pm_parser_err_prefix(parser, diag_id);
20456 if (token_begins_expression_p(parser->
current.type)) {
20457 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20463 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20465 return parse_target_validate(parser, splat,
true);
20469 if (binding_power > PM_BINDING_POWER_UNARY) {
20470 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20473 parser_lex(parser);
20476 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));
20477 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20479 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20483 if (binding_power > PM_BINDING_POWER_UNARY) {
20484 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20486 parser_lex(parser);
20489 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20490 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20495 if (binding_power > PM_BINDING_POWER_UNARY) {
20496 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20498 parser_lex(parser);
20501 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20502 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20507 parser_lex(parser);
20510 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20514 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20515 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20516 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20523 parse_negative_numeric(node);
20526 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20537 size_t opening_newline_index = token_newline_index(parser);
20538 pm_accepts_block_stack_push(parser,
true);
20539 parser_lex(parser);
20542 pm_parser_scope_push(parser,
false);
20546 switch (parser->
current.type) {
20549 parser_lex(parser);
20552 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20554 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20560 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20563 case PM_CASE_PARAMETER: {
20564 pm_accepts_block_stack_push(parser,
false);
20566 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20567 pm_accepts_block_stack_pop(parser);
20571 block_parameters = NULL;
20587 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20594 pm_accepts_block_stack_push(parser,
true);
20596 pm_accepts_block_stack_pop(parser);
20601 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));
20603 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20610 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20613 pm_parser_scope_pop(parser);
20614 pm_accepts_block_stack_pop(parser);
20616 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20619 if (binding_power > PM_BINDING_POWER_UNARY) {
20620 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20622 parser_lex(parser);
20625 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20626 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20631 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20634 parser_lex(parser);
20636 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20647 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20648 pm_parser_err_prefix(parser, diag_id);
20654 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20655 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20661 pm_parser_err_prefix(parser, diag_id);
20679parse_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) {
20680 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));
20688 parser_lex(parser);
20690 pm_node_t *right = parse_expression(parser, binding_power,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20691 context_pop(parser);
20693 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20713 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20718 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20726 parse_assignment_value_local(parser, statement);
20748parse_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) {
20749 bool permitted =
true;
20750 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_USTAR)) permitted =
false;
20752 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));
20753 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20755 parse_assignment_value_local(parser, value);
20756 bool single_value =
true;
20759 single_value =
false;
20764 pm_array_node_elements_append(array, value);
20768 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20770 pm_array_node_elements_append(array, element);
20773 parse_assignment_value_local(parser, element);
20783 parser_lex(parser);
20785 bool accepts_command_call_inner =
false;
20792 accepts_command_call_inner =
true;
20796 pm_node_t *right = parse_expression(parser, binding_power, accepts_command_call_inner,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20797 context_pop(parser);
20799 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20815 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20820 if (call_node->
block != NULL) {
20821 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20823 call_node->
block = NULL;
20857parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20864 const uint8_t *source = pm_string_source(capture);
20865 size_t length = pm_string_length(capture);
20872 if (!pm_slice_is_valid_local(parser, source, source + length))
return;
20874 if (callback_data->
shared) {
20877 location = (
pm_location_t) { .start = source, .end = source + length };
20878 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20884 void *memory =
xmalloc(length);
20885 if (memory == NULL) abort();
20887 memcpy(memory, source, length);
20888 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20893 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20894 pm_constant_id_list_append(names, name);
20897 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20900 if (pm_local_is_keyword((
const char *) source, length))
return;
20904 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20909 if (callback_data->
match == NULL) {
20910 callback_data->
match = pm_match_write_node_create(parser, call);
20915 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
20916 pm_node_list_append(&callback_data->
match->
targets, target);
20930 .shared = content->
type == PM_STRING_SHARED
20937 .shared = content->
type == PM_STRING_SHARED
20940 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);
20941 pm_constant_id_list_free(&callback_data.
names);
20943 if (callback_data.
match != NULL) {
20951parse_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) {
20954 switch (token.type) {
20968 case PM_CASE_WRITABLE: {
20969 parser_lex(parser);
20970 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));
20973 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20976 return parse_write(parser, node, &token, value);
20980 pm_multi_target_node_targets_append(parser, multi_target, node);
20982 parser_lex(parser);
20983 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));
20984 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
20995 parser_lex(parser);
20996 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));
20997 return parse_unwriteable_write(parser, node, &token, value);
21003 parser_lex(parser);
21004 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21012 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21015 parser_lex(parser);
21017 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21018 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21020 pm_node_destroy(parser, node);
21024 parser_lex(parser);
21026 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21029 pm_node_destroy(parser, node);
21033 parser_lex(parser);
21035 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21038 return parse_shareable_constant_write(parser, write);
21041 parser_lex(parser);
21043 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));
21046 pm_node_destroy(parser, node);
21047 return parse_shareable_constant_write(parser, write);
21050 parser_lex(parser);
21052 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21055 pm_node_destroy(parser, node);
21060 parser_lex(parser);
21062 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));
21065 pm_node_destroy(parser, node);
21076 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21079 parser_lex(parser);
21081 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21082 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21084 pm_node_destroy(parser, (
pm_node_t *) cast);
21090 parser_lex(parser);
21096 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21097 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21101 if (pm_call_node_writable_p(parser, cast)) {
21102 parse_write_name(parser, &cast->name);
21104 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21107 parse_call_operator_write(parser, cast, &token);
21108 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));
21109 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21112 parser_lex(parser);
21113 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21117 parser_lex(parser);
21122 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21130 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21133 parser_lex(parser);
21135 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21136 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21138 pm_node_destroy(parser, node);
21142 parser_lex(parser);
21144 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));
21147 pm_node_destroy(parser, node);
21151 parser_lex(parser);
21153 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));
21156 return parse_shareable_constant_write(parser, write);
21159 parser_lex(parser);
21161 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));
21164 pm_node_destroy(parser, node);
21165 return parse_shareable_constant_write(parser, write);
21168 parser_lex(parser);
21170 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21173 pm_node_destroy(parser, node);
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_PIPEPIPEEQ, (uint16_t) (depth + 1));
21183 pm_node_destroy(parser, node);
21194 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21197 parser_lex(parser);
21199 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));
21200 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21202 pm_node_destroy(parser, (
pm_node_t *) cast);
21208 parser_lex(parser);
21214 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));
21215 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21219 if (pm_call_node_writable_p(parser, cast)) {
21220 parse_write_name(parser, &cast->name);
21222 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21225 parse_call_operator_write(parser, cast, &token);
21226 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));
21227 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21230 parser_lex(parser);
21231 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21235 parser_lex(parser);
21240 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21258 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21261 parser_lex(parser);
21263 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21264 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21266 pm_node_destroy(parser, node);
21270 parser_lex(parser);
21272 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21275 pm_node_destroy(parser, node);
21279 parser_lex(parser);
21281 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21284 return parse_shareable_constant_write(parser, write);
21287 parser_lex(parser);
21289 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21292 pm_node_destroy(parser, node);
21293 return parse_shareable_constant_write(parser, write);
21296 parser_lex(parser);
21298 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));
21301 pm_node_destroy(parser, node);
21306 parser_lex(parser);
21308 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));
21309 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21311 pm_node_destroy(parser, node);
21315 parser_lex(parser);
21323 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21326 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));
21327 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21329 pm_node_destroy(parser, (
pm_node_t *) cast);
21337 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));
21338 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21342 if (pm_call_node_writable_p(parser, cast)) {
21343 parse_write_name(parser, &cast->name);
21345 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21348 parse_call_operator_write(parser, cast, &token);
21349 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));
21350 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21353 parser_lex(parser);
21354 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21358 parser_lex(parser);
21369 parser_lex(parser);
21372 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21376 parser_lex(parser);
21379 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21389 parser_lex(parser);
21390 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21393 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21406 bool interpolated =
false;
21407 size_t total_length = 0;
21412 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21414 interpolated =
true;
21419 if (!interpolated && total_length > 0) {
21420 void *memory =
xmalloc(total_length);
21421 if (!memory) abort();
21423 uint8_t *cursor = memory;
21426 size_t length = pm_string_length(unescaped);
21428 memcpy(cursor, pm_string_source(unescaped), length);
21433 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21436 pm_string_free(&owned);
21468 parser_lex(parser);
21474 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21481 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21488 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21496 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21497 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21504 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21507 parser_lex(parser);
21508 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21509 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21513 parser_lex(parser);
21519 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21520 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21527 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21534 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21541 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21551 switch (parser->
current.type) {
21552 case PM_CASE_OPERATOR:
21553 case PM_CASE_KEYWORD:
21557 parser_lex(parser);
21567 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21568 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21571 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21576 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21583 parser_lex(parser);
21586 if (token_begins_expression_p(parser->
current.type)) {
21587 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21590 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21594 parser_lex(parser);
21596 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21597 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21601 parser_lex(parser);
21603 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21604 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21607 parser_lex(parser);
21609 pm_statements_node_body_append(parser, statements, node,
true);
21611 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21615 parser_lex(parser);
21617 pm_statements_node_body_append(parser, statements, node,
true);
21619 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21625 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21628 parser_lex(parser);
21630 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21642 context_pop(parser);
21643 pop_block_exits(parser, previous_block_exits);
21644 pm_node_list_free(¤t_block_exits);
21646 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21653 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21655 context_pop(parser);
21656 pop_block_exits(parser, previous_block_exits);
21657 pm_node_list_free(¤t_block_exits);
21659 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21662 parser_lex(parser);
21665 switch (parser->
current.type) {
21667 parser_lex(parser);
21683 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21684 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21687 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21691 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21692 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21697 case PM_CASE_OPERATOR:
21698 case PM_CASE_KEYWORD:
21701 parser_lex(parser);
21707 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21708 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21711 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21712 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21721 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21723 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
21727 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21733 parser_lex(parser);
21736 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21737 context_pop(parser);
21739 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
21742 parser_lex(parser);
21748 pm_accepts_block_stack_push(parser,
true);
21750 pm_accepts_block_stack_pop(parser);
21758 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21759 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21760 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21768 block = parse_block(parser, (uint16_t) (depth + 1));
21769 pm_arguments_validate_block(parser, &arguments, block);
21771 block = parse_block(parser, (uint16_t) (depth + 1));
21774 if (block != NULL) {
21775 if (arguments.
block != NULL) {
21776 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
21778 arguments.
arguments = pm_arguments_node_create(parser);
21780 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21786 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
21794 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21795 parser_lex(parser);
21798 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));
21801 pm_constant_id_list_free(&captures);
21803 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
21811 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21812 parser_lex(parser);
21815 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));
21818 pm_constant_id_list_free(&captures);
21820 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
21823 assert(
false &&
"unreachable");
21828#undef PM_PARSE_PATTERN_SINGLE
21829#undef PM_PARSE_PATTERN_TOP
21830#undef PM_PARSE_PATTERN_MULTI
21854parse_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) {
21856 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21860 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21875 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21885 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21893 if (pm_symbol_node_label_p(node)) {
21906 current_token_type = parser->
current.type,
21907 current_binding_powers = pm_binding_powers[current_token_type],
21908 binding_power <= current_binding_powers.
left &&
21909 current_binding_powers.
binary
21911 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21917 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21929 if (
PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21937 if (
PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21947 if (current_binding_powers.
nonassoc) {
21950 if (match1(parser, current_token_type)) {
21968 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21971 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21976 if (accepts_command_call) {
21985 switch (node->
type) {
22000 cast->
block == NULL &&
22013 accepts_command_call =
false;
22021 accepts_command_call =
false;
22036 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22038 pm_arguments_node_arguments_append(
22040 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22043 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22046 pm_parser_constant_id_constant(parser,
"print", 5)
22050 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22051 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22053 pm_arguments_node_arguments_append(
22055 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22058 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22059 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22063 pm_parser_constant_id_constant(parser,
"$F", 2),
22067 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22071 pm_arguments_node_arguments_append(
22073 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22076 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22078 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22080 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22082 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22085 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22090 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22092 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22096 statements = wrapped_statements;
22111 pm_parser_scope_push(parser,
true);
22115 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22117 parser_lex(parser);
22120 if (statements == NULL) {
22121 statements = pm_statements_node_create(parser);
22126 assert(statements->
body.
size > 0);
22127 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22132 pm_parser_scope_pop(parser);
22137 if (pm_statements_node_body_length(statements) == 0) {
22138 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22144 statements = wrap_statements(parser, statements);
22146 flush_block_exits(parser, previous_block_exits);
22147 pm_node_list_free(¤t_block_exits);
22150 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22167pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22168 size_t little_length = strlen(little);
22170 for (
const char *big_end = big + big_length; big < big_end; big++) {
22171 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22178#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22186pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22187 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22188 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22199 const char *switches = pm_strnstr(engine,
" -", length);
22200 if (switches == NULL)
return;
22205 (
const uint8_t *) (switches + 1),
22206 length - ((
size_t) (switches - engine)) - 1,
22210 size_t encoding_length;
22211 if ((encoding_length = pm_string_length(&next_options.
encoding)) > 0) {
22212 const uint8_t *encoding_source = pm_string_source(&next_options.
encoding);
22213 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22225 assert(source != NULL);
22229 .lex_state = PM_LEX_STATE_BEG,
22230 .enclosure_nesting = 0,
22231 .lambda_enclosure_nesting = -1,
22232 .brace_nesting = 0,
22233 .do_loop_stack = 0,
22234 .accepts_block_stack = 0,
22237 .stack = {{ .mode = PM_LEX_DEFAULT }},
22241 .end = source + size,
22242 .previous = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22243 .current = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22244 .next_start = NULL,
22245 .heredoc_end = NULL,
22246 .data_loc = { .start = NULL, .end = NULL },
22247 .comment_list = { 0 },
22248 .magic_comment_list = { 0 },
22249 .warning_list = { 0 },
22250 .error_list = { 0 },
22251 .current_scope = NULL,
22252 .current_context = NULL,
22254 .encoding_changed_callback = NULL,
22255 .encoding_comment_start = source,
22256 .lex_callback = NULL,
22258 .constant_pool = { 0 },
22259 .newline_list = { 0 },
22263 .explicit_encoding = NULL,
22265 .parsing_eval =
false,
22266 .partial_script =
false,
22267 .command_start =
true,
22268 .recovering =
false,
22269 .encoding_locked =
false,
22270 .encoding_changed =
false,
22271 .pattern_matching_newlines =
false,
22272 .in_keyword_arg =
false,
22273 .current_block_exits = NULL,
22274 .semantic_token_seen =
false,
22276 .current_regular_expression_ascii_only =
false,
22277 .warn_mismatched_indentation =
true
22294 uint32_t constant_size = ((uint32_t) size) / 95;
22295 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22300 size_t newline_size = size / 22;
22301 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22304 if (options != NULL) {
22312 size_t encoding_length = pm_string_length(&options->
encoding);
22313 if (encoding_length > 0) {
22314 const uint8_t *encoding_source = pm_string_source(&options->
encoding);
22315 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22337 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22339 pm_parser_scope_push(parser, scope_index == 0);
22345 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22346 const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
22348 const uint8_t *source = pm_string_source(local);
22349 size_t length = pm_string_length(local);
22351 void *allocated =
xmalloc(length);
22352 if (allocated == NULL)
continue;
22354 memcpy(allocated, source, length);
22355 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22360 pm_accepts_block_stack_push(parser,
true);
22363 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22376 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22393 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22394 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22396 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22397 const char *engine;
22399 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22400 if (newline != NULL) {
22404 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22409 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22412 search_shebang =
false;
22414 search_shebang =
true;
22420 if (search_shebang) {
22423 bool found_shebang =
false;
22427 const uint8_t *cursor = parser->
start;
22431 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22433 while (newline != NULL) {
22434 pm_newline_list_append(&parser->
newline_list, newline);
22436 cursor = newline + 1;
22437 newline = next_newline(cursor, parser->
end - cursor);
22439 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22440 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22441 const char *engine;
22442 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22443 found_shebang =
true;
22445 if (newline != NULL) {
22446 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22451 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22459 if (found_shebang) {
22463 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22490 for (node = list->
head; node != NULL; node = next) {
22502pm_magic_comment_list_free(
pm_list_t *list) {
22505 for (node = list->
head; node != NULL; node = next) {
22518 pm_string_free(&parser->
filepath);
22519 pm_diagnostic_list_free(&parser->
error_list);
22531 pm_parser_scope_pop(parser);
22535 lex_mode_pop(parser);
22544 return parse_program(parser);
22554#define LINE_SIZE 4096
22555 char line[LINE_SIZE];
22557 while (memset(line,
'\n', LINE_SIZE), fgets(line, LINE_SIZE, stream) != NULL) {
22558 size_t length = LINE_SIZE;
22559 while (length > 0 && line[length - 1] ==
'\n') length--;
22561 if (length == LINE_SIZE) {
22566 pm_buffer_append_string(buffer, line, length);
22572 pm_buffer_append_string(buffer, line, length);
22580 if (strncmp(line,
"__END__", 7) == 0)
return false;
22583 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22586 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22605pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22608 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22609 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22625 pm_buffer_init(buffer);
22627 bool eof = pm_parse_stream_read(buffer, stream, fgets);
22628 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22632 pm_node_destroy(parser, node);
22633 eof = pm_parse_stream_read(buffer, stream, fgets);
22635 pm_parser_free(parser);
22636 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22637 node = pm_parse(parser);
22647pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22649 pm_options_read(&options, data);
22652 pm_parser_init(&parser, source, size, &options);
22655 pm_node_destroy(&parser, node);
22658 pm_parser_free(&parser);
22659 pm_options_free(&options);
22664#undef PM_CASE_KEYWORD
22665#undef PM_CASE_OPERATOR
22666#undef PM_CASE_WRITABLE
22667#undef PM_STRING_EMPTY
22668#undef PM_LOCATION_NODE_BASE_VALUE
22669#undef PM_LOCATION_NODE_VALUE
22670#undef PM_LOCATION_NULL_VALUE
22671#undef PM_LOCATION_TOKEN_VALUE
22676#ifndef PRISM_EXCLUDE_SERIALIZATION
22680 pm_buffer_append_string(buffer,
"PRISM", 5);
22692 pm_serialize_header(buffer);
22694 pm_buffer_append_byte(buffer,
'\0');
22702pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22704 pm_options_read(&options, data);
22707 pm_parser_init(&parser, source, size, &options);
22711 pm_serialize_header(buffer);
22713 pm_buffer_append_byte(buffer,
'\0');
22715 pm_node_destroy(&parser, node);
22716 pm_parser_free(&parser);
22717 pm_options_free(&options);
22728 pm_options_read(&options, data);
22731 pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, fgets, &options);
22732 pm_serialize_header(buffer);
22734 pm_buffer_append_byte(buffer,
'\0');
22736 pm_node_destroy(&parser, node);
22737 pm_buffer_free(&parser_buffer);
22738 pm_parser_free(&parser);
22739 pm_options_free(&options);
22746pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22748 pm_options_read(&options, data);
22751 pm_parser_init(&parser, source, size, &options);
22754 pm_serialize_header(buffer);
22756 pm_buffer_append_varsint(buffer, parser.
start_line);
22759 pm_node_destroy(&parser, node);
22760 pm_parser_free(&parser);
22761 pm_options_free(&options);
22773 PM_SLICE_TYPE_ERROR = -1,
22776 PM_SLICE_TYPE_NONE,
22779 PM_SLICE_TYPE_LOCAL,
22782 PM_SLICE_TYPE_CONSTANT,
22785 PM_SLICE_TYPE_METHOD_NAME
22792pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22794 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22795 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22798 if (length == 0)
return PM_SLICE_TYPE_NONE;
22801 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22803 }
else if (*source ==
'_') {
22806 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22810 return PM_SLICE_TYPE_NONE;
22814 const uint8_t *end = source + length;
22815 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22821 while (source < end) {
22822 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22825 }
else if (*source ==
'_') {
22828 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22838 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22840 result = PM_SLICE_TYPE_METHOD_NAME;
22844 return source == end ? result : PM_SLICE_TYPE_NONE;
22851pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22852 switch (pm_slice_type(source, length, encoding_name)) {
22853 case PM_SLICE_TYPE_ERROR:
22855 case PM_SLICE_TYPE_NONE:
22856 case PM_SLICE_TYPE_CONSTANT:
22857 case PM_SLICE_TYPE_METHOD_NAME:
22859 case PM_SLICE_TYPE_LOCAL:
22863 assert(
false &&
"unreachable");
22871pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22872 switch (pm_slice_type(source, length, encoding_name)) {
22873 case PM_SLICE_TYPE_ERROR:
22875 case PM_SLICE_TYPE_NONE:
22876 case PM_SLICE_TYPE_LOCAL:
22877 case PM_SLICE_TYPE_METHOD_NAME:
22879 case PM_SLICE_TYPE_CONSTANT:
22883 assert(
false &&
"unreachable");
22891pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22892#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22893#define C1(c) (*source == c)
22894#define C2(s) (memcmp(source, s, 2) == 0)
22895#define C3(s) (memcmp(source, s, 3) == 0)
22897 switch (pm_slice_type(source, length, encoding_name)) {
22898 case PM_SLICE_TYPE_ERROR:
22900 case PM_SLICE_TYPE_NONE:
22902 case PM_SLICE_TYPE_LOCAL:
22904 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22905 case PM_SLICE_TYPE_CONSTANT:
22907 case PM_SLICE_TYPE_METHOD_NAME:
22914 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22916 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22918 return B(C3(
"===") || C3(
"<=>") || C3(
"[]="));
struct pm_block_parameter_node pm_block_parameter_node_t
BlockParameterNode.
struct pm_else_node pm_else_node_t
ElseNode.
struct pm_assoc_node pm_assoc_node_t
AssocNode.
struct pm_undef_node pm_undef_node_t
UndefNode.
struct pm_local_variable_target_node pm_local_variable_target_node_t
LocalVariableTargetNode.
struct pm_block_node pm_block_node_t
BlockNode.
struct pm_hash_pattern_node pm_hash_pattern_node_t
HashPatternNode.
struct pm_optional_parameter_node pm_optional_parameter_node_t
OptionalParameterNode.
struct pm_x_string_node pm_x_string_node_t
XStringNode.
struct pm_class_variable_write_node pm_class_variable_write_node_t
ClassVariableWriteNode.
struct pm_interpolated_string_node pm_interpolated_string_node_t
InterpolatedStringNode.
struct pm_call_node pm_call_node_t
CallNode.
struct pm_class_variable_read_node pm_class_variable_read_node_t
ClassVariableReadNode.
@ PM_RANGE_FLAGS_EXCLUDE_END
... operator
struct pm_local_variable_read_node pm_local_variable_read_node_t
LocalVariableReadNode.
struct pm_arguments_node pm_arguments_node_t
ArgumentsNode.
@ 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.
struct pm_begin_node pm_begin_node_t
BeginNode.
struct pm_statements_node pm_statements_node_t
StatementsNode.
struct pm_instance_variable_write_node pm_instance_variable_write_node_t
InstanceVariableWriteNode.
struct pm_keyword_hash_node pm_keyword_hash_node_t
KeywordHashNode.
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
struct pm_constant_path_node pm_constant_path_node_t
ConstantPathNode.
struct pm_local_variable_write_node pm_local_variable_write_node_t
LocalVariableWriteNode.
@ 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
struct pm_parameters_node pm_parameters_node_t
ParametersNode.
#define PM_NODE_FLAG_P(node, flag)
Return true if the given flag is set on the given node.
struct pm_case_node pm_case_node_t
CaseNode.
struct pm_if_node pm_if_node_t
IfNode.
struct pm_rescue_modifier_node pm_rescue_modifier_node_t
RescueModifierNode.
struct pm_splat_node pm_splat_node_t
SplatNode.
struct pm_match_write_node pm_match_write_node_t
MatchWriteNode.
struct pm_multi_write_node pm_multi_write_node_t
MultiWriteNode.
struct pm_interpolated_x_string_node pm_interpolated_x_string_node_t
InterpolatedXStringNode.
struct pm_constant_write_node pm_constant_write_node_t
ConstantWriteNode.
struct pm_flip_flop_node pm_flip_flop_node_t
FlipFlopNode.
#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.
struct pm_global_variable_read_node pm_global_variable_read_node_t
GlobalVariableReadNode.
struct pm_match_last_line_node pm_match_last_line_node_t
MatchLastLineNode.
struct pm_hash_node pm_hash_node_t
HashNode.
struct pm_block_local_variable_node pm_block_local_variable_node_t
BlockLocalVariableNode.
struct pm_multi_target_node pm_multi_target_node_t
MultiTargetNode.
@ 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
struct pm_rational_node pm_rational_node_t
RationalNode.
struct pm_ensure_node pm_ensure_node_t
EnsureNode.
struct pm_forwarding_parameter_node pm_forwarding_parameter_node_t
ForwardingParameterNode.
struct pm_when_node pm_when_node_t
WhenNode.
enum pm_token_type pm_token_type_t
This enum represents every type of token in the Ruby source.
struct pm_range_node pm_range_node_t
RangeNode.
struct pm_and_node pm_and_node_t
AndNode.
#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
struct pm_constant_read_node pm_constant_read_node_t
ConstantReadNode.
struct pm_or_node pm_or_node_t
OrNode.
struct pm_case_match_node pm_case_match_node_t
CaseMatchNode.
struct pm_imaginary_node pm_imaginary_node_t
ImaginaryNode.
struct pm_array_pattern_node pm_array_pattern_node_t
ArrayPatternNode.
struct pm_integer_node pm_integer_node_t
IntegerNode.
struct pm_constant_path_target_node pm_constant_path_target_node_t
ConstantPathTargetNode.
struct pm_global_variable_target_node pm_global_variable_target_node_t
GlobalVariableTargetNode.
struct pm_node_list pm_node_list_t
A list of nodes in the source, most often used for lists of children.
struct pm_required_parameter_node pm_required_parameter_node_t
RequiredParameterNode.
struct pm_symbol_node pm_symbol_node_t
SymbolNode.
struct pm_block_parameters_node pm_block_parameters_node_t
BlockParametersNode.
struct pm_parentheses_node pm_parentheses_node_t
ParenthesesNode.
@ 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
struct pm_instance_variable_read_node pm_instance_variable_read_node_t
InstanceVariableReadNode.
struct pm_constant_target_node pm_constant_target_node_t
ConstantTargetNode.
struct pm_node pm_node_t
This is the base structure that represents a node in the syntax tree.
struct pm_interpolated_symbol_node pm_interpolated_symbol_node_t
InterpolatedSymbolNode.
struct pm_class_variable_target_node pm_class_variable_target_node_t
ClassVariableTargetNode.
uint16_t pm_node_flags_t
These are the flags embedded in the node struct.
struct pm_regular_expression_node pm_regular_expression_node_t
RegularExpressionNode.
@ 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
struct pm_rescue_node pm_rescue_node_t
RescueNode.
struct pm_array_node pm_array_node_t
ArrayNode.
struct pm_global_variable_write_node pm_global_variable_write_node_t
GlobalVariableWriteNode.
@ PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
struct pm_interpolated_match_last_line_node pm_interpolated_match_last_line_node_t
InterpolatedMatchLastLineNode.
struct pm_unless_node pm_unless_node_t
UnlessNode.
struct pm_interpolated_regular_expression_node pm_interpolated_regular_expression_node_t
InterpolatedRegularExpressionNode.
struct pm_instance_variable_target_node pm_instance_variable_target_node_t
InstanceVariableTargetNode.
struct pm_string_node pm_string_node_t
StringNode.
struct pm_float_node pm_float_node_t
FloatNode.
@ PM_LOOP_FLAGS_BEGIN_MODIFIER
a loop after a begin statement, so the body is executed first before the condition
struct pm_find_pattern_node pm_find_pattern_node_t
FindPatternNode.
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.
struct pm_options_scope pm_options_scope_t
A scope of locals surrounding the code that is being parsed.
struct pm_options pm_options_t
The options that can be passed to the parser.
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.
struct pm_locals pm_locals_t
This is a set of local variables in a certain lexical context (method, class, module,...
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_lex_mode pm_lex_mode_t
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
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?
@ PM_CONTEXT_MODULE_ENSURE
an ensure statement within a module statement
@ PM_CONTEXT_BEGIN_RESCUE
a rescue statement with an explicit begin
@ PM_CONTEXT_UNTIL
an until statement
@ PM_CONTEXT_DEF_ELSE
a rescue else statement within a method definition
@ PM_CONTEXT_FOR
a for loop
@ PM_CONTEXT_PREDICATE
a predicate inside an if/elsif/unless statement
@ PM_CONTEXT_BEGIN_ENSURE
an ensure statement with an explicit begin
@ PM_CONTEXT_SCLASS_ENSURE
an ensure statement with a singleton class
@ PM_CONTEXT_DEFAULT_PARAMS
a method definition's default parameter
@ PM_CONTEXT_LAMBDA_ELSE
a rescue else statement within a lambda expression
@ PM_CONTEXT_CLASS
a class declaration
@ PM_CONTEXT_MAIN
the top level context
@ PM_CONTEXT_LAMBDA_DO_END
a lambda expression with do..end
@ PM_CONTEXT_BEGIN
a begin statement
@ PM_CONTEXT_RESCUE_MODIFIER
a modifier rescue clause
@ PM_CONTEXT_EMBEXPR
an interpolated expression
@ PM_CONTEXT_TERNARY
a ternary expression
@ PM_CONTEXT_DEF
a method definition
@ PM_CONTEXT_SCLASS_ELSE
a rescue else statement with a singleton class
@ PM_CONTEXT_MODULE_RESCUE
a rescue statement within a module statement
@ PM_CONTEXT_BLOCK_KEYWORDS
expressions in block arguments using do..end
@ PM_CONTEXT_WHILE
a while statement
uint8_t pm_shareable_constant_value_t
The type of shareable constant value that can be set.
pm_comment_type_t
This is the type of a comment that we've found while parsing.
#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.
struct pm_list_node pm_list_node_t
This struct represents an abstract linked list that provides common functionality.
#define PM_STRING_EMPTY
Defines an empty string.
#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.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
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_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.
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.
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.
pm_integer_t value
IntegerNode#value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
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...
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.
union pm_lex_mode::@303336126360075302344075121136356113360170030306 as
The data associated with this type of lex mode.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
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...
enum pm_lex_mode::@204051102252353332352362146052355003264223055126 mode
The type of this lex mode.
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.
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.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
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.
size_t locals_count
The number of locals in the scope.
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.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
pm_lex_state_t lex_state
The current state of the lexer.
uint8_t command_line
The command line flags given from the options.
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool partial_script
Whether or not we are parsing a "partial" script, which is a script that will be evaluated in the con...
bool pattern_matching_newlines
This flag indicates that we are currently parsing a pattern matching expression and impacts that calc...
const uint8_t * end
The pointer to the end of the source.
bool recovering
Whether or not we're currently recovering from a syntax error.
pm_node_flags_t integer_base
We want to add a flag to integer nodes that indicates their base.
bool warn_mismatched_indentation
By default, Ruby always warns about mismatched indentation.
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
bool in_keyword_arg
This flag indicates that we are currently parsing a keyword argument.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
pm_token_t previous
The previous token we were considering.
pm_string_t current_string
This string is used to pass information from the lexer to the parser.
bool parsing_eval
Whether or not we are parsing an eval string.
bool current_regular_expression_ascii_only
True if the current regular expression being lexed contains only ASCII characters.
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
pm_location_t data_loc
An optional location that represents the location of the END marker and the rest of the content of th...
pm_context_node_t * current_context
The current parsing context.
const uint8_t * start
The pointer to the start of the source.
int enclosure_nesting
Tracks the current nesting of (), [], and {}.
pm_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.
struct pm_parser::@236040131255244317313236162207277265316171136011 lex_modes
A stack of lex modes.
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...
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.
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::@346265266332060241255337121126133217326336224105 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.