15#define PM_TAB_WHITESPACE_SIZE 8
18#define MIN(a,b) (((a)<(b))?(a):(b))
19#define MAX(a,b) (((a)>(b))?(a):(b))
30lex_mode_incrementor(
const uint8_t start) {
47lex_mode_terminator(
const uint8_t start) {
89lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
90 uint8_t incrementor = lex_mode_incrementor(delimiter);
91 uint8_t terminator = lex_mode_terminator(delimiter);
97 .interpolation = interpolation,
98 .incrementor = incrementor,
99 .terminator = terminator
106 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
111 if (terminator !=
'\0') {
112 breakpoints[index++] = terminator;
118 breakpoints[index++] =
'#';
122 if (incrementor !=
'\0') {
123 breakpoints[index++] = incrementor;
127 return lex_mode_push(parser, lex_mode);
137 return lex_mode_push_list(parser,
false,
'\0');
144lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
146 .
mode = PM_LEX_REGEXP,
149 .incrementor = incrementor,
150 .terminator = terminator
158 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
162 if (terminator !=
'\0') {
163 breakpoints[index++] = terminator;
167 if (incrementor !=
'\0') {
168 breakpoints[index++] = incrementor;
172 return lex_mode_push(parser, lex_mode);
179lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
181 .
mode = PM_LEX_STRING,
184 .interpolation = interpolation,
185 .label_allowed = label_allowed,
186 .incrementor = incrementor,
187 .terminator = terminator
194 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
199 if (terminator !=
'\0') {
200 breakpoints[index++] = terminator;
206 breakpoints[index++] =
'#';
211 if (incrementor !=
'\0') {
212 breakpoints[index++] = incrementor;
216 return lex_mode_push(parser, lex_mode);
226 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
258 PM_IGNORED_NEWLINE_NONE = 0,
259 PM_IGNORED_NEWLINE_ALL,
260 PM_IGNORED_NEWLINE_PATTERN
261} pm_ignored_newline_type_t;
263static inline pm_ignored_newline_type_t
265 bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
268 return PM_IGNORED_NEWLINE_ALL;
269 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
270 return PM_IGNORED_NEWLINE_PATTERN;
272 return PM_IGNORED_NEWLINE_NONE;
278 return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->
lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
283 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
287lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
291 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
296 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
304 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
316#ifndef PM_DEBUG_LOGGING
321#define PM_DEBUG_LOGGING 0
327 fprintf(stderr,
"STATE: ");
330 if (parser->
lex_state == PM_LEX_STATE_NONE) {
331 fprintf(stderr,
"NONE\n");
335#define CHECK_STATE(state) \
336 if (parser->lex_state & state) { \
337 if (!first) fprintf(stderr, "|"); \
338 fprintf(stderr, "%s", #state); \
342 CHECK_STATE(PM_LEX_STATE_BEG)
343 CHECK_STATE(PM_LEX_STATE_END)
344 CHECK_STATE(PM_LEX_STATE_ENDARG)
345 CHECK_STATE(PM_LEX_STATE_ENDFN)
346 CHECK_STATE(PM_LEX_STATE_ARG)
347 CHECK_STATE(PM_LEX_STATE_CMDARG)
348 CHECK_STATE(PM_LEX_STATE_MID)
349 CHECK_STATE(PM_LEX_STATE_FNAME)
350 CHECK_STATE(PM_LEX_STATE_DOT)
351 CHECK_STATE(PM_LEX_STATE_CLASS)
352 CHECK_STATE(PM_LEX_STATE_LABEL)
353 CHECK_STATE(PM_LEX_STATE_LABELED)
354 CHECK_STATE(PM_LEX_STATE_FITEM)
358 fprintf(stderr,
"\n");
363 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
365 lex_state_set(parser, state);
366 fprintf(stderr,
"Now: ");
368 fprintf(stderr,
"\n");
371#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
379#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
382#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
385#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
388#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
391#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
394#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
397#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
408 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
414#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
415 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
423 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
430#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
431 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
446#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
447 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
453#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
454 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
471 pm_parser_err(parser, token->start, token->end, diag_id);
478#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
479 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
485#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
486 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
493 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
502 pm_parser_warn(parser, token->start, token->end, diag_id);
517#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
518 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
524#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
525 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
531#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
532 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
538#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
539 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
547pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
548 PM_PARSER_ERR_FORMAT(
551 ident_start + ident_length,
554 (
const char *) ident_start
566pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
568 if (scope == NULL)
return false;
573 .parameters = PM_SCOPE_PARAMETERS_NONE,
574 .implicit_parameters = { 0 },
592 if (scope->
previous == NULL)
return true;
593 if (scope->
closed)
return false;
594 }
while ((scope = scope->
previous) != NULL);
596 assert(
false &&
"unreachable");
604pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
607 while (depth-- > 0) {
608 assert(scope != NULL);
616 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
617 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
618 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
619} pm_scope_forwarding_param_check_result_t;
621static pm_scope_forwarding_param_check_result_t
622pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
624 bool conflict =
false;
626 while (scope != NULL) {
630 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
632 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
643 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
648 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
649 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
652 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
653 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
655 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
656 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
663 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
664 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
668 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
678 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
679 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
687 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
688 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
695 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
696 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
699 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
700 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
702 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
703 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
712pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
736#define PM_LOCALS_HASH_THRESHOLD 9
751 name = ((name >> 16) ^ name) * 0x45d9f3b;
752 name = ((name >> 16) ^ name) * 0x45d9f3b;
753 name = (name >> 16) ^ name;
763 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
764 assert(next_capacity > locals->
capacity);
767 if (next_locals == NULL) abort();
769 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
770 if (locals->
size > 0) {
776 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
777 uint32_t mask = next_capacity - 1;
779 for (uint32_t index = 0; index < locals->
capacity; index++) {
783 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
785 uint32_t hash = local->
hash;
787 next_locals[hash & mask] = *local;
792 pm_locals_free(locals);
793 locals->
locals = next_locals;
815 pm_locals_resize(locals);
818 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
819 for (uint32_t index = 0; index < locals->
capacity; index++) {
825 .location = { .start = start, .end = end },
826 .index = locals->
size++,
831 }
else if (local->
name == name) {
836 uint32_t mask = locals->
capacity - 1;
837 uint32_t hash = pm_locals_hash(name);
838 uint32_t initial_hash = hash;
846 .location = { .start = start, .end = end },
847 .index = locals->
size++,
852 }
else if (local->
name == name) {
857 }
while ((hash & mask) != initial_hash);
860 assert(
false &&
"unreachable");
870 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
871 for (uint32_t index = 0; index < locals->
size; index++) {
873 if (local->
name == name)
return index;
876 uint32_t mask = locals->
capacity - 1;
877 uint32_t hash = pm_locals_hash(name);
878 uint32_t initial_hash = hash & mask;
885 }
else if (local->
name == name) {
890 }
while ((hash & mask) != initial_hash);
902 uint32_t index = pm_locals_find(locals, name);
903 assert(index != UINT32_MAX);
906 assert(local->
reads < UINT32_MAX);
917 uint32_t index = pm_locals_find(locals, name);
918 assert(index != UINT32_MAX);
921 assert(local->
reads > 0);
931 uint32_t index = pm_locals_find(locals, name);
932 assert(index != UINT32_MAX);
947 pm_constant_id_list_init_capacity(list, locals->
size);
952 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
956 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
958 for (uint32_t index = 0; index < capacity; index++) {
962 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
964 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
965 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
967 if (constant->
length >= 1 && *constant->
start !=
'_') {
968 PM_PARSER_WARN_FORMAT(
972 PM_WARN_UNUSED_LOCAL_VARIABLE,
974 (
const char *) constant->
start
990pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
991 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
998pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
999 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1006pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1007 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1015 return pm_parser_constant_id_location(parser, token->start, token->end);
1036 while (node != NULL) {
1044 return void_node != NULL ? void_node : node;
1053 if (vn != NULL)
return vn;
1058 if (vn != NULL)
return vn;
1066 if (vn == NULL)
return NULL;
1067 if (void_node == NULL) void_node = vn;
1070 pm_node_t *vn = pm_check_value_expression(parser, (
pm_node_t *) rescue_clause->statements);
1075 if (void_node == NULL) {
1115 if (void_node == NULL) {
1130 if (void_node == NULL) {
1155 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1170 pm_node_t *void_node = pm_check_value_expression(parser, node);
1171 if (void_node != NULL) {
1172 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1181 const char *
type = NULL;
1191 type =
"a variable";
1199 switch (message->
length) {
1201 switch (message->
start[0]) {
1218 switch (message->
start[1]) {
1220 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1226 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1232 if (message->
start[0] ==
'*') {
1240 if (memcmp(message->
start,
"<=>", 3) == 0) {
1254 type =
"a constant";
1310 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1321 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1322 for (
size_t index = 0; index < size; index++) {
1323 pm_void_statement_check(parser, node->
body.
nodes[index]);
1333 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1334 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1335 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1336} pm_conditional_predicate_type_t;
1344 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1345 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1347 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1348 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1350 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1360pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1363 if (
PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1366 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1367 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1373 if (
PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1376 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1381 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1411 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1433 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1434 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1439 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1440 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1448 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1464 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1465 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1484 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1485 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1496 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1497 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1502 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1503 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1504 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1507 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1513 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1517 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1524 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1562#define PM_LOCATION_NULL_VALUE(parser) ((pm_location_t) { .start = (parser)->start, .end = (parser)->start })
1563#define PM_LOCATION_TOKEN_VALUE(token) ((pm_location_t) { .start = (token)->start, .end = (token)->end })
1564#define PM_LOCATION_NODE_VALUE(node) ((pm_location_t) { .start = (node)->location.start, .end = (node)->location.end })
1565#define PM_LOCATION_NODE_BASE_VALUE(node) ((pm_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end })
1566#define PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((pm_location_t) { .start = NULL, .end = NULL })
1567#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : PM_LOCATION_TOKEN_VALUE(token))
1595static inline const uint8_t *
1597 if (arguments->
block != NULL) {
1638 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1652char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1653 if (n <= 0)
return 0;
1660 }
else if (*b ==
'_') {
1662 }
else if (*b >= 0x80) {
1667 }
else if (*b < 0x80) {
1670 return pm_encoding_utf_8_char_width(b, n);
1679char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1682 }
else if (*b < 0x80) {
1685 return pm_encoding_utf_8_char_width(b, n);
1695char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1703 }
else if (*b ==
'_') {
1705 }
else if (*b >= 0x80) {
1711 return char_is_identifier_utf8(b, n);
1718#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1719#define PUNCT(idx) ( \
1720 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1721 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1722 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1723 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1724 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1727const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1733char_is_global_name_punctuation(const uint8_t b) {
1734 const unsigned int i = (const unsigned int) b;
1735 if (i <= 0x20 || 0x7e < i) return false;
1737 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1741token_is_setter_name(pm_token_t *token) {
1743 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1744 ((token->type == PM_TOKEN_IDENTIFIER) &&
1745 (token->end - token->start >= 2) &&
1746 (token->end[-1] == '='))
1754pm_local_is_keyword(const char *source, size_t length) {
1755#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1759 switch (source[0]) {
1760 case 'd': KEYWORD("do"); return false;
1761 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1762 case 'o': KEYWORD("or"); return false;
1763 default: return false;
1766 switch (source[0]) {
1767 case 'a': KEYWORD("and"); return false;
1768 case 'd': KEYWORD("def"); return false;
1769 case 'e': KEYWORD("end"); return false;
1770 case 'f': KEYWORD("for"); return false;
1771 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1772 default: return false;
1775 switch (source[0]) {
1776 case 'c': KEYWORD("case"); return false;
1777 case 'e': KEYWORD("else"); return false;
1778 case 'n': KEYWORD("next"); return false;
1779 case 'r': KEYWORD("redo"); return false;
1780 case 's': KEYWORD("self"); return false;
1781 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1782 case 'w': KEYWORD("when"); return false;
1783 default: return false;
1786 switch (source[0]) {
1787 case 'a': KEYWORD("alias"); return false;
1788 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1789 case 'c': KEYWORD("class"); return false;
1790 case 'e': KEYWORD("elsif"); return false;
1791 case 'f': KEYWORD("false"); return false;
1792 case 'r': KEYWORD("retry"); return false;
1793 case 's': KEYWORD("super"); return false;
1794 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1795 case 'w': KEYWORD("while"); return false;
1796 case 'y': KEYWORD("yield"); return false;
1797 default: return false;
1800 switch (source[0]) {
1801 case 'e': KEYWORD("ensure"); return false;
1802 case 'm': KEYWORD("module"); return false;
1803 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1804 case 'u': KEYWORD("unless"); return false;
1805 default: return false;
1808 KEYWORD("__LINE__");
1809 KEYWORD("__FILE__");
1812 KEYWORD("__ENCODING__");
1821/******************************************************************************/
1822/* Node flag handling functions */
1823/******************************************************************************/
1829pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1830 node->flags |= flag;
1837pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1838 node->flags &= (pm_node_flags_t) ~flag;
1845pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1846 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1847 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1848 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1849 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1850 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1851 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1852 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1853 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1855 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1858/******************************************************************************/
1859/* Node creation functions */
1860/******************************************************************************/
1867#define PM_REGULAR_EXPRESSION_ENCODING_MASK ~(PM_REGULAR_EXPRESSION_FLAGS_EUC_JP | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J | PM_REGULAR_EXPRESSION_FLAGS_UTF_8)
1872static inline pm_node_flags_t
1873pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1874 pm_node_flags_t flags = 0;
1876 if (closing->type == PM_TOKEN_REGEXP_END) {
1877 pm_buffer_t unknown_flags = { 0 };
1879 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1881 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1882 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1883 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1884 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1886 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1887 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1888 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1889 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1891 default: pm_buffer_append_byte(&unknown_flags, *flag);
1895 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1896 if (unknown_flags_length != 0) {
1897 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1898 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1900 pm_buffer_free(&unknown_flags);
1906#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1908static pm_statements_node_t *
1909pm_statements_node_create(pm_parser_t *parser);
1912pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1915pm_statements_node_body_length(pm_statements_node_t *node);
1922pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1923 void *memory = xcalloc(1, size);
1924 if (memory == NULL) {
1925 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1931#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
1932#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
1937static pm_missing_node_t *
1938pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1939 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1941 *node = (pm_missing_node_t) {{
1942 .type = PM_MISSING_NODE,
1943 .node_id = PM_NODE_IDENTIFY(parser),
1944 .location = { .start = start, .end = end }
1953static pm_alias_global_variable_node_t *
1954pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1955 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1956 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1958 *node = (pm_alias_global_variable_node_t) {
1960 .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
1961 .node_id = PM_NODE_IDENTIFY(parser),
1963 .start = keyword->start,
1964 .end = old_name->location.end
1967 .new_name = new_name,
1968 .old_name = old_name,
1969 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1978static pm_alias_method_node_t *
1979pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1980 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1981 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
1983 *node = (pm_alias_method_node_t) {
1985 .type = PM_ALIAS_METHOD_NODE,
1986 .node_id = PM_NODE_IDENTIFY(parser),
1988 .start = keyword->start,
1989 .end = old_name->location.end
1992 .new_name = new_name,
1993 .old_name = old_name,
1994 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2003static pm_alternation_pattern_node_t *
2004pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2005 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2007 *node = (pm_alternation_pattern_node_t) {
2009 .type = PM_ALTERNATION_PATTERN_NODE,
2010 .node_id = PM_NODE_IDENTIFY(parser),
2012 .start = left->location.start,
2013 .end = right->location.end
2018 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2027static pm_and_node_t *
2028pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2029 pm_assert_value_expression(parser, left);
2031 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2033 *node = (pm_and_node_t) {
2035 .type = PM_AND_NODE,
2036 .node_id = PM_NODE_IDENTIFY(parser),
2038 .start = left->location.start,
2039 .end = right->location.end
2043 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2053static pm_arguments_node_t *
2054pm_arguments_node_create(pm_parser_t *parser) {
2055 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2057 *node = (pm_arguments_node_t) {
2059 .type = PM_ARGUMENTS_NODE,
2060 .node_id = PM_NODE_IDENTIFY(parser),
2061 .location = PM_LOCATION_NULL_VALUE(parser)
2073pm_arguments_node_size(pm_arguments_node_t *node) {
2074 return node->arguments.size;
2081pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2082 if (pm_arguments_node_size(node) == 0) {
2083 node->base.location.start = argument->location.start;
2086 node->base.location.end = argument->location.end;
2087 pm_node_list_append(&node->arguments, argument);
2089 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2090 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2091 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2093 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2101static pm_array_node_t *
2102pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2103 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2105 *node = (pm_array_node_t) {
2107 .type = PM_ARRAY_NODE,
2108 .flags = PM_NODE_FLAG_STATIC_LITERAL,
2109 .node_id = PM_NODE_IDENTIFY(parser),
2110 .location = PM_LOCATION_TOKEN_VALUE(opening)
2112 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2113 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2124pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2125 if (!node->elements.size && !node->opening_loc.start) {
2126 node->base.location.start = element->location.start;
2129 pm_node_list_append(&node->elements, element);
2130 node->base.location.end = element->location.end;
2132 // If the element is not a static literal, then the array is not a static
2133 // literal. Turn that flag off.
2134 if (PM_NODE_TYPE_P(element, PM_ARRAY_NODE) || PM_NODE_TYPE_P(element, PM_HASH_NODE) || PM_NODE_TYPE_P(element, PM_RANGE_NODE) || !PM_NODE_FLAG_P(element, PM_NODE_FLAG_STATIC_LITERAL)) {
2135 pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
2138 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2139 pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2147pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2148 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2149 node->base.location.end = closing->end;
2150 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2157static pm_array_pattern_node_t *
2158pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2159 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2161 *node = (pm_array_pattern_node_t) {
2163 .type = PM_ARRAY_PATTERN_NODE,
2164 .node_id = PM_NODE_IDENTIFY(parser),
2166 .start = nodes->nodes[0]->location.start,
2167 .end = nodes->nodes[nodes->size - 1]->location.end
2174 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2175 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2178 // For now we're going to just copy over each pointer manually. This could be
2179 // much more efficient, as we could instead resize the node list.
2180 bool found_rest = false;
2183 PM_NODE_LIST_FOREACH(nodes, index, child) {
2184 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2187 } else if (found_rest) {
2188 pm_node_list_append(&node->posts, child);
2190 pm_node_list_append(&node->requireds, child);
2200static pm_array_pattern_node_t *
2201pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2202 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2204 *node = (pm_array_pattern_node_t) {
2206 .type = PM_ARRAY_PATTERN_NODE,
2207 .node_id = PM_NODE_IDENTIFY(parser),
2208 .location = rest->location,
2214 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2215 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2227 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2229 *node = (pm_array_pattern_node_t) {
2231 .type = PM_ARRAY_PATTERN_NODE,
2232 .node_id = PM_NODE_IDENTIFY(parser),
2234 .start = constant->location.start,
2238 .constant = constant,
2240 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2241 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2253static pm_array_pattern_node_t *
2254pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2255 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2257 *node = (pm_array_pattern_node_t) {
2259 .type = PM_ARRAY_PATTERN_NODE,
2260 .node_id = PM_NODE_IDENTIFY(parser),
2262 .start = opening->start,
2268 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2269 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2278pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2279 pm_node_list_append(&node->requireds, inner);
2285static pm_assoc_node_t *
2286pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2287 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2290 if (value != NULL && value->location.end > key->location.end) {
2291 end = value->location.end;
2292 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2293 end = operator->end;
2295 end = key->location.end;
2298 // Hash string keys will be frozen, so we can mark them as frozen here so
2299 // that the compiler picks them up and also when we check for static literal
2300 // on the keys it gets factored in.
2301 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2302 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2305 // If the key and value of this assoc node are both static literals, then
2306 // we can mark this node as a static literal.
2307 pm_node_flags_t flags = 0;
2309 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2310 value && !PM_NODE_TYPE_P(value, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(value, PM_HASH_NODE) && !PM_NODE_TYPE_P(value, PM_RANGE_NODE)
2312 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2315 *node = (pm_assoc_node_t) {
2317 .type = PM_ASSOC_NODE,
2319 .node_id = PM_NODE_IDENTIFY(parser),
2321 .start = key->location.start,
2326 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2336static pm_assoc_splat_node_t *
2337pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2338 assert(operator->type == PM_TOKEN_USTAR_STAR);
2339 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2341 *node = (pm_assoc_splat_node_t) {
2343 .type = PM_ASSOC_SPLAT_NODE,
2344 .node_id = PM_NODE_IDENTIFY(parser),
2346 .start = operator->start,
2347 .end = value == NULL ? operator->end : value->location.end
2351 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2360static pm_back_reference_read_node_t *
2361pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2362 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2363 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2365 *node = (pm_back_reference_read_node_t) {
2367 .type = PM_BACK_REFERENCE_READ_NODE,
2368 .node_id = PM_NODE_IDENTIFY(parser),
2369 .location = PM_LOCATION_TOKEN_VALUE(name),
2371 .name = pm_parser_constant_id_token(parser, name)
2380static pm_begin_node_t *
2381pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2382 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2384 *node = (pm_begin_node_t) {
2386 .type = PM_BEGIN_NODE,
2387 .node_id = PM_NODE_IDENTIFY(parser),
2389 .start = begin_keyword->start,
2390 .end = statements == NULL ? begin_keyword->end : statements->base.location.end
2393 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2394 .statements = statements,
2395 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2405pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2406 // If the begin keyword doesn't exist, we set the start on the begin_node
2407 if (!node->begin_keyword_loc.start) {
2408 node->base.location.start = rescue_clause->base.location.start;
2410 node->base.location.end = rescue_clause->base.location.end;
2411 node->rescue_clause = rescue_clause;
2418pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2419 node->base.location.end = else_clause->base.location.end;
2420 node->else_clause = else_clause;
2427pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2428 node->base.location.end = ensure_clause->base.location.end;
2429 node->ensure_clause = ensure_clause;
2436pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2437 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2439 node->base.location.end = end_keyword->end;
2440 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2446static pm_block_argument_node_t *
2447pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2448 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2450 *node = (pm_block_argument_node_t) {
2452 .type = PM_BLOCK_ARGUMENT_NODE,
2453 .node_id = PM_NODE_IDENTIFY(parser),
2455 .start = operator->start,
2456 .end = expression == NULL ? operator->end : expression->location.end
2459 .expression = expression,
2460 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2469static pm_block_node_t *
2470pm_block_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *opening, pm_node_t *parameters, pm_node_t *body, const pm_token_t *closing) {
2471 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2473 *node = (pm_block_node_t) {
2475 .type = PM_BLOCK_NODE,
2476 .node_id = PM_NODE_IDENTIFY(parser),
2477 .location = { .start = opening->start, .end = closing->end },
2480 .parameters = parameters,
2482 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2483 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2492static pm_block_parameter_node_t *
2493pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2494 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2495 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2497 *node = (pm_block_parameter_node_t) {
2499 .type = PM_BLOCK_PARAMETER_NODE,
2500 .node_id = PM_NODE_IDENTIFY(parser),
2502 .start = operator->start,
2503 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
2506 .name = pm_parser_optional_constant_id_token(parser, name),
2507 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2508 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2517static pm_block_parameters_node_t *
2518pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2519 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2521 const uint8_t *start;
2522 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2523 start = opening->start;
2524 } else if (parameters != NULL) {
2525 start = parameters->base.location.start;
2531 if (parameters != NULL) {
2532 end = parameters->base.location.end;
2533 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2539 *node = (pm_block_parameters_node_t) {
2541 .type = PM_BLOCK_PARAMETERS_NODE,
2542 .node_id = PM_NODE_IDENTIFY(parser),
2548 .parameters = parameters,
2549 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2550 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2561pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2562 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2564 node->base.location.end = closing->end;
2565 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2571static pm_block_local_variable_node_t *
2572pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2573 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2575 *node = (pm_block_local_variable_node_t) {
2577 .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
2578 .node_id = PM_NODE_IDENTIFY(parser),
2579 .location = PM_LOCATION_TOKEN_VALUE(name),
2581 .name = pm_parser_constant_id_token(parser, name)
2591pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2592 pm_node_list_append(&node->locals, (pm_node_t *) local);
2594 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2595 node->base.location.end = local->base.location.end;
2601static pm_break_node_t *
2602pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2603 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2604 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2606 *node = (pm_break_node_t) {
2608 .type = PM_BREAK_NODE,
2609 .node_id = PM_NODE_IDENTIFY(parser),
2611 .start = keyword->start,
2612 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
2615 .arguments = arguments,
2616 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2622// There are certain flags that we want to use internally but don't want to
2623// expose because they are not relevant beyond parsing. Therefore we'll define
2624// them here and not define them in config.yml/a header file.
2625static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
2626static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
2627static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
2628static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
2635static pm_call_node_t *
2636pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2637 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2639 *node = (pm_call_node_t) {
2641 .type = PM_CALL_NODE,
2643 .node_id = PM_NODE_IDENTIFY(parser),
2644 .location = PM_LOCATION_NULL_VALUE(parser),
2647 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2648 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2649 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2651 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2663static inline pm_node_flags_t
2664pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2665 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2672static pm_call_node_t *
2673pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2674 pm_assert_value_expression(parser, receiver);
2676 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2677 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2678 flags |= PM_CALL_NODE_FLAGS_INDEX;
2681 pm_call_node_t *node = pm_call_node_create(parser, flags);
2683 node->base.location.start = receiver->location.start;
2684 node->base.location.end = pm_arguments_end(arguments);
2686 node->receiver = receiver;
2687 node->message_loc.start = arguments->opening_loc.start;
2688 node->message_loc.end = arguments->closing_loc.end;
2690 node->opening_loc = arguments->opening_loc;
2691 node->arguments = arguments->arguments;
2692 node->closing_loc = arguments->closing_loc;
2693 node->block = arguments->block;
2695 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2702static pm_call_node_t *
2703pm_call_node_binary_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_node_t *argument, pm_node_flags_t flags) {
2704 pm_assert_value_expression(parser, receiver);
2705 pm_assert_value_expression(parser, argument);
2707 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2709 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2710 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2712 node->receiver = receiver;
2713 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2715 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2716 pm_arguments_node_arguments_append(arguments, argument);
2717 node->arguments = arguments;
2719 node->name = pm_parser_constant_id_token(parser, operator);
2726static pm_call_node_t *
2727pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2728 pm_assert_value_expression(parser, receiver);
2730 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2732 node->base.location.start = receiver->location.start;
2733 const uint8_t *end = pm_arguments_end(arguments);
2737 node->base.location.end = end;
2739 node->receiver = receiver;
2740 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2741 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2742 node->opening_loc = arguments->opening_loc;
2743 node->arguments = arguments->arguments;
2744 node->closing_loc = arguments->closing_loc;
2745 node->block = arguments->block;
2747 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2748 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2751 node->name = pm_parser_constant_id_token(parser, message);
2758static pm_call_node_t *
2759pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2760 pm_call_node_t *node = pm_call_node_create(parser, 0);
2761 node->base.location.start = parser->start;
2762 node->base.location.end = parser->end;
2764 node->receiver = receiver;
2765 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2766 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2767 node->arguments = arguments;
2769 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2777static pm_call_node_t *
2778pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2779 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2781 node->base.location.start = message->start;
2782 node->base.location.end = pm_arguments_end(arguments);
2784 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2785 node->opening_loc = arguments->opening_loc;
2786 node->arguments = arguments->arguments;
2787 node->closing_loc = arguments->closing_loc;
2788 node->block = arguments->block;
2790 node->name = pm_parser_constant_id_token(parser, message);
2798static pm_call_node_t *
2799pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2800 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2802 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2803 node->arguments = arguments;
2812static pm_call_node_t *
2813pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2814 pm_assert_value_expression(parser, receiver);
2815 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2817 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2819 node->base.location.start = message->start;
2820 if (arguments->closing_loc.start != NULL) {
2821 node->base.location.end = arguments->closing_loc.end;
2823 assert(receiver != NULL);
2824 node->base.location.end = receiver->location.end;
2827 node->receiver = receiver;
2828 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2829 node->opening_loc = arguments->opening_loc;
2830 node->arguments = arguments->arguments;
2831 node->closing_loc = arguments->closing_loc;
2833 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2840static pm_call_node_t *
2841pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2842 pm_assert_value_expression(parser, receiver);
2844 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2846 node->base.location.start = receiver->location.start;
2847 node->base.location.end = pm_arguments_end(arguments);
2849 node->receiver = receiver;
2850 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2851 node->opening_loc = arguments->opening_loc;
2852 node->arguments = arguments->arguments;
2853 node->closing_loc = arguments->closing_loc;
2854 node->block = arguments->block;
2856 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2857 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2860 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2867static pm_call_node_t *
2868pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2869 pm_assert_value_expression(parser, receiver);
2871 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2873 node->base.location.start = operator->start;
2874 node->base.location.end = receiver->location.end;
2876 node->receiver = receiver;
2877 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2879 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2887static pm_call_node_t *
2888pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2889 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2891 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2892 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2894 node->name = pm_parser_constant_id_token(parser, message);
2903pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2905 (node->message_loc.start != NULL) &&
2906 (node->message_loc.end[-1] != '!') &&
2907 (node->message_loc.end[-1] != '?') &&
2908 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2909 (node->opening_loc.start == NULL) &&
2910 (node->arguments == NULL) &&
2911 (node->block == NULL)
2919pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2920 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2922 if (write_constant->length > 0) {
2923 size_t length = write_constant->length - 1;
2925 void *memory = xmalloc(length);
2926 memcpy(memory, write_constant->start, length);
2928 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2930 // We can get here if the message was missing because of a syntax error.
2931 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2938static pm_call_and_write_node_t *
2939pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2940 assert(target->block == NULL);
2941 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2942 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2944 *node = (pm_call_and_write_node_t) {
2946 .type = PM_CALL_AND_WRITE_NODE,
2947 .flags = target->base.flags,
2948 .node_id = PM_NODE_IDENTIFY(parser),
2950 .start = target->base.location.start,
2951 .end = value->location.end
2954 .receiver = target->receiver,
2955 .call_operator_loc = target->call_operator_loc,
2956 .message_loc = target->message_loc,
2958 .write_name = target->name,
2959 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2963 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2965 // Here we're going to free the target, since it is no longer necessary.
2966 // However, we don't want to call `pm_node_destroy` because we want to keep
2967 // around all of its children since we just reused them.
2978pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2979 if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
2980 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2982 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2983 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2984 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2990 if (block != NULL) {
2991 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2999static pm_index_and_write_node_t *
3000pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3001 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3002 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
3004 pm_index_arguments_check(parser, target->arguments, target->block);
3006 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3007 *node = (pm_index_and_write_node_t) {
3009 .type = PM_INDEX_AND_WRITE_NODE,
3010 .flags = target->base.flags,
3011 .node_id = PM_NODE_IDENTIFY(parser),
3013 .start = target->base.location.start,
3014 .end = value->location.end
3017 .receiver = target->receiver,
3018 .call_operator_loc = target->call_operator_loc,
3019 .opening_loc = target->opening_loc,
3020 .arguments = target->arguments,
3021 .closing_loc = target->closing_loc,
3022 .block = (pm_block_argument_node_t *) target->block,
3023 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3027 // Here we're going to free the target, since it is no longer necessary.
3028 // However, we don't want to call `pm_node_destroy` because we want to keep
3029 // around all of its children since we just reused them.
3038static pm_call_operator_write_node_t *
3039pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3040 assert(target->block == NULL);
3041 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3043 *node = (pm_call_operator_write_node_t) {
3045 .type = PM_CALL_OPERATOR_WRITE_NODE,
3046 .flags = target->base.flags,
3047 .node_id = PM_NODE_IDENTIFY(parser),
3049 .start = target->base.location.start,
3050 .end = value->location.end
3053 .receiver = target->receiver,
3054 .call_operator_loc = target->call_operator_loc,
3055 .message_loc = target->message_loc,
3057 .write_name = target->name,
3058 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3059 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3063 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3065 // Here we're going to free the target, since it is no longer necessary.
3066 // However, we don't want to call `pm_node_destroy` because we want to keep
3067 // around all of its children since we just reused them.
3076static pm_index_operator_write_node_t *
3077pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3078 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3080 pm_index_arguments_check(parser, target->arguments, target->block);
3082 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3083 *node = (pm_index_operator_write_node_t) {
3085 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3086 .flags = target->base.flags,
3087 .node_id = PM_NODE_IDENTIFY(parser),
3089 .start = target->base.location.start,
3090 .end = value->location.end
3093 .receiver = target->receiver,
3094 .call_operator_loc = target->call_operator_loc,
3095 .opening_loc = target->opening_loc,
3096 .arguments = target->arguments,
3097 .closing_loc = target->closing_loc,
3098 .block = (pm_block_argument_node_t *) target->block,
3099 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3100 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3104 // Here we're going to free the target, since it is no longer necessary.
3105 // However, we don't want to call `pm_node_destroy` because we want to keep
3106 // around all of its children since we just reused them.
3115static pm_call_or_write_node_t *
3116pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3117 assert(target->block == NULL);
3118 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3119 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3121 *node = (pm_call_or_write_node_t) {
3123 .type = PM_CALL_OR_WRITE_NODE,
3124 .flags = target->base.flags,
3125 .node_id = PM_NODE_IDENTIFY(parser),
3127 .start = target->base.location.start,
3128 .end = value->location.end
3131 .receiver = target->receiver,
3132 .call_operator_loc = target->call_operator_loc,
3133 .message_loc = target->message_loc,
3135 .write_name = target->name,
3136 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3140 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3142 // Here we're going to free the target, since it is no longer necessary.
3143 // However, we don't want to call `pm_node_destroy` because we want to keep
3144 // around all of its children since we just reused them.
3153static pm_index_or_write_node_t *
3154pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3155 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3156 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3158 pm_index_arguments_check(parser, target->arguments, target->block);
3160 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3161 *node = (pm_index_or_write_node_t) {
3163 .type = PM_INDEX_OR_WRITE_NODE,
3164 .flags = target->base.flags,
3165 .node_id = PM_NODE_IDENTIFY(parser),
3167 .start = target->base.location.start,
3168 .end = value->location.end
3171 .receiver = target->receiver,
3172 .call_operator_loc = target->call_operator_loc,
3173 .opening_loc = target->opening_loc,
3174 .arguments = target->arguments,
3175 .closing_loc = target->closing_loc,
3176 .block = (pm_block_argument_node_t *) target->block,
3177 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3181 // Here we're going to free the target, since it is no longer necessary.
3182 // However, we don't want to call `pm_node_destroy` because we want to keep
3183 // around all of its children since we just reused them.
3193static pm_call_target_node_t *
3194pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3195 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3197 *node = (pm_call_target_node_t) {
3199 .type = PM_CALL_TARGET_NODE,
3200 .flags = target->base.flags,
3201 .node_id = PM_NODE_IDENTIFY(parser),
3202 .location = target->base.location
3204 .receiver = target->receiver,
3205 .call_operator_loc = target->call_operator_loc,
3206 .name = target->name,
3207 .message_loc = target->message_loc
3210 // Here we're going to free the target, since it is no longer necessary.
3211 // However, we don't want to call `pm_node_destroy` because we want to keep
3212 // around all of its children since we just reused them.
3222static pm_index_target_node_t *
3223pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3224 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3225 pm_node_flags_t flags = target->base.flags;
3227 pm_index_arguments_check(parser, target->arguments, target->block);
3229 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3230 *node = (pm_index_target_node_t) {
3232 .type = PM_INDEX_TARGET_NODE,
3233 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3234 .node_id = PM_NODE_IDENTIFY(parser),
3235 .location = target->base.location
3237 .receiver = target->receiver,
3238 .opening_loc = target->opening_loc,
3239 .arguments = target->arguments,
3240 .closing_loc = target->closing_loc,
3241 .block = (pm_block_argument_node_t *) target->block,
3244 // Here we're going to free the target, since it is no longer necessary.
3245 // However, we don't want to call `pm_node_destroy` because we want to keep
3246 // around all of its children since we just reused them.
3255static pm_capture_pattern_node_t *
3256pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3257 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3259 *node = (pm_capture_pattern_node_t) {
3261 .type = PM_CAPTURE_PATTERN_NODE,
3262 .node_id = PM_NODE_IDENTIFY(parser),
3264 .start = value->location.start,
3265 .end = target->base.location.end
3270 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3279static pm_case_node_t *
3280pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3281 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3283 *node = (pm_case_node_t) {
3285 .type = PM_CASE_NODE,
3286 .node_id = PM_NODE_IDENTIFY(parser),
3288 .start = case_keyword->start,
3289 .end = end_keyword->end
3292 .predicate = predicate,
3293 .else_clause = NULL,
3294 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3295 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3306pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3307 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3309 pm_node_list_append(&node->conditions, condition);
3310 node->base.location.end = condition->location.end;
3317pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3318 node->else_clause = else_clause;
3319 node->base.location.end = else_clause->base.location.end;
3326pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3327 node->base.location.end = end_keyword->end;
3328 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3334static pm_case_match_node_t *
3335pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3336 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3338 *node = (pm_case_match_node_t) {
3340 .type = PM_CASE_MATCH_NODE,
3341 .node_id = PM_NODE_IDENTIFY(parser),
3343 .start = case_keyword->start,
3344 .end = end_keyword->end
3347 .predicate = predicate,
3348 .else_clause = NULL,
3349 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3350 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3361pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3362 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3364 pm_node_list_append(&node->conditions, condition);
3365 node->base.location.end = condition->location.end;
3372pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3373 node->else_clause = else_clause;
3374 node->base.location.end = else_clause->base.location.end;
3381pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3382 node->base.location.end = end_keyword->end;
3383 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3389static pm_class_node_t *
3390pm_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, pm_node_t *constant_path, const pm_token_t *name, const pm_token_t *inheritance_operator, pm_node_t *superclass, pm_node_t *body, const pm_token_t *end_keyword) {
3391 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3393 *node = (pm_class_node_t) {
3395 .type = PM_CLASS_NODE,
3396 .node_id = PM_NODE_IDENTIFY(parser),
3397 .location = { .start = class_keyword->start, .end = end_keyword->end },
3400 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3401 .constant_path = constant_path,
3402 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3403 .superclass = superclass,
3405 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3406 .name = pm_parser_constant_id_token(parser, name)
3415static pm_class_variable_and_write_node_t *
3416pm_class_variable_and_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3417 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3418 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3420 *node = (pm_class_variable_and_write_node_t) {
3422 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3423 .node_id = PM_NODE_IDENTIFY(parser),
3425 .start = target->base.location.start,
3426 .end = value->location.end
3429 .name = target->name,
3430 .name_loc = target->base.location,
3431 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3441static pm_class_variable_operator_write_node_t *
3442pm_class_variable_operator_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3443 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3445 *node = (pm_class_variable_operator_write_node_t) {
3447 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3448 .node_id = PM_NODE_IDENTIFY(parser),
3450 .start = target->base.location.start,
3451 .end = value->location.end
3454 .name = target->name,
3455 .name_loc = target->base.location,
3456 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3458 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3467static pm_class_variable_or_write_node_t *
3468pm_class_variable_or_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3469 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3470 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3472 *node = (pm_class_variable_or_write_node_t) {
3474 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3475 .node_id = PM_NODE_IDENTIFY(parser),
3477 .start = target->base.location.start,
3478 .end = value->location.end
3481 .name = target->name,
3482 .name_loc = target->base.location,
3483 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3493static pm_class_variable_read_node_t *
3494pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3495 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3496 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3498 *node = (pm_class_variable_read_node_t) {
3500 .type = PM_CLASS_VARIABLE_READ_NODE,
3501 .node_id = PM_NODE_IDENTIFY(parser),
3502 .location = PM_LOCATION_TOKEN_VALUE(token)
3504 .name = pm_parser_constant_id_token(parser, token)
3516static inline pm_node_flags_t
3517pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3518 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3527static pm_class_variable_write_node_t *
3528pm_class_variable_write_node_create(pm_parser_t *parser, pm_class_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
3529 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3531 *node = (pm_class_variable_write_node_t) {
3533 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3534 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3535 .node_id = PM_NODE_IDENTIFY(parser),
3537 .start = read_node->base.location.start,
3538 .end = value->location.end
3541 .name = read_node->name,
3542 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3543 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3553static pm_constant_path_and_write_node_t *
3554pm_constant_path_and_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3555 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3556 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3558 *node = (pm_constant_path_and_write_node_t) {
3560 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3561 .node_id = PM_NODE_IDENTIFY(parser),
3563 .start = target->base.location.start,
3564 .end = value->location.end
3568 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3578static pm_constant_path_operator_write_node_t *
3579pm_constant_path_operator_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3580 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3582 *node = (pm_constant_path_operator_write_node_t) {
3584 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3585 .node_id = PM_NODE_IDENTIFY(parser),
3587 .start = target->base.location.start,
3588 .end = value->location.end
3592 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3594 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3603static pm_constant_path_or_write_node_t *
3604pm_constant_path_or_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3605 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3606 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3608 *node = (pm_constant_path_or_write_node_t) {
3610 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3611 .node_id = PM_NODE_IDENTIFY(parser),
3613 .start = target->base.location.start,
3614 .end = value->location.end
3618 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3628static pm_constant_path_node_t *
3629pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3630 pm_assert_value_expression(parser, parent);
3631 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3633 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3634 if (name_token->type == PM_TOKEN_CONSTANT) {
3635 name = pm_parser_constant_id_token(parser, name_token);
3638 *node = (pm_constant_path_node_t) {
3640 .type = PM_CONSTANT_PATH_NODE,
3641 .node_id = PM_NODE_IDENTIFY(parser),
3643 .start = parent == NULL ? delimiter->start : parent->location.start,
3644 .end = name_token->end
3649 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3650 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3659static pm_constant_path_write_node_t *
3660pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3661 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3663 *node = (pm_constant_path_write_node_t) {
3665 .type = PM_CONSTANT_PATH_WRITE_NODE,
3666 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3667 .node_id = PM_NODE_IDENTIFY(parser),
3669 .start = target->base.location.start,
3670 .end = value->location.end
3674 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3684static pm_constant_and_write_node_t *
3685pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3686 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3687 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3689 *node = (pm_constant_and_write_node_t) {
3691 .type = PM_CONSTANT_AND_WRITE_NODE,
3692 .node_id = PM_NODE_IDENTIFY(parser),
3694 .start = target->base.location.start,
3695 .end = value->location.end
3698 .name = target->name,
3699 .name_loc = target->base.location,
3700 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3710static pm_constant_operator_write_node_t *
3711pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3712 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3714 *node = (pm_constant_operator_write_node_t) {
3716 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3717 .node_id = PM_NODE_IDENTIFY(parser),
3719 .start = target->base.location.start,
3720 .end = value->location.end
3723 .name = target->name,
3724 .name_loc = target->base.location,
3725 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3727 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3736static pm_constant_or_write_node_t *
3737pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3738 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3739 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3741 *node = (pm_constant_or_write_node_t) {
3743 .type = PM_CONSTANT_OR_WRITE_NODE,
3744 .node_id = PM_NODE_IDENTIFY(parser),
3746 .start = target->base.location.start,
3747 .end = value->location.end
3750 .name = target->name,
3751 .name_loc = target->base.location,
3752 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3762static pm_constant_read_node_t *
3763pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3764 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3765 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3767 *node = (pm_constant_read_node_t) {
3769 .type = PM_CONSTANT_READ_NODE,
3770 .node_id = PM_NODE_IDENTIFY(parser),
3771 .location = PM_LOCATION_TOKEN_VALUE(name)
3773 .name = pm_parser_constant_id_token(parser, name)
3782static pm_constant_write_node_t *
3783pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3784 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3786 *node = (pm_constant_write_node_t) {
3788 .type = PM_CONSTANT_WRITE_NODE,
3789 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3790 .node_id = PM_NODE_IDENTIFY(parser),
3792 .start = target->base.location.start,
3793 .end = value->location.end
3796 .name = target->name,
3797 .name_loc = target->base.location,
3798 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3809pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3810 switch (PM_NODE_TYPE(node)) {
3811 case PM_BEGIN_NODE: {
3812 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3813 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3816 case PM_PARENTHESES_NODE: {
3817 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3818 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3821 case PM_STATEMENTS_NODE: {
3822 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3823 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3828 case PM_IMAGINARY_NODE:
3829 case PM_INTEGER_NODE:
3830 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3831 case PM_INTERPOLATED_STRING_NODE:
3832 case PM_INTERPOLATED_SYMBOL_NODE:
3833 case PM_INTERPOLATED_X_STRING_NODE:
3834 case PM_RATIONAL_NODE:
3835 case PM_REGULAR_EXPRESSION_NODE:
3836 case PM_SOURCE_ENCODING_NODE:
3837 case PM_SOURCE_FILE_NODE:
3838 case PM_SOURCE_LINE_NODE:
3839 case PM_STRING_NODE:
3840 case PM_SYMBOL_NODE:
3841 case PM_X_STRING_NODE:
3842 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3852static pm_def_node_t *
3854 pm_parser_t *parser,
3855 pm_constant_id_t name,
3856 const pm_token_t *name_loc,
3857 pm_node_t *receiver,
3858 pm_parameters_node_t *parameters,
3860 pm_constant_id_list_t *locals,
3861 const pm_token_t *def_keyword,
3862 const pm_token_t *operator,
3863 const pm_token_t *lparen,
3864 const pm_token_t *rparen,
3865 const pm_token_t *equal,
3866 const pm_token_t *end_keyword
3868 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3871 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3872 end = body->location.end;
3874 end = end_keyword->end;
3877 if (receiver != NULL) {
3878 pm_def_node_receiver_check(parser, receiver);
3881 *node = (pm_def_node_t) {
3883 .type = PM_DEF_NODE,
3884 .node_id = PM_NODE_IDENTIFY(parser),
3885 .location = { .start = def_keyword->start, .end = end },
3888 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3889 .receiver = receiver,
3890 .parameters = parameters,
3893 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3894 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3895 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3896 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3897 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3898 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3907static pm_defined_node_t *
3908pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_location_t *keyword_loc) {
3909 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3911 *node = (pm_defined_node_t) {
3913 .type = PM_DEFINED_NODE,
3914 .node_id = PM_NODE_IDENTIFY(parser),
3916 .start = keyword_loc->start,
3917 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3920 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3922 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3923 .keyword_loc = *keyword_loc
3932static pm_else_node_t *
3933pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3934 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3935 const uint8_t *end = NULL;
3936 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3937 end = statements->base.location.end;
3939 end = end_keyword->end;
3942 *node = (pm_else_node_t) {
3944 .type = PM_ELSE_NODE,
3945 .node_id = PM_NODE_IDENTIFY(parser),
3947 .start = else_keyword->start,
3951 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3952 .statements = statements,
3953 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3962static pm_embedded_statements_node_t *
3963pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3964 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3966 *node = (pm_embedded_statements_node_t) {
3968 .type = PM_EMBEDDED_STATEMENTS_NODE,
3969 .node_id = PM_NODE_IDENTIFY(parser),
3971 .start = opening->start,
3975 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3976 .statements = statements,
3977 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3986static pm_embedded_variable_node_t *
3987pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3988 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3990 *node = (pm_embedded_variable_node_t) {
3992 .type = PM_EMBEDDED_VARIABLE_NODE,
3993 .node_id = PM_NODE_IDENTIFY(parser),
3995 .start = operator->start,
3996 .end = variable->location.end
3999 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4000 .variable = variable
4009static pm_ensure_node_t *
4010pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4011 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4013 *node = (pm_ensure_node_t) {
4015 .type = PM_ENSURE_NODE,
4016 .node_id = PM_NODE_IDENTIFY(parser),
4018 .start = ensure_keyword->start,
4019 .end = end_keyword->end
4022 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4023 .statements = statements,
4024 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4033static pm_false_node_t *
4034pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4035 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4036 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4038 *node = (pm_false_node_t) {{
4039 .type = PM_FALSE_NODE,
4040 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4041 .node_id = PM_NODE_IDENTIFY(parser),
4042 .location = PM_LOCATION_TOKEN_VALUE(token)
4052static pm_find_pattern_node_t *
4053pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4054 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4056 pm_node_t *left = nodes->nodes[0];
4057 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4058 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4062 if (nodes->size == 1) {
4063 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4065 right = nodes->nodes[nodes->size - 1];
4066 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4069#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4070 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4071 // The resulting AST will anyway be ignored, but this file still needs to compile.
4072 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4074 pm_node_t *right_splat_node = right;
4076 *node = (pm_find_pattern_node_t) {
4078 .type = PM_FIND_PATTERN_NODE,
4079 .node_id = PM_NODE_IDENTIFY(parser),
4081 .start = left->location.start,
4082 .end = right->location.end,
4086 .left = left_splat_node,
4087 .right = right_splat_node,
4089 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4090 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4093 // For now we're going to just copy over each pointer manually. This could be
4094 // much more efficient, as we could instead resize the node list to only point
4096 for (size_t index = 1; index < nodes->size - 1; index++) {
4097 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4108pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4109 ptrdiff_t diff = token->end - token->start;
4110 if (diff <= 0) return 0.0;
4112 // First, get a buffer of the content.
4113 size_t length = (size_t) diff;
4114 char *buffer = xmalloc(sizeof(char) * (length + 1));
4115 memcpy((void *) buffer, token->start, length);
4117 // Next, determine if we need to replace the decimal point because of
4118 // locale-specific options, and then normalize them if we have to.
4119 char decimal_point = *localeconv()->decimal_point;
4120 if (decimal_point != '.') {
4121 for (size_t index = 0; index < length; index++) {
4122 if (buffer[index] == '.') buffer[index] = decimal_point;
4126 // Next, handle underscores by removing them from the buffer.
4127 for (size_t index = 0; index < length; index++) {
4128 if (buffer[index] == '_') {
4129 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4134 // Null-terminate the buffer so that strtod cannot read off the end.
4135 buffer[length] = '\0';
4137 // Now, call strtod to parse the value. Note that CRuby has their own
4138 // version of strtod which avoids locales. We're okay using the locale-aware
4139 // version because we've already validated through the parser that the token
4140 // is in a valid format.
4143 double value = strtod(buffer, &eptr);
4145 // This should never happen, because we've already checked that the token
4146 // is in a valid format. However it's good to be safe.
4147 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4148 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4149 xfree((void *) buffer);
4153 // If errno is set, then it should only be ERANGE. At this point we need to
4154 // check if it's infinity (it should be).
4155 if (errno == ERANGE && PRISM_ISINF(value)) {
4157 const char *ellipsis;
4163 warn_width = (int) length;
4167 pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
4168 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4171 // Finally we can free the buffer and return the value.
4172 xfree((void *) buffer);
4179static pm_float_node_t *
4180pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4181 assert(token->type == PM_TOKEN_FLOAT);
4182 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4184 *node = (pm_float_node_t) {
4186 .type = PM_FLOAT_NODE,
4187 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4188 .node_id = PM_NODE_IDENTIFY(parser),
4189 .location = PM_LOCATION_TOKEN_VALUE(token)
4191 .value = pm_double_parse(parser, token)
4200static pm_imaginary_node_t *
4201pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4202 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4204 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4205 *node = (pm_imaginary_node_t) {
4207 .type = PM_IMAGINARY_NODE,
4208 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4209 .node_id = PM_NODE_IDENTIFY(parser),
4210 .location = PM_LOCATION_TOKEN_VALUE(token)
4212 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4213 .type = PM_TOKEN_FLOAT,
4214 .start = token->start,
4215 .end = token->end - 1
4225static pm_rational_node_t *
4226pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4227 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4229 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4230 *node = (pm_rational_node_t) {
4232 .type = PM_RATIONAL_NODE,
4233 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4234 .node_id = PM_NODE_IDENTIFY(parser),
4235 .location = PM_LOCATION_TOKEN_VALUE(token)
4238 .denominator = { 0 }
4241 const uint8_t *start = token->start;
4242 const uint8_t *end = token->end - 1; // r
4244 while (start < end && *start == '0') start++; // 0.1 -> .1
4245 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4247 size_t length = (size_t) (end - start);
4249 node->denominator.value = 1;
4253 const uint8_t *point = memchr(start, '.', length);
4254 assert(point && "should have a decimal point");
4256 uint8_t *digits = xmalloc(length);
4257 if (digits == NULL) {
4258 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4262 memcpy(digits, start, (unsigned long) (point - start));
4263 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4264 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4267 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4268 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4271 pm_integers_reduce(&node->numerator, &node->denominator);
4279static pm_imaginary_node_t *
4280pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4281 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4283 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4284 *node = (pm_imaginary_node_t) {
4286 .type = PM_IMAGINARY_NODE,
4287 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4288 .node_id = PM_NODE_IDENTIFY(parser),
4289 .location = PM_LOCATION_TOKEN_VALUE(token)
4291 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4292 .type = PM_TOKEN_FLOAT_RATIONAL,
4293 .start = token->start,
4294 .end = token->end - 1
4304static pm_for_node_t *
4306 pm_parser_t *parser,
4308 pm_node_t *collection,
4309 pm_statements_node_t *statements,
4310 const pm_token_t *for_keyword,
4311 const pm_token_t *in_keyword,
4312 const pm_token_t *do_keyword,
4313 const pm_token_t *end_keyword
4315 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4317 *node = (pm_for_node_t) {
4319 .type = PM_FOR_NODE,
4320 .node_id = PM_NODE_IDENTIFY(parser),
4322 .start = for_keyword->start,
4323 .end = end_keyword->end
4327 .collection = collection,
4328 .statements = statements,
4329 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4330 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4331 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4332 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4341static pm_forwarding_arguments_node_t *
4342pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4343 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4344 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4346 *node = (pm_forwarding_arguments_node_t) {{
4347 .type = PM_FORWARDING_ARGUMENTS_NODE,
4348 .node_id = PM_NODE_IDENTIFY(parser),
4349 .location = PM_LOCATION_TOKEN_VALUE(token)
4358static pm_forwarding_parameter_node_t *
4359pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4360 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4361 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4363 *node = (pm_forwarding_parameter_node_t) {{
4364 .type = PM_FORWARDING_PARAMETER_NODE,
4365 .node_id = PM_NODE_IDENTIFY(parser),
4366 .location = PM_LOCATION_TOKEN_VALUE(token)
4375static pm_forwarding_super_node_t *
4376pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4377 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4378 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4379 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4381 pm_block_node_t *block = NULL;
4382 if (arguments->block != NULL) {
4383 block = (pm_block_node_t *) arguments->block;
4386 *node = (pm_forwarding_super_node_t) {
4388 .type = PM_FORWARDING_SUPER_NODE,
4389 .node_id = PM_NODE_IDENTIFY(parser),
4391 .start = token->start,
4392 .end = block != NULL ? block->base.location.end : token->end
4405static pm_hash_pattern_node_t *
4406pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4407 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4409 *node = (pm_hash_pattern_node_t) {
4411 .type = PM_HASH_PATTERN_NODE,
4412 .node_id = PM_NODE_IDENTIFY(parser),
4414 .start = opening->start,
4419 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4420 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4431static pm_hash_pattern_node_t *
4432pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4433 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4435 const uint8_t *start;
4438 if (elements->size > 0) {
4440 start = elements->nodes[0]->location.start;
4441 end = rest->location.end;
4443 start = elements->nodes[0]->location.start;
4444 end = elements->nodes[elements->size - 1]->location.end;
4447 assert(rest != NULL);
4448 start = rest->location.start;
4449 end = rest->location.end;
4452 *node = (pm_hash_pattern_node_t) {
4454 .type = PM_HASH_PATTERN_NODE,
4455 .node_id = PM_NODE_IDENTIFY(parser),
4464 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4465 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4469 PM_NODE_LIST_FOREACH(elements, index, element) {
4470 pm_node_list_append(&node->elements, element);
4479static pm_constant_id_t
4480pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4481 switch (PM_NODE_TYPE(target)) {
4482 case PM_GLOBAL_VARIABLE_READ_NODE:
4483 return ((pm_global_variable_read_node_t *) target)->name;
4484 case PM_BACK_REFERENCE_READ_NODE:
4485 return ((pm_back_reference_read_node_t *) target)->name;
4486 case PM_NUMBERED_REFERENCE_READ_NODE:
4487 // This will only ever happen in the event of a syntax error, but we
4488 // still need to provide something for the node.
4489 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4491 assert(false && "unreachable");
4492 return (pm_constant_id_t) -1;
4499static pm_global_variable_and_write_node_t *
4500pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4501 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4502 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4504 *node = (pm_global_variable_and_write_node_t) {
4506 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4507 .node_id = PM_NODE_IDENTIFY(parser),
4509 .start = target->location.start,
4510 .end = value->location.end
4513 .name = pm_global_variable_write_name(parser, target),
4514 .name_loc = target->location,
4515 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4525static pm_global_variable_operator_write_node_t *
4526pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4527 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4529 *node = (pm_global_variable_operator_write_node_t) {
4531 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4532 .node_id = PM_NODE_IDENTIFY(parser),
4534 .start = target->location.start,
4535 .end = value->location.end
4538 .name = pm_global_variable_write_name(parser, target),
4539 .name_loc = target->location,
4540 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4542 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4551static pm_global_variable_or_write_node_t *
4552pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4553 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4554 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4556 *node = (pm_global_variable_or_write_node_t) {
4558 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4559 .node_id = PM_NODE_IDENTIFY(parser),
4561 .start = target->location.start,
4562 .end = value->location.end
4565 .name = pm_global_variable_write_name(parser, target),
4566 .name_loc = target->location,
4567 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4577static pm_global_variable_read_node_t *
4578pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4579 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4581 *node = (pm_global_variable_read_node_t) {
4583 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4584 .node_id = PM_NODE_IDENTIFY(parser),
4585 .location = PM_LOCATION_TOKEN_VALUE(name),
4587 .name = pm_parser_constant_id_token(parser, name)
4596static pm_global_variable_read_node_t *
4597pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4598 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4600 *node = (pm_global_variable_read_node_t) {
4602 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4603 .node_id = PM_NODE_IDENTIFY(parser),
4604 .location = PM_LOCATION_NULL_VALUE(parser)
4615static pm_global_variable_write_node_t *
4616pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4617 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4619 *node = (pm_global_variable_write_node_t) {
4621 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4622 .node_id = PM_NODE_IDENTIFY(parser),
4623 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4625 .start = target->location.start,
4626 .end = value->location.end
4629 .name = pm_global_variable_write_name(parser, target),
4630 .name_loc = PM_LOCATION_NODE_VALUE(target),
4631 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4641static pm_global_variable_write_node_t *
4642pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4643 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4645 *node = (pm_global_variable_write_node_t) {
4647 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4648 .node_id = PM_NODE_IDENTIFY(parser),
4649 .location = PM_LOCATION_NULL_VALUE(parser)
4652 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4653 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4663static pm_hash_node_t *
4664pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4665 assert(opening != NULL);
4666 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4668 *node = (pm_hash_node_t) {
4670 .type = PM_HASH_NODE,
4671 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4672 .node_id = PM_NODE_IDENTIFY(parser),
4673 .location = PM_LOCATION_TOKEN_VALUE(opening)
4675 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4676 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4687pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4688 pm_node_list_append(&hash->elements, element);
4690 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4691 if (static_literal) {
4692 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4693 static_literal = !PM_NODE_TYPE_P(assoc->key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_HASH_NODE) && !PM_NODE_TYPE_P(assoc->key, PM_RANGE_NODE);
4694 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4695 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4698 if (!static_literal) {
4699 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4704pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4705 hash->base.location.end = token->end;
4706 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4712static pm_if_node_t *
4713pm_if_node_create(pm_parser_t *parser,
4714 const pm_token_t *if_keyword,
4715 pm_node_t *predicate,
4716 const pm_token_t *then_keyword,
4717 pm_statements_node_t *statements,
4718 pm_node_t *subsequent,
4719 const pm_token_t *end_keyword
4721 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4722 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4725 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4726 end = end_keyword->end;
4727 } else if (subsequent != NULL) {
4728 end = subsequent->location.end;
4729 } else if (pm_statements_node_body_length(statements) != 0) {
4730 end = statements->base.location.end;
4732 end = predicate->location.end;
4735 *node = (pm_if_node_t) {
4738 .flags = PM_NODE_FLAG_NEWLINE,
4739 .node_id = PM_NODE_IDENTIFY(parser),
4741 .start = if_keyword->start,
4745 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4746 .predicate = predicate,
4747 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4748 .statements = statements,
4749 .subsequent = subsequent,
4750 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4759static pm_if_node_t *
4760pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4761 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4762 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4764 pm_statements_node_t *statements = pm_statements_node_create(parser);
4765 pm_statements_node_body_append(parser, statements, statement, true);
4767 *node = (pm_if_node_t) {
4770 .flags = PM_NODE_FLAG_NEWLINE,
4771 .node_id = PM_NODE_IDENTIFY(parser),
4773 .start = statement->location.start,
4774 .end = predicate->location.end
4777 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4778 .predicate = predicate,
4779 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4780 .statements = statements,
4782 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4791static pm_if_node_t *
4792pm_if_node_ternary_create(pm_parser_t *parser, pm_node_t *predicate, const pm_token_t *qmark, pm_node_t *true_expression, const pm_token_t *colon, pm_node_t *false_expression) {
4793 pm_assert_value_expression(parser, predicate);
4794 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4796 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4797 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4799 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4800 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4802 pm_token_t end_keyword = not_provided(parser);
4803 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4805 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4807 *node = (pm_if_node_t) {
4810 .flags = PM_NODE_FLAG_NEWLINE,
4811 .node_id = PM_NODE_IDENTIFY(parser),
4813 .start = predicate->location.start,
4814 .end = false_expression->location.end,
4817 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4818 .predicate = predicate,
4819 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4820 .statements = if_statements,
4821 .subsequent = (pm_node_t *) else_node,
4822 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4830pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4831 node->base.location.end = keyword->end;
4832 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4836pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4837 node->base.location.end = keyword->end;
4838 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4844static pm_implicit_node_t *
4845pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4846 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4848 *node = (pm_implicit_node_t) {
4850 .type = PM_IMPLICIT_NODE,
4851 .node_id = PM_NODE_IDENTIFY(parser),
4852 .location = value->location
4863static pm_implicit_rest_node_t *
4864pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4865 assert(token->type == PM_TOKEN_COMMA);
4867 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4869 *node = (pm_implicit_rest_node_t) {
4871 .type = PM_IMPLICIT_REST_NODE,
4872 .node_id = PM_NODE_IDENTIFY(parser),
4873 .location = PM_LOCATION_TOKEN_VALUE(token)
4883static pm_integer_node_t *
4884pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4885 assert(token->type == PM_TOKEN_INTEGER);
4886 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4888 *node = (pm_integer_node_t) {
4890 .type = PM_INTEGER_NODE,
4891 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4892 .node_id = PM_NODE_IDENTIFY(parser),
4893 .location = PM_LOCATION_TOKEN_VALUE(token)
4898 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4900 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4901 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4902 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4903 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4904 default: assert(false && "unreachable"); break;
4907 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4915static pm_imaginary_node_t *
4916pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4917 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4919 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4920 *node = (pm_imaginary_node_t) {
4922 .type = PM_IMAGINARY_NODE,
4923 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4924 .node_id = PM_NODE_IDENTIFY(parser),
4925 .location = PM_LOCATION_TOKEN_VALUE(token)
4927 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4928 .type = PM_TOKEN_INTEGER,
4929 .start = token->start,
4930 .end = token->end - 1
4941static pm_rational_node_t *
4942pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4943 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4945 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4946 *node = (pm_rational_node_t) {
4948 .type = PM_RATIONAL_NODE,
4949 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4950 .node_id = PM_NODE_IDENTIFY(parser),
4951 .location = PM_LOCATION_TOKEN_VALUE(token)
4954 .denominator = { .value = 1, 0 }
4957 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4959 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4960 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4961 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4962 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4963 default: assert(false && "unreachable"); break;
4966 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4975static pm_imaginary_node_t *
4976pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4977 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4979 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4980 *node = (pm_imaginary_node_t) {
4982 .type = PM_IMAGINARY_NODE,
4983 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4984 .node_id = PM_NODE_IDENTIFY(parser),
4985 .location = PM_LOCATION_TOKEN_VALUE(token)
4987 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4988 .type = PM_TOKEN_INTEGER_RATIONAL,
4989 .start = token->start,
4990 .end = token->end - 1
5000static pm_in_node_t *
5001pm_in_node_create(pm_parser_t *parser, pm_node_t *pattern, pm_statements_node_t *statements, const pm_token_t *in_keyword, const pm_token_t *then_keyword) {
5002 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
5005 if (statements != NULL) {
5006 end = statements->base.location.end;
5007 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
5008 end = then_keyword->end;
5010 end = pattern->location.end;
5013 *node = (pm_in_node_t) {
5016 .node_id = PM_NODE_IDENTIFY(parser),
5018 .start = in_keyword->start,
5023 .statements = statements,
5024 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5025 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5034static pm_instance_variable_and_write_node_t *
5035pm_instance_variable_and_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5036 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5037 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5039 *node = (pm_instance_variable_and_write_node_t) {
5041 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5042 .node_id = PM_NODE_IDENTIFY(parser),
5044 .start = target->base.location.start,
5045 .end = value->location.end
5048 .name = target->name,
5049 .name_loc = target->base.location,
5050 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5060static pm_instance_variable_operator_write_node_t *
5061pm_instance_variable_operator_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5062 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5064 *node = (pm_instance_variable_operator_write_node_t) {
5066 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5067 .node_id = PM_NODE_IDENTIFY(parser),
5069 .start = target->base.location.start,
5070 .end = value->location.end
5073 .name = target->name,
5074 .name_loc = target->base.location,
5075 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5077 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5086static pm_instance_variable_or_write_node_t *
5087pm_instance_variable_or_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5088 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5089 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5091 *node = (pm_instance_variable_or_write_node_t) {
5093 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5094 .node_id = PM_NODE_IDENTIFY(parser),
5096 .start = target->base.location.start,
5097 .end = value->location.end
5100 .name = target->name,
5101 .name_loc = target->base.location,
5102 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5112static pm_instance_variable_read_node_t *
5113pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5114 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5115 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5117 *node = (pm_instance_variable_read_node_t) {
5119 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5120 .node_id = PM_NODE_IDENTIFY(parser),
5121 .location = PM_LOCATION_TOKEN_VALUE(token)
5123 .name = pm_parser_constant_id_token(parser, token)
5133static pm_instance_variable_write_node_t *
5134pm_instance_variable_write_node_create(pm_parser_t *parser, pm_instance_variable_read_node_t *read_node, pm_token_t *operator, pm_node_t *value) {
5135 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5136 *node = (pm_instance_variable_write_node_t) {
5138 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5139 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5140 .node_id = PM_NODE_IDENTIFY(parser),
5142 .start = read_node->base.location.start,
5143 .end = value->location.end
5146 .name = read_node->name,
5147 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5148 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5161pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5162 switch (PM_NODE_TYPE(part)) {
5163 case PM_STRING_NODE:
5164 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5166 case PM_EMBEDDED_STATEMENTS_NODE: {
5167 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5168 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5170 if (embedded == NULL) {
5171 // If there are no statements or more than one statement, then
5172 // we lose the static literal flag.
5173 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5174 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5175 // If the embedded statement is a string, then we can keep the
5176 // static literal flag and mark the string as frozen.
5177 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5178 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5179 // If the embedded statement is an interpolated string and it's
5180 // a static literal, then we can keep the static literal flag.
5182 // Otherwise we lose the static literal flag.
5183 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5188 case PM_EMBEDDED_VARIABLE_NODE:
5189 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5192 assert(false && "unexpected node type");
5196 pm_node_list_append(parts, part);
5202static pm_interpolated_regular_expression_node_t *
5203pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5204 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5206 *node = (pm_interpolated_regular_expression_node_t) {
5208 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5209 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5210 .node_id = PM_NODE_IDENTIFY(parser),
5212 .start = opening->start,
5216 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5217 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5225pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5226 if (node->base.location.start > part->location.start) {
5227 node->base.location.start = part->location.start;
5229 if (node->base.location.end < part->location.end) {
5230 node->base.location.end = part->location.end;
5233 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5237pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5238 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5239 node->base.location.end = closing->end;
5240 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5267pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5268#define CLEAR_FLAGS(node) \
5269 node->base.flags = (pm_node_flags_t) (node->base.flags & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
5271#define MUTABLE_FLAGS(node) \
5272 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5274 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5275 node->base.location.start = part->location.start;
5278 node->base.location.end = MAX(node->base.location.end, part->location.end);
5280 switch (PM_NODE_TYPE(part)) {
5281 case PM_STRING_NODE:
5282 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5284 case PM_INTERPOLATED_STRING_NODE:
5285 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5286 // If the string that we're concatenating is a static literal,
5287 // then we can keep the static literal flag for this string.
5289 // Otherwise, we lose the static literal flag here and we should
5290 // also clear the mutability flags.
5294 case PM_EMBEDDED_STATEMENTS_NODE: {
5295 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5296 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5298 if (embedded == NULL) {
5299 // If we're embedding multiple statements or no statements, then
5300 // the string is not longer a static literal.
5302 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5303 // If the embedded statement is a string, then we can make that
5304 // string as frozen and static literal, and not touch the static
5305 // literal status of this string.
5306 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5308 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5309 MUTABLE_FLAGS(node);
5311 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5312 // If the embedded statement is an interpolated string, but that
5313 // string is marked as static literal, then we can keep our
5314 // static literal status for this string.
5315 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5316 MUTABLE_FLAGS(node);
5319 // In all other cases, we lose the static literal flag here and
5326 case PM_EMBEDDED_VARIABLE_NODE:
5327 // Embedded variables clear static literal, which means we also
5328 // should clear the mutability flags.
5331 case PM_X_STRING_NODE:
5332 case PM_INTERPOLATED_X_STRING_NODE:
5333 // If this is an x string, then this is a syntax error. But we want
5334 // to handle it here so that we don't fail the assertion.
5338 assert(false && "unexpected node type");
5342 pm_node_list_append(&node->parts, part);
5351static pm_interpolated_string_node_t *
5352pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5353 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5354 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5356 switch (parser->frozen_string_literal) {
5357 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5358 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5360 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5361 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5365 *node = (pm_interpolated_string_node_t) {
5367 .type = PM_INTERPOLATED_STRING_NODE,
5369 .node_id = PM_NODE_IDENTIFY(parser),
5371 .start = opening->start,
5372 .end = closing->end,
5375 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5376 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5380 if (parts != NULL) {
5382 PM_NODE_LIST_FOREACH(parts, index, part) {
5383 pm_interpolated_string_node_append(node, part);
5394pm_interpolated_string_node_closing_set(pm_interpolated_string_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;
5400pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5401 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5402 node->base.location.start = part->location.start;
5405 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5406 node->base.location.end = MAX(node->base.location.end, part->location.end);
5410pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5411 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5412 node->base.location.end = closing->end;
5418static pm_interpolated_symbol_node_t *
5419pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5420 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5422 *node = (pm_interpolated_symbol_node_t) {
5424 .type = PM_INTERPOLATED_SYMBOL_NODE,
5425 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5426 .node_id = PM_NODE_IDENTIFY(parser),
5428 .start = opening->start,
5429 .end = closing->end,
5432 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5433 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5437 if (parts != NULL) {
5439 PM_NODE_LIST_FOREACH(parts, index, part) {
5440 pm_interpolated_symbol_node_append(node, part);
5450static pm_interpolated_x_string_node_t *
5451pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5452 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5454 *node = (pm_interpolated_x_string_node_t) {
5456 .type = PM_INTERPOLATED_X_STRING_NODE,
5457 .node_id = PM_NODE_IDENTIFY(parser),
5459 .start = opening->start,
5463 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5464 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5472pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5473 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5474 node->base.location.end = part->location.end;
5478pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5479 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5480 node->base.location.end = closing->end;
5486static pm_it_local_variable_read_node_t *
5487pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5488 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5490 *node = (pm_it_local_variable_read_node_t) {
5492 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5493 .node_id = PM_NODE_IDENTIFY(parser),
5494 .location = PM_LOCATION_TOKEN_VALUE(name)
5504static pm_it_parameters_node_t *
5505pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5506 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5508 *node = (pm_it_parameters_node_t) {
5510 .type = PM_IT_PARAMETERS_NODE,
5511 .node_id = PM_NODE_IDENTIFY(parser),
5513 .start = opening->start,
5525static pm_keyword_hash_node_t *
5526pm_keyword_hash_node_create(pm_parser_t *parser) {
5527 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5529 *node = (pm_keyword_hash_node_t) {
5531 .type = PM_KEYWORD_HASH_NODE,
5532 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5533 .node_id = PM_NODE_IDENTIFY(parser),
5534 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5546pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5547 // If the element being added is not an AssocNode or does not have a symbol
5548 // key, then we want to turn the SYMBOL_KEYS flag off.
5549 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5550 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5553 pm_node_list_append(&hash->elements, element);
5554 if (hash->base.location.start == NULL) {
5555 hash->base.location.start = element->location.start;
5557 hash->base.location.end = element->location.end;
5563static pm_required_keyword_parameter_node_t *
5564pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5565 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5567 *node = (pm_required_keyword_parameter_node_t) {
5569 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5570 .node_id = PM_NODE_IDENTIFY(parser),
5572 .start = name->start,
5576 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5577 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5586static pm_optional_keyword_parameter_node_t *
5587pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5588 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5590 *node = (pm_optional_keyword_parameter_node_t) {
5592 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5593 .node_id = PM_NODE_IDENTIFY(parser),
5595 .start = name->start,
5596 .end = value->location.end
5599 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5600 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5610static pm_keyword_rest_parameter_node_t *
5611pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5612 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5614 *node = (pm_keyword_rest_parameter_node_t) {
5616 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5617 .node_id = PM_NODE_IDENTIFY(parser),
5619 .start = operator->start,
5620 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5623 .name = pm_parser_optional_constant_id_token(parser, name),
5624 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5625 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5634static pm_lambda_node_t *
5635pm_lambda_node_create(
5636 pm_parser_t *parser,
5637 pm_constant_id_list_t *locals,
5638 const pm_token_t *operator,
5639 const pm_token_t *opening,
5640 const pm_token_t *closing,
5641 pm_node_t *parameters,
5644 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5646 *node = (pm_lambda_node_t) {
5648 .type = PM_LAMBDA_NODE,
5649 .node_id = PM_NODE_IDENTIFY(parser),
5651 .start = operator->start,
5656 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5657 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5658 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5659 .parameters = parameters,
5669static pm_local_variable_and_write_node_t *
5670pm_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) {
5671 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5672 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5673 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5675 *node = (pm_local_variable_and_write_node_t) {
5677 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5678 .node_id = PM_NODE_IDENTIFY(parser),
5680 .start = target->location.start,
5681 .end = value->location.end
5684 .name_loc = target->location,
5685 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5697static pm_local_variable_operator_write_node_t *
5698pm_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) {
5699 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5701 *node = (pm_local_variable_operator_write_node_t) {
5703 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5704 .node_id = PM_NODE_IDENTIFY(parser),
5706 .start = target->location.start,
5707 .end = value->location.end
5710 .name_loc = target->location,
5711 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5714 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5724static pm_local_variable_or_write_node_t *
5725pm_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) {
5726 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5727 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5728 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5730 *node = (pm_local_variable_or_write_node_t) {
5732 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5733 .node_id = PM_NODE_IDENTIFY(parser),
5735 .start = target->location.start,
5736 .end = value->location.end
5739 .name_loc = target->location,
5740 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5752static pm_local_variable_read_node_t *
5753pm_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) {
5754 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5756 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5758 *node = (pm_local_variable_read_node_t) {
5760 .type = PM_LOCAL_VARIABLE_READ_NODE,
5761 .node_id = PM_NODE_IDENTIFY(parser),
5762 .location = PM_LOCATION_TOKEN_VALUE(name)
5774static pm_local_variable_read_node_t *
5775pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5776 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5777 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5784static pm_local_variable_read_node_t *
5785pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5786 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5787 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5793static pm_local_variable_write_node_t *
5794pm_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) {
5795 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5797 *node = (pm_local_variable_write_node_t) {
5799 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5800 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5801 .node_id = PM_NODE_IDENTIFY(parser),
5803 .start = name_loc->start,
5804 .end = value->location.end
5810 .name_loc = *name_loc,
5811 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5821pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5822 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5830pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5831 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5839pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5840 if (pm_token_is_numbered_parameter(start, end)) {
5841 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5849static pm_local_variable_target_node_t *
5850pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5851 pm_refute_numbered_parameter(parser, location->start, location->end);
5852 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5854 *node = (pm_local_variable_target_node_t) {
5856 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5857 .node_id = PM_NODE_IDENTIFY(parser),
5858 .location = *location
5870static pm_match_predicate_node_t *
5871pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5872 pm_assert_value_expression(parser, value);
5874 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5876 *node = (pm_match_predicate_node_t) {
5878 .type = PM_MATCH_PREDICATE_NODE,
5879 .node_id = PM_NODE_IDENTIFY(parser),
5881 .start = value->location.start,
5882 .end = pattern->location.end
5887 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5896static pm_match_required_node_t *
5897pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5898 pm_assert_value_expression(parser, value);
5900 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5902 *node = (pm_match_required_node_t) {
5904 .type = PM_MATCH_REQUIRED_NODE,
5905 .node_id = PM_NODE_IDENTIFY(parser),
5907 .start = value->location.start,
5908 .end = pattern->location.end
5913 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5922static pm_match_write_node_t *
5923pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5924 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5926 *node = (pm_match_write_node_t) {
5928 .type = PM_MATCH_WRITE_NODE,
5929 .node_id = PM_NODE_IDENTIFY(parser),
5930 .location = call->base.location
5942static pm_module_node_t *
5943pm_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) {
5944 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5946 *node = (pm_module_node_t) {
5948 .type = PM_MODULE_NODE,
5949 .node_id = PM_NODE_IDENTIFY(parser),
5951 .start = module_keyword->start,
5952 .end = end_keyword->end
5955 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5956 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5957 .constant_path = constant_path,
5959 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5960 .name = pm_parser_constant_id_token(parser, name)
5969static pm_multi_target_node_t *
5970pm_multi_target_node_create(pm_parser_t *parser) {
5971 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5973 *node = (pm_multi_target_node_t) {
5975 .type = PM_MULTI_TARGET_NODE,
5976 .node_id = PM_NODE_IDENTIFY(parser),
5977 .location = { .start = NULL, .end = NULL }
5982 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5983 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5993pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5994 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5995 if (node->rest == NULL) {
5996 node->rest = target;
5998 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5999 pm_node_list_append(&node->rights, target);
6001 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
6002 if (node->rest == NULL) {
6003 node->rest = target;
6005 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
6006 pm_node_list_append(&node->rights, target);
6008 } else if (node->rest == NULL) {
6009 pm_node_list_append(&node->lefts, target);
6011 pm_node_list_append(&node->rights, target);
6014 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
6015 node->base.location.start = target->location.start;
6018 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6019 node->base.location.end = target->location.end;
6027pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6028 node->base.location.start = lparen->start;
6029 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6036pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6037 node->base.location.end = rparen->end;
6038 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6044static pm_multi_write_node_t *
6045pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6046 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6048 *node = (pm_multi_write_node_t) {
6050 .type = PM_MULTI_WRITE_NODE,
6051 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6052 .node_id = PM_NODE_IDENTIFY(parser),
6054 .start = target->base.location.start,
6055 .end = value->location.end
6058 .lefts = target->lefts,
6059 .rest = target->rest,
6060 .rights = target->rights,
6061 .lparen_loc = target->lparen_loc,
6062 .rparen_loc = target->rparen_loc,
6063 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6067 // Explicitly do not call pm_node_destroy here because we want to keep
6068 // around all of the information within the MultiWriteNode node.
6077static pm_next_node_t *
6078pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6079 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6080 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6082 *node = (pm_next_node_t) {
6084 .type = PM_NEXT_NODE,
6085 .node_id = PM_NODE_IDENTIFY(parser),
6087 .start = keyword->start,
6088 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6091 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6092 .arguments = arguments
6101static pm_nil_node_t *
6102pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6103 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6104 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6106 *node = (pm_nil_node_t) {{
6107 .type = PM_NIL_NODE,
6108 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6109 .node_id = PM_NODE_IDENTIFY(parser),
6110 .location = PM_LOCATION_TOKEN_VALUE(token)
6119static pm_no_keywords_parameter_node_t *
6120pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6121 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6122 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6123 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6125 *node = (pm_no_keywords_parameter_node_t) {
6127 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6128 .node_id = PM_NODE_IDENTIFY(parser),
6130 .start = operator->start,
6134 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6135 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6144static pm_numbered_parameters_node_t *
6145pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6146 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6148 *node = (pm_numbered_parameters_node_t) {
6150 .type = PM_NUMBERED_PARAMETERS_NODE,
6151 .node_id = PM_NODE_IDENTIFY(parser),
6152 .location = *location
6164#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6173pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6174 const uint8_t *start = token->start + 1;
6175 const uint8_t *end = token->end;
6177 ptrdiff_t diff = end - start;
6179#if PTRDIFF_MAX > SIZE_MAX
6180 assert(diff < (ptrdiff_t) SIZE_MAX);
6182 size_t length = (size_t) diff;
6184 char *digits = xcalloc(length + 1, sizeof(char));
6185 memcpy(digits, start, length);
6186 digits[length] = '\0';
6190 unsigned long value = strtoul(digits, &endptr, 10);
6192 if ((digits == endptr) || (*endptr != '\0')) {
6193 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6199 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6200 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6204 return (uint32_t) value;
6212static pm_numbered_reference_read_node_t *
6213pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6214 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6215 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6217 *node = (pm_numbered_reference_read_node_t) {
6219 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6220 .node_id = PM_NODE_IDENTIFY(parser),
6221 .location = PM_LOCATION_TOKEN_VALUE(name),
6223 .number = pm_numbered_reference_read_node_number(parser, name)
6232static pm_optional_parameter_node_t *
6233pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6234 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6236 *node = (pm_optional_parameter_node_t) {
6238 .type = PM_OPTIONAL_PARAMETER_NODE,
6239 .node_id = PM_NODE_IDENTIFY(parser),
6241 .start = name->start,
6242 .end = value->location.end
6245 .name = pm_parser_constant_id_token(parser, name),
6246 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6247 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6257static pm_or_node_t *
6258pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6259 pm_assert_value_expression(parser, left);
6261 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6263 *node = (pm_or_node_t) {
6266 .node_id = PM_NODE_IDENTIFY(parser),
6268 .start = left->location.start,
6269 .end = right->location.end
6274 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6283static pm_parameters_node_t *
6284pm_parameters_node_create(pm_parser_t *parser) {
6285 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6287 *node = (pm_parameters_node_t) {
6289 .type = PM_PARAMETERS_NODE,
6290 .node_id = PM_NODE_IDENTIFY(parser),
6291 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6294 .keyword_rest = NULL,
6309pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6310 if (params->base.location.start == NULL) {
6311 params->base.location.start = param->location.start;
6313 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6316 if (params->base.location.end == NULL) {
6317 params->base.location.end = param->location.end;
6319 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6327pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6328 pm_parameters_node_location_set(params, param);
6329 pm_node_list_append(¶ms->requireds, param);
6336pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6337 pm_parameters_node_location_set(params, (pm_node_t *) param);
6338 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6345pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6346 pm_parameters_node_location_set(params, param);
6347 pm_node_list_append(¶ms->posts, param);
6354pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6355 pm_parameters_node_location_set(params, param);
6356 params->rest = param;
6363pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6364 pm_parameters_node_location_set(params, param);
6365 pm_node_list_append(¶ms->keywords, param);
6372pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6373 assert(params->keyword_rest == NULL);
6374 pm_parameters_node_location_set(params, param);
6375 params->keyword_rest = param;
6382pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6383 assert(params->block == NULL);
6384 pm_parameters_node_location_set(params, (pm_node_t *) param);
6385 params->block = param;
6391static pm_program_node_t *
6392pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6393 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6395 *node = (pm_program_node_t) {
6397 .type = PM_PROGRAM_NODE,
6398 .node_id = PM_NODE_IDENTIFY(parser),
6400 .start = statements == NULL ? parser->start : statements->base.location.start,
6401 .end = statements == NULL ? parser->end : statements->base.location.end
6405 .statements = statements
6414static pm_parentheses_node_t *
6415pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing, pm_node_flags_t flags) {
6416 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6418 *node = (pm_parentheses_node_t) {
6420 .type = PM_PARENTHESES_NODE,
6422 .node_id = PM_NODE_IDENTIFY(parser),
6424 .start = opening->start,
6429 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6430 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6439static pm_pinned_expression_node_t *
6440pm_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) {
6441 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6443 *node = (pm_pinned_expression_node_t) {
6445 .type = PM_PINNED_EXPRESSION_NODE,
6446 .node_id = PM_NODE_IDENTIFY(parser),
6448 .start = operator->start,
6452 .expression = expression,
6453 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6454 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6455 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6464static pm_pinned_variable_node_t *
6465pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6466 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6468 *node = (pm_pinned_variable_node_t) {
6470 .type = PM_PINNED_VARIABLE_NODE,
6471 .node_id = PM_NODE_IDENTIFY(parser),
6473 .start = operator->start,
6474 .end = variable->location.end
6477 .variable = variable,
6478 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6487static pm_post_execution_node_t *
6488pm_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) {
6489 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6491 *node = (pm_post_execution_node_t) {
6493 .type = PM_POST_EXECUTION_NODE,
6494 .node_id = PM_NODE_IDENTIFY(parser),
6496 .start = keyword->start,
6500 .statements = statements,
6501 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6502 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6503 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6512static pm_pre_execution_node_t *
6513pm_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) {
6514 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6516 *node = (pm_pre_execution_node_t) {
6518 .type = PM_PRE_EXECUTION_NODE,
6519 .node_id = PM_NODE_IDENTIFY(parser),
6521 .start = keyword->start,
6525 .statements = statements,
6526 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6527 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6528 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6537static pm_range_node_t *
6538pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6539 pm_assert_value_expression(parser, left);
6540 pm_assert_value_expression(parser, right);
6542 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6543 pm_node_flags_t flags = 0;
6545 // Indicate that this node is an exclusive range if the operator is `...`.
6546 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6547 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6550 // Indicate that this node is a static literal (i.e., can be compiled with
6551 // a putobject in CRuby) if the left and right are implicit nil, explicit
6552 // nil, or integers.
6554 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6555 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6557 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6560 *node = (pm_range_node_t) {
6562 .type = PM_RANGE_NODE,
6564 .node_id = PM_NODE_IDENTIFY(parser),
6566 .start = (left == NULL ? operator->start : left->location.start),
6567 .end = (right == NULL ? operator->end : right->location.end)
6572 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6581static pm_redo_node_t *
6582pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6583 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6584 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6586 *node = (pm_redo_node_t) {{
6587 .type = PM_REDO_NODE,
6588 .node_id = PM_NODE_IDENTIFY(parser),
6589 .location = PM_LOCATION_TOKEN_VALUE(token)
6599static pm_regular_expression_node_t *
6600pm_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) {
6601 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6603 *node = (pm_regular_expression_node_t) {
6605 .type = PM_REGULAR_EXPRESSION_NODE,
6606 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6607 .node_id = PM_NODE_IDENTIFY(parser),
6609 .start = MIN(opening->start, closing->start),
6610 .end = MAX(opening->end, closing->end)
6613 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6614 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6615 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6616 .unescaped = *unescaped
6625static inline pm_regular_expression_node_t *
6626pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6627 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6633static pm_required_parameter_node_t *
6634pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6635 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6637 *node = (pm_required_parameter_node_t) {
6639 .type = PM_REQUIRED_PARAMETER_NODE,
6640 .node_id = PM_NODE_IDENTIFY(parser),
6641 .location = PM_LOCATION_TOKEN_VALUE(token)
6643 .name = pm_parser_constant_id_token(parser, token)
6652static pm_rescue_modifier_node_t *
6653pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6654 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6656 *node = (pm_rescue_modifier_node_t) {
6658 .type = PM_RESCUE_MODIFIER_NODE,
6659 .node_id = PM_NODE_IDENTIFY(parser),
6661 .start = expression->location.start,
6662 .end = rescue_expression->location.end
6665 .expression = expression,
6666 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6667 .rescue_expression = rescue_expression
6676static pm_rescue_node_t *
6677pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6678 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6680 *node = (pm_rescue_node_t) {
6682 .type = PM_RESCUE_NODE,
6683 .node_id = PM_NODE_IDENTIFY(parser),
6684 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6686 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6687 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6688 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6699pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6700 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6707pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6708 node->reference = reference;
6709 node->base.location.end = reference->location.end;
6716pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6717 node->statements = statements;
6718 if (pm_statements_node_body_length(statements) > 0) {
6719 node->base.location.end = statements->base.location.end;
6727pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6728 node->subsequent = subsequent;
6729 node->base.location.end = subsequent->base.location.end;
6736pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6737 pm_node_list_append(&node->exceptions, exception);
6738 node->base.location.end = exception->location.end;
6744static pm_rest_parameter_node_t *
6745pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6746 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6748 *node = (pm_rest_parameter_node_t) {
6750 .type = PM_REST_PARAMETER_NODE,
6751 .node_id = PM_NODE_IDENTIFY(parser),
6753 .start = operator->start,
6754 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6757 .name = pm_parser_optional_constant_id_token(parser, name),
6758 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6759 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6768static pm_retry_node_t *
6769pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6770 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6771 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6773 *node = (pm_retry_node_t) {{
6774 .type = PM_RETRY_NODE,
6775 .node_id = PM_NODE_IDENTIFY(parser),
6776 .location = PM_LOCATION_TOKEN_VALUE(token)
6785static pm_return_node_t *
6786pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6787 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6789 *node = (pm_return_node_t) {
6791 .type = PM_RETURN_NODE,
6792 .node_id = PM_NODE_IDENTIFY(parser),
6794 .start = keyword->start,
6795 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6798 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6799 .arguments = arguments
6808static pm_self_node_t *
6809pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6810 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6811 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6813 *node = (pm_self_node_t) {{
6814 .type = PM_SELF_NODE,
6815 .node_id = PM_NODE_IDENTIFY(parser),
6816 .location = PM_LOCATION_TOKEN_VALUE(token)
6825static pm_shareable_constant_node_t *
6826pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6827 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6829 *node = (pm_shareable_constant_node_t) {
6831 .type = PM_SHAREABLE_CONSTANT_NODE,
6832 .flags = (pm_node_flags_t) value,
6833 .node_id = PM_NODE_IDENTIFY(parser),
6834 .location = PM_LOCATION_NODE_VALUE(write)
6845static pm_singleton_class_node_t *
6846pm_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) {
6847 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6849 *node = (pm_singleton_class_node_t) {
6851 .type = PM_SINGLETON_CLASS_NODE,
6852 .node_id = PM_NODE_IDENTIFY(parser),
6854 .start = class_keyword->start,
6855 .end = end_keyword->end
6859 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6860 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6861 .expression = expression,
6863 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6872static pm_source_encoding_node_t *
6873pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6874 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6875 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6877 *node = (pm_source_encoding_node_t) {{
6878 .type = PM_SOURCE_ENCODING_NODE,
6879 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6880 .node_id = PM_NODE_IDENTIFY(parser),
6881 .location = PM_LOCATION_TOKEN_VALUE(token)
6890static pm_source_file_node_t*
6891pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6892 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6893 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6895 pm_node_flags_t flags = 0;
6897 switch (parser->frozen_string_literal) {
6898 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6899 flags |= PM_STRING_FLAGS_MUTABLE;
6901 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6902 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6906 *node = (pm_source_file_node_t) {
6908 .type = PM_SOURCE_FILE_NODE,
6910 .node_id = PM_NODE_IDENTIFY(parser),
6911 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6913 .filepath = parser->filepath
6922static pm_source_line_node_t *
6923pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6924 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6925 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6927 *node = (pm_source_line_node_t) {{
6928 .type = PM_SOURCE_LINE_NODE,
6929 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6930 .node_id = PM_NODE_IDENTIFY(parser),
6931 .location = PM_LOCATION_TOKEN_VALUE(token)
6940static pm_splat_node_t *
6941pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6942 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6944 *node = (pm_splat_node_t) {
6946 .type = PM_SPLAT_NODE,
6947 .node_id = PM_NODE_IDENTIFY(parser),
6949 .start = operator->start,
6950 .end = (expression == NULL ? operator->end : expression->location.end)
6953 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6954 .expression = expression
6963static pm_statements_node_t *
6964pm_statements_node_create(pm_parser_t *parser) {
6965 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6967 *node = (pm_statements_node_t) {
6969 .type = PM_STATEMENTS_NODE,
6970 .node_id = PM_NODE_IDENTIFY(parser),
6971 .location = PM_LOCATION_NULL_VALUE(parser)
6983pm_statements_node_body_length(pm_statements_node_t *node) {
6984 return node && node->body.size;
6991pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6992 node->base.location = (pm_location_t) { .start = start, .end = end };
7000pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
7001 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
7002 node->base.location.start = statement->location.start;
7005 if (statement->location.end > node->base.location.end) {
7006 node->base.location.end = statement->location.end;
7014pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
7015 pm_statements_node_body_update(node, statement);
7017 if (node->body.size > 0) {
7018 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
7020 switch (PM_NODE_TYPE(previous)) {
7025 case PM_RETURN_NODE:
7026 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7033 pm_node_list_append(&node->body, statement);
7034 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7041pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7042 pm_statements_node_body_update(node, statement);
7043 pm_node_list_prepend(&node->body, statement);
7044 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7050static inline pm_string_node_t *
7051pm_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) {
7052 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7053 pm_node_flags_t flags = 0;
7055 switch (parser->frozen_string_literal) {
7056 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7057 flags = PM_STRING_FLAGS_MUTABLE;
7059 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7060 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7064 *node = (pm_string_node_t) {
7066 .type = PM_STRING_NODE,
7068 .node_id = PM_NODE_IDENTIFY(parser),
7070 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7071 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7074 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7075 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7076 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7077 .unescaped = *string
7086static pm_string_node_t *
7087pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7088 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7095static pm_string_node_t *
7096pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7097 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7098 parser->current_string = PM_STRING_EMPTY;
7105static pm_super_node_t *
7106pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7107 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7108 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7110 const uint8_t *end = pm_arguments_end(arguments);
7112 assert(false && "unreachable");
7115 *node = (pm_super_node_t) {
7117 .type = PM_SUPER_NODE,
7118 .node_id = PM_NODE_IDENTIFY(parser),
7120 .start = keyword->start,
7124 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7125 .lparen_loc = arguments->opening_loc,
7126 .arguments = arguments->arguments,
7127 .rparen_loc = arguments->closing_loc,
7128 .block = arguments->block
7139pm_ascii_only_p(const pm_string_t *contents) {
7140 const size_t length = pm_string_length(contents);
7141 const uint8_t *source = pm_string_source(contents);
7143 for (size_t index = 0; index < length; index++) {
7144 if (source[index] & 0x80) return false;
7154parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7155 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7156 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7159 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7172parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7173 const pm_encoding_t *encoding = parser->encoding;
7175 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7176 size_t width = encoding->char_width(cursor, end - cursor);
7179 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7196static inline pm_node_flags_t
7197parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7198 if (parser->explicit_encoding != NULL) {
7199 // A Symbol may optionally have its encoding explicitly set. This will
7200 // happen if an escape sequence results in a non-ASCII code point.
7201 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7202 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7203 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7204 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7205 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7206 } else if (validate) {
7207 parse_symbol_encoding_validate_other(parser, location, contents);
7209 } else if (pm_ascii_only_p(contents)) {
7210 // Ruby stipulates that all source files must use an ASCII-compatible
7211 // encoding. Thus, all symbols appearing in source are eligible for
7212 // "downgrading" to US-ASCII.
7213 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7214 } else if (validate) {
7215 parse_symbol_encoding_validate_other(parser, location, contents);
7221static pm_node_flags_t
7222parse_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) {
7223 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7224 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7225 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7226 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7228 // There's special validation logic used if a string does not contain any character escape sequences.
7229 if (parser->explicit_encoding == NULL) {
7230 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7231 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7232 // the US-ASCII encoding.
7234 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7237 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7239 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7241 } else if (parser->encoding != modifier_encoding) {
7242 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7244 if (modifier == 'n' && !ascii_only) {
7245 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));
7252 // 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.
7253 bool mixed_encoding = false;
7255 if (mixed_encoding) {
7256 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7257 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7258 // 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.
7259 bool valid_string_in_modifier_encoding = true;
7261 if (!valid_string_in_modifier_encoding) {
7262 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7264 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7265 // 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.
7266 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7267 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));
7271 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7281static pm_node_flags_t
7282parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7283 // 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.
7284 bool valid_unicode_range = true;
7285 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7286 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));
7290 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7291 // to multi-byte characters are allowed.
7292 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7293 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7294 // following error message appearing twice. We do the same for compatibility.
7295 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7306 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7307 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7310 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7311 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7314 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7315 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7318 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7319 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7322 // At this point no encoding modifiers will be present on the regular expression as they would have already
7323 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7324 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7326 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7329 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7330 // or by specifying a modifier.
7332 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7333 if (parser->explicit_encoding != NULL) {
7334 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7335 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7336 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7337 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7348static pm_symbol_node_t *
7349pm_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) {
7350 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7352 *node = (pm_symbol_node_t) {
7354 .type = PM_SYMBOL_NODE,
7355 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7356 .node_id = PM_NODE_IDENTIFY(parser),
7358 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7359 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7362 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7363 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7364 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7365 .unescaped = *unescaped
7374static inline pm_symbol_node_t *
7375pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7376 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7382static pm_symbol_node_t *
7383pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7384 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));
7385 parser->current_string = PM_STRING_EMPTY;
7392static pm_symbol_node_t *
7393pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7394 pm_symbol_node_t *node;
7396 switch (token->type) {
7397 case PM_TOKEN_LABEL: {
7398 pm_token_t opening = not_provided(parser);
7399 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7401 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7402 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7404 assert((label.end - label.start) >= 0);
7405 pm_string_shared_init(&node->unescaped, label.start, label.end);
7406 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7410 case PM_TOKEN_MISSING: {
7411 pm_token_t opening = not_provided(parser);
7412 pm_token_t closing = not_provided(parser);
7414 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7415 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7419 assert(false && "unreachable");
7430static pm_symbol_node_t *
7431pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7432 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7434 *node = (pm_symbol_node_t) {
7436 .type = PM_SYMBOL_NODE,
7437 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7438 .node_id = PM_NODE_IDENTIFY(parser),
7439 .location = PM_LOCATION_NULL_VALUE(parser)
7441 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7445 pm_string_constant_init(&node->unescaped, content, strlen(content));
7453pm_symbol_node_label_p(pm_node_t *node) {
7454 const uint8_t *end = NULL;
7456 switch (PM_NODE_TYPE(node)) {
7457 case PM_SYMBOL_NODE:
7458 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7460 case PM_INTERPOLATED_SYMBOL_NODE:
7461 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7467 return (end != NULL) && (end[-1] == ':');
7473static pm_symbol_node_t *
7474pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7475 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7477 *new_node = (pm_symbol_node_t) {
7479 .type = PM_SYMBOL_NODE,
7480 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7481 .node_id = PM_NODE_IDENTIFY(parser),
7483 .start = opening->start,
7487 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7488 .value_loc = node->content_loc,
7489 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7490 .unescaped = node->unescaped
7493 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7494 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7496 // We are explicitly _not_ using pm_node_destroy here because we don't want
7497 // to trash the unescaped string. We could instead copy the string if we
7498 // know that it is owned, but we're taking the fast path for now.
7507static pm_string_node_t *
7508pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7509 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7510 pm_node_flags_t flags = 0;
7512 switch (parser->frozen_string_literal) {
7513 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7514 flags = PM_STRING_FLAGS_MUTABLE;
7516 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7517 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7521 *new_node = (pm_string_node_t) {
7523 .type = PM_STRING_NODE,
7525 .node_id = PM_NODE_IDENTIFY(parser),
7526 .location = node->base.location
7528 .opening_loc = node->opening_loc,
7529 .content_loc = node->value_loc,
7530 .closing_loc = node->closing_loc,
7531 .unescaped = node->unescaped
7534 // We are explicitly _not_ using pm_node_destroy here because we don't want
7535 // to trash the unescaped string. We could instead copy the string if we
7536 // know that it is owned, but we're taking the fast path for now.
7545static pm_true_node_t *
7546pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7547 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7548 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7550 *node = (pm_true_node_t) {{
7551 .type = PM_TRUE_NODE,
7552 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7553 .node_id = PM_NODE_IDENTIFY(parser),
7554 .location = PM_LOCATION_TOKEN_VALUE(token)
7563static pm_true_node_t *
7564pm_true_node_synthesized_create(pm_parser_t *parser) {
7565 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7567 *node = (pm_true_node_t) {{
7568 .type = PM_TRUE_NODE,
7569 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7570 .node_id = PM_NODE_IDENTIFY(parser),
7571 .location = { .start = parser->start, .end = parser->end }
7580static pm_undef_node_t *
7581pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7582 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7583 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7585 *node = (pm_undef_node_t) {
7587 .type = PM_UNDEF_NODE,
7588 .node_id = PM_NODE_IDENTIFY(parser),
7589 .location = PM_LOCATION_TOKEN_VALUE(token),
7591 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7602pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7603 node->base.location.end = name->location.end;
7604 pm_node_list_append(&node->names, name);
7610static pm_unless_node_t *
7611pm_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) {
7612 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7613 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7616 if (statements != NULL) {
7617 end = statements->base.location.end;
7619 end = predicate->location.end;
7622 *node = (pm_unless_node_t) {
7624 .type = PM_UNLESS_NODE,
7625 .flags = PM_NODE_FLAG_NEWLINE,
7626 .node_id = PM_NODE_IDENTIFY(parser),
7628 .start = keyword->start,
7632 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7633 .predicate = predicate,
7634 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7635 .statements = statements,
7636 .else_clause = NULL,
7637 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7646static pm_unless_node_t *
7647pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7648 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7649 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7651 pm_statements_node_t *statements = pm_statements_node_create(parser);
7652 pm_statements_node_body_append(parser, statements, statement, true);
7654 *node = (pm_unless_node_t) {
7656 .type = PM_UNLESS_NODE,
7657 .flags = PM_NODE_FLAG_NEWLINE,
7658 .node_id = PM_NODE_IDENTIFY(parser),
7660 .start = statement->location.start,
7661 .end = predicate->location.end
7664 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7665 .predicate = predicate,
7666 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7667 .statements = statements,
7668 .else_clause = NULL,
7669 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7676pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7677 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7678 node->base.location.end = end_keyword->end;
7687pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7688 assert(parser->current_block_exits != NULL);
7690 // All of the block exits that we want to remove should be within the
7691 // statements, and since we are modifying the statements, we shouldn't have
7692 // to check the end location.
7693 const uint8_t *start = statements->base.location.start;
7695 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7696 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7697 if (block_exit->location.start < start) break;
7699 // Implicitly remove from the list by lowering the size.
7700 parser->current_block_exits->size--;
7707static pm_until_node_t *
7708pm_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) {
7709 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7710 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7712 *node = (pm_until_node_t) {
7714 .type = PM_UNTIL_NODE,
7716 .node_id = PM_NODE_IDENTIFY(parser),
7718 .start = keyword->start,
7719 .end = closing->end,
7722 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7723 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7724 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7725 .predicate = predicate,
7726 .statements = statements
7735static pm_until_node_t *
7736pm_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) {
7737 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7738 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7739 pm_loop_modifier_block_exits(parser, statements);
7741 *node = (pm_until_node_t) {
7743 .type = PM_UNTIL_NODE,
7745 .node_id = PM_NODE_IDENTIFY(parser),
7747 .start = statements->base.location.start,
7748 .end = predicate->location.end,
7751 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7752 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7753 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7754 .predicate = predicate,
7755 .statements = statements
7764static pm_when_node_t *
7765pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7766 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7768 *node = (pm_when_node_t) {
7770 .type = PM_WHEN_NODE,
7771 .node_id = PM_NODE_IDENTIFY(parser),
7773 .start = keyword->start,
7777 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7779 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7790pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7791 node->base.location.end = condition->location.end;
7792 pm_node_list_append(&node->conditions, condition);
7799pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7800 node->base.location.end = then_keyword->end;
7801 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7808pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7809 if (statements->base.location.end > node->base.location.end) {
7810 node->base.location.end = statements->base.location.end;
7813 node->statements = statements;
7819static pm_while_node_t *
7820pm_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) {
7821 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7822 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7824 *node = (pm_while_node_t) {
7826 .type = PM_WHILE_NODE,
7828 .node_id = PM_NODE_IDENTIFY(parser),
7830 .start = keyword->start,
7834 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7835 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7836 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7837 .predicate = predicate,
7838 .statements = statements
7847static pm_while_node_t *
7848pm_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) {
7849 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7850 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7851 pm_loop_modifier_block_exits(parser, statements);
7853 *node = (pm_while_node_t) {
7855 .type = PM_WHILE_NODE,
7857 .node_id = PM_NODE_IDENTIFY(parser),
7859 .start = statements->base.location.start,
7860 .end = predicate->location.end
7863 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7864 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7865 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7866 .predicate = predicate,
7867 .statements = statements
7876static pm_while_node_t *
7877pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7878 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7880 *node = (pm_while_node_t) {
7882 .type = PM_WHILE_NODE,
7883 .node_id = PM_NODE_IDENTIFY(parser),
7884 .location = PM_LOCATION_NULL_VALUE(parser)
7886 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7887 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7888 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7889 .predicate = predicate,
7890 .statements = statements
7900static pm_x_string_node_t *
7901pm_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) {
7902 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7904 *node = (pm_x_string_node_t) {
7906 .type = PM_X_STRING_NODE,
7907 .flags = PM_STRING_FLAGS_FROZEN,
7908 .node_id = PM_NODE_IDENTIFY(parser),
7910 .start = opening->start,
7914 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7915 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7916 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7917 .unescaped = *unescaped
7926static inline pm_x_string_node_t *
7927pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7928 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7934static pm_yield_node_t *
7935pm_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) {
7936 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7939 if (rparen_loc->start != NULL) {
7940 end = rparen_loc->end;
7941 } else if (arguments != NULL) {
7942 end = arguments->base.location.end;
7943 } else if (lparen_loc->start != NULL) {
7944 end = lparen_loc->end;
7949 *node = (pm_yield_node_t) {
7951 .type = PM_YIELD_NODE,
7952 .node_id = PM_NODE_IDENTIFY(parser),
7954 .start = keyword->start,
7958 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7959 .lparen_loc = *lparen_loc,
7960 .arguments = arguments,
7961 .rparen_loc = *rparen_loc
7968#undef PM_NODE_IDENTIFY
7975pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7976 pm_scope_t *scope = parser->current_scope;
7979 while (scope != NULL) {
7980 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7981 if (scope->closed) break;
7983 scope = scope->previous;
7996pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7997 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
8004pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8005 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
8011static pm_constant_id_t
8012pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
8013 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
8014 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8021static inline pm_constant_id_t
8022pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8023 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8029static pm_constant_id_t
8030pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8031 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8032 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8039static pm_constant_id_t
8040pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8041 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8042 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8054pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8055 // We want to check whether the parameter name is a numbered parameter or
8057 pm_refute_numbered_parameter(parser, name->start, name->end);
8059 // Otherwise we'll fetch the constant id for the parameter name and check
8060 // whether it's already in the current scope.
8061 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8063 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8064 // Add an error if the parameter doesn't start with _ and has been seen before
8065 if ((name->start < name->end) && (*name->start != '_')) {
8066 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8077pm_parser_scope_pop(pm_parser_t *parser) {
8078 pm_scope_t *scope = parser->current_scope;
8079 parser->current_scope = scope->previous;
8080 pm_locals_free(&scope->locals);
8081 pm_node_list_free(&scope->implicit_parameters);
8085/******************************************************************************/
8087/******************************************************************************/
8093pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8094 *stack = (*stack << 1) | (value & 1);
8101pm_state_stack_pop(pm_state_stack_t *stack) {
8109pm_state_stack_p(const pm_state_stack_t *stack) {
8114pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8115 // Use the negation of the value to prevent stack overflow.
8116 pm_state_stack_push(&parser->accepts_block_stack, !value);
8120pm_accepts_block_stack_pop(pm_parser_t *parser) {
8121 pm_state_stack_pop(&parser->accepts_block_stack);
8125pm_accepts_block_stack_p(pm_parser_t *parser) {
8126 return !pm_state_stack_p(&parser->accepts_block_stack);
8130pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8131 pm_state_stack_push(&parser->do_loop_stack, value);
8135pm_do_loop_stack_pop(pm_parser_t *parser) {
8136 pm_state_stack_pop(&parser->do_loop_stack);
8140pm_do_loop_stack_p(pm_parser_t *parser) {
8141 return pm_state_stack_p(&parser->do_loop_stack);
8144/******************************************************************************/
8145/* Lexer check helpers */
8146/******************************************************************************/
8152static inline uint8_t
8153peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8154 if (cursor < parser->end) {
8166static inline uint8_t
8167peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8168 return peek_at(parser, parser->current.end + offset);
8175static inline uint8_t
8176peek(const pm_parser_t *parser) {
8177 return peek_at(parser, parser->current.end);
8185match(pm_parser_t *parser, uint8_t value) {
8186 if (peek(parser) == value) {
8187 parser->current.end++;
8198match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8199 if (peek_at(parser, cursor) == '\n') {
8202 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8214match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8215 return match_eol_at(parser, parser->current.end + offset);
8224match_eol(pm_parser_t *parser) {
8225 return match_eol_at(parser, parser->current.end);
8231static inline const uint8_t *
8232next_newline(const uint8_t *cursor, ptrdiff_t length) {
8233 assert(length >= 0);
8235 // Note that it's okay for us to use memchr here to look for \n because none
8236 // of the encodings that we support have \n as a component of a multi-byte
8238 return memchr(cursor, '\n', (size_t) length);
8245ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8246 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));
8254parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8255 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8257 if (encoding != NULL) {
8258 if (parser->encoding != encoding) {
8259 parser->encoding = encoding;
8260 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8263 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8275parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8276 const uint8_t *cursor = parser->current.start + 1;
8277 const uint8_t *end = parser->current.end;
8279 bool separator = false;
8281 if (end - cursor <= 6) return;
8282 switch (cursor[6]) {
8283 case 'C': case 'c': cursor += 6; continue;
8284 case 'O': case 'o': cursor += 5; continue;
8285 case 'D': case 'd': cursor += 4; continue;
8286 case 'I': case 'i': cursor += 3; continue;
8287 case 'N': case 'n': cursor += 2; continue;
8288 case 'G': case 'g': cursor += 1; continue;
8295 if (pm_char_is_whitespace(*cursor)) break;
8298 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8304 if (++cursor >= end) return;
8305 } while (pm_char_is_whitespace(*cursor));
8307 if (separator) break;
8308 if (*cursor != '=' && *cursor != ':') return;
8314 const uint8_t *value_start = cursor;
8315 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8317 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8318 // If we were unable to parse the encoding value, then we've got an
8319 // issue because we didn't understand the encoding that the user was
8320 // trying to use. In this case we'll keep using the default encoding but
8321 // add an error to the parser to indicate an unsuccessful parse.
8322 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8327 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8328 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8329 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8330} pm_magic_comment_boolean_value_t;
8336static pm_magic_comment_boolean_value_t
8337parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8338 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8339 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8340 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8341 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8343 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8348pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8349 return b == '\'' || b == '"' || b == ':' || b == ';';
8357static inline const uint8_t *
8358parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8359 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8360 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8379parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8382 const uint8_t *start = parser->
current.start + 1;
8383 const uint8_t *end = parser->
current.end;
8384 if (end - start <= 7)
return false;
8386 const uint8_t *cursor;
8387 bool indicator =
false;
8389 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8392 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8403 while (cursor < end) {
8404 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8406 const uint8_t *key_start = cursor;
8407 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8409 const uint8_t *key_end = cursor;
8410 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8411 if (cursor == end)
break;
8413 if (*cursor ==
':') {
8416 if (!indicator)
return false;
8420 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8421 if (cursor == end)
break;
8423 const uint8_t *value_start;
8424 const uint8_t *value_end;
8426 if (*cursor ==
'"') {
8427 value_start = ++cursor;
8428 for (; cursor < end && *cursor !=
'"'; cursor++) {
8429 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8432 if (*cursor ==
'"') cursor++;
8434 value_start = cursor;
8435 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8440 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8442 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8443 if (cursor != end)
return false;
8449 const size_t key_length = (size_t) (key_end - key_start);
8453 pm_string_shared_init(&key, key_start, key_end);
8455 uint8_t *buffer =
xmalloc(key_length);
8456 if (buffer == NULL)
break;
8458 memcpy(buffer, key_start, key_length);
8459 buffer[dash - key_start] =
'_';
8461 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8462 buffer[dash - key_start] =
'_';
8465 pm_string_owned_init(&key, buffer, key_length);
8470 const uint8_t *key_source = pm_string_source(&key);
8471 uint32_t value_length = (uint32_t) (value_end - value_start);
8477 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8478 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8480 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8484 if (key_length == 11) {
8485 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8486 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8487 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8488 PM_PARSER_WARN_TOKEN_FORMAT(
8491 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8493 (
const char *) key_source,
8495 (
const char *) value_start
8498 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8501 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8506 }
else if (key_length == 21) {
8507 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8510 if (semantic_token_seen) {
8511 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8513 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8514 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8515 PM_PARSER_WARN_TOKEN_FORMAT(
8518 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8520 (
const char *) key_source,
8522 (
const char *) value_start
8525 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8528 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8534 }
else if (key_length == 24) {
8535 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8536 const uint8_t *cursor = parser->
current.start;
8537 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8539 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8540 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8541 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8542 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8543 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8544 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8545 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8546 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8547 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8548 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8550 PM_PARSER_WARN_TOKEN_FORMAT(
8553 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8555 (
const char *) key_source,
8557 (
const char *) value_start
8565 pm_string_free(&key);
8674 while (context_node != NULL) {
8675 if (context_terminator(context_node->
context, token))
return context_node->
context;
8676 context_node = context_node->
prev;
8685 if (context_node == NULL)
return false;
8710 while (context_node != NULL) {
8711 if (context_node->
context == context)
return true;
8712 context_node = context_node->
prev;
8722 while (context_node != NULL) {
8723 switch (context_node->
context) {
8744 context_node = context_node->
prev;
8759 assert(
false &&
"unreachable");
8816 assert(
false &&
"unreachable");
8825pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8826 if (invalid != NULL) {
8827 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8828 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8833pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8834 const uint8_t *invalid = NULL;
8835 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8836 pm_strspn_number_validate(parser,
string, length, invalid);
8841pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8842 const uint8_t *invalid = NULL;
8843 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8844 pm_strspn_number_validate(parser,
string, length, invalid);
8849pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8850 const uint8_t *invalid = NULL;
8851 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8852 pm_strspn_number_validate(parser,
string, length, invalid);
8857pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8858 const uint8_t *invalid = NULL;
8859 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8860 pm_strspn_number_validate(parser,
string, length, invalid);
8865lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8870 if (peek(parser) ==
'.') {
8871 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8873 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8884 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8885 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8888 if (pm_char_is_decimal_digit(peek(parser))) {
8890 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8892 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8894 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8896 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8909lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8913 if (peek_offset(parser, -1) ==
'0') {
8914 switch (*parser->
current.end) {
8919 if (pm_char_is_decimal_digit(peek(parser))) {
8920 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8923 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8932 if (pm_char_is_binary_digit(peek(parser))) {
8933 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8936 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8946 if (pm_char_is_octal_digit(peek(parser))) {
8947 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8950 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8966 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8974 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8975 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8978 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8986 type = lex_optional_float_suffix(parser, seen_e);
8993 type = lex_optional_float_suffix(parser, seen_e);
9000 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
9003 type = lex_optional_float_suffix(parser, seen_e);
9009 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
9010 const uint8_t *fraction_start = parser->
current.end;
9011 const uint8_t *fraction_end = parser->
current.end + 2;
9012 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
9013 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9025 bool seen_e =
false;
9026 type = lex_numeric_prefix(parser, &seen_e);
9028 const uint8_t *end = parser->
current.end;
9032 if (match(parser,
'r')) {
9035 if (match(parser,
'i')) {
9038 }
else if (match(parser,
'i')) {
9042 if (!seen_e && match(parser,
'r')) {
9045 if (match(parser,
'i')) {
9048 }
else if (match(parser,
'i')) {
9053 const uint8_t b = peek(parser);
9054 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9067 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9073 bool allow_multiple =
true;
9075 switch (*parser->
current.end) {
9106 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9109 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9113 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9133 allow_multiple =
false;
9138 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9141 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
9142 }
else if (pm_char_is_whitespace(peek(parser))) {
9145 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9151 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9173 if (memcmp(current_start, value, vlen) == 0) {
9176 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9177 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9179 lex_state_set(parser, state);
9180 if (state == PM_LEX_STATE_BEG) {
9184 if ((modifier_type !=
PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9185 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9186 return modifier_type;
9197lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9200 const uint8_t *end = parser->
end;
9201 const uint8_t *current_start = parser->
current.start;
9202 const uint8_t *current_end = parser->
current.end;
9205 if (encoding_changed) {
9206 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
9207 current_end += width;
9210 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
9211 current_end += width;
9214 parser->
current.end = current_end;
9218 width = (size_t) (current_end - current_start);
9220 if (current_end < end) {
9221 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9227 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9228 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9232 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9233 (void) match(parser,
':');
9237 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9246 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,
'=')) {
9253 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9254 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9258 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9259 (void) match(parser,
':');
9264 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9269 if (pm_do_loop_stack_p(parser)) {
9330 if (encoding_changed) {
9360lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9363 if (pound + 1 >= parser->
end) {
9364 parser->
current.end = pound + 1;
9374 if (pound + 2 >= parser->
end) {
9375 parser->
current.end = pound + 1;
9381 const uint8_t *variable = pound + 2;
9382 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9384 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
9388 if (pound > parser->
current.start) {
9395 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9396 parser->
current.end = pound + 1;
9403 parser->
current.end = pound + 1;
9409 if (pound + 2 >= parser->
end) {
9410 parser->
current.end = pound + 1;
9417 const uint8_t *check = pound + 2;
9419 if (pound[2] ==
'-') {
9420 if (pound + 3 >= parser->
end) {
9421 parser->
current.end = pound + 2;
9433 char_is_identifier_start(parser, check, parser->
end - check) ||
9434 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9439 if (pound > parser->
current.start) {
9446 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9447 parser->
current.end = pound + 1;
9453 parser->
current.end = pound + 1;
9459 if (pound > parser->
current.start) {
9468 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9469 parser->
current.end = pound + 2;
9471 pm_do_loop_stack_push(parser,
false);
9477 parser->
current.end = pound + 1;
9482static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9483static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9484static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9485static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9486static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9491static const bool ascii_printable_chars[] = {
9492 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9493 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9494 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9495 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9496 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9497 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9498 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9499 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9503char_is_ascii_printable(
const uint8_t b) {
9504 return (b < 0x80) && ascii_printable_chars[b];
9511static inline uint8_t
9512escape_hexadecimal_digit(
const uint8_t value) {
9513 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9521static inline uint32_t
9522escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9524 for (
size_t index = 0; index < length; index++) {
9525 if (index != 0) value <<= 4;
9526 value |= escape_hexadecimal_digit(
string[index]);
9531 if (value >= 0xD800 && value <= 0xDFFF) {
9532 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9542static inline uint8_t
9543escape_byte(uint8_t value,
const uint8_t flags) {
9544 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9545 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9553escape_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) {
9557 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9565 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9566 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9567 pm_buffer_append_byte(buffer, 0xEF);
9568 pm_buffer_append_byte(buffer, 0xBF);
9569 pm_buffer_append_byte(buffer, 0xBD);
9581 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9587 pm_buffer_append_byte(buffer,
byte);
9607 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9608 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9611 escape_write_byte_encoded(parser, buffer,
byte);
9623 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9627 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
9628 }
else if (width > 1) {
9630 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9631 pm_buffer_append_bytes(b, parser->
current.end, width);
9637 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9647escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9648#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9650 PM_PARSER_WARN_TOKEN_FORMAT(
9653 PM_WARN_INVALID_CHARACTER,
9667 uint8_t peeked = peek(parser);
9671 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9676 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9681 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9686 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9691 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9696 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9701 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9706 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9711 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9716 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9721 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9724 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9725 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9728 if (pm_char_is_octal_digit(peek(parser))) {
9729 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9732 if (pm_char_is_octal_digit(peek(parser))) {
9733 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9738 value = escape_byte(value, flags);
9739 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9743 const uint8_t *start = parser->
current.end - 1;
9746 uint8_t
byte = peek(parser);
9748 if (pm_char_is_hexadecimal_digit(
byte)) {
9749 uint8_t value = escape_hexadecimal_digit(
byte);
9752 byte = peek(parser);
9753 if (pm_char_is_hexadecimal_digit(
byte)) {
9754 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9758 value = escape_byte(value, flags);
9759 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9760 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9761 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9763 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9767 escape_write_byte_encoded(parser, buffer, value);
9769 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9775 const uint8_t *start = parser->
current.end - 1;
9779 const uint8_t *start = parser->
current.end - 2;
9780 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9781 }
else if (peek(parser) ==
'{') {
9782 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9787 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9788 parser->
current.end += whitespace;
9789 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9800 const uint8_t *extra_codepoints_start = NULL;
9801 int codepoints_count = 0;
9804 const uint8_t *unicode_start = parser->
current.end;
9805 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9807 if (hexadecimal_length > 6) {
9809 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9810 }
else if (hexadecimal_length == 0) {
9813 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9817 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9819 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9820 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9826 parser->
current.end += hexadecimal_length;
9828 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9829 extra_codepoints_start = unicode_start;
9832 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9833 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9840 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9841 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9845 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9846 }
else if (peek(parser) ==
'}') {
9849 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9853 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9855 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9859 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9860 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9863 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9866 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9867 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9869 const uint8_t *start = parser->
current.end - 2;
9870 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9872 }
else if (length == 4) {
9873 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9875 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9876 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9879 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9882 parser->
current.end += length;
9884 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9888 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9890 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9899 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9900 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9904 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9908 uint8_t peeked = peek(parser);
9912 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9918 if (match(parser,
'u') || match(parser,
'U')) {
9919 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9923 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9927 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9928 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9932 escape_read_warn(parser, flags, 0,
"\\t");
9933 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9936 if (!char_is_ascii_printable(peeked)) {
9937 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9942 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9949 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9950 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9953 if (peek(parser) !=
'-') {
9955 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9961 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9965 uint8_t peeked = peek(parser);
9969 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9975 if (match(parser,
'u') || match(parser,
'U')) {
9976 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9980 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9984 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9985 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9989 escape_read_warn(parser, flags, 0,
"\\t");
9990 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9993 if (!char_is_ascii_printable(peeked)) {
9995 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
10000 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
10007 if (flags & PM_ESCAPE_FLAG_META) {
10008 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
10011 if (peek(parser) !=
'-') {
10013 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10019 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10023 uint8_t peeked = peek(parser);
10028 if (match(parser,
'u') || match(parser,
'U')) {
10029 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10033 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10037 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10038 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10042 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10043 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10046 if (!char_is_ascii_printable(peeked)) {
10048 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10053 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10058 if (peek_offset(parser, 1) ==
'\n') {
10060 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10066 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
10068 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10072 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
10074 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10108 if (lex_state_end_p(parser)) {
10109 lex_state_set(parser, PM_LEX_STATE_BEG);
10114 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10119 if (pm_char_is_whitespace(*parser->
current.end)) {
10120 lex_state_set(parser, PM_LEX_STATE_BEG);
10124 lex_state_set(parser, PM_LEX_STATE_BEG);
10126 if (match(parser,
'\\')) {
10127 lex_state_set(parser, PM_LEX_STATE_END);
10130 pm_buffer_init_capacity(&buffer, 3);
10132 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10144 (parser->
current.end + encoding_width >= parser->
end) ||
10145 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
10148 lex_state_set(parser, PM_LEX_STATE_END);
10149 parser->
current.end += encoding_width;
10165 const uint8_t *end = parser->
end;
10168 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10169 parser->
current.end += width;
10171 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
10172 parser->
current.end += width;
10174 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
10181 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10184 pm_parser_err_token(parser, &parser->
current, diag_id);
10190 lex_mode_pop(parser);
10212 if (comment == NULL)
return NULL;
10230 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10232 if (newline == NULL) {
10235 pm_newline_list_append(&parser->
newline_list, newline);
10236 parser->
current.end = newline + 1;
10240 parser_lex_callback(parser);
10243 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10248 while (parser->
current.end + 4 <= parser->
end) {
10254 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10257 pm_char_is_whitespace(parser->
current.end[4]) ||
10258 (parser->
current.end[4] ==
'\0') ||
10259 (parser->
current.end[4] ==
'\004') ||
10260 (parser->
current.end[4] ==
'\032')
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);
10283 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10285 if (newline == NULL) {
10288 pm_newline_list_append(&parser->
newline_list, newline);
10289 parser->
current.end = newline + 1;
10293 parser_lex_callback(parser);
10296 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10312 parser_lex_callback(parser);
10336 const uint8_t *cursor = parser->
current.end;
10338 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10339 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10402 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10413static inline size_t
10419 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10424 return (width == 0 ? 1 : width);
10432 size_t width = parser_char_width(parser);
10433 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10434 parser->
current.end += width;
10439 size_t width = parser_char_width(parser);
10440 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10442 parser->
current.end += width;
10446pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10447 for (
size_t index = 0; index < length; index++) {
10448 if (value[index] & 0x80)
return false;
10462 pm_string_owned_init(&parser->
current_string, (uint8_t *) pm_buffer_value(&token_buffer->
buffer), pm_buffer_length(&token_buffer->
buffer));
10483 if (token_buffer->
cursor == NULL) {
10486 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10487 pm_token_buffer_copy(parser, token_buffer);
10499 pm_regexp_token_buffer_copy(parser, token_buffer);
10503#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10515 const uint8_t *start;
10516 if (token_buffer->
cursor == NULL) {
10517 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10518 start = parser->
current.start;
10520 start = token_buffer->
cursor;
10523 const uint8_t *end = parser->
current.end - 1;
10524 assert(end >= start);
10525 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10527 token_buffer->
cursor = end;
10532 const uint8_t *start;
10534 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10535 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10536 start = parser->
current.start;
10541 const uint8_t *end = parser->
current.end - 1;
10542 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10543 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10548#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10554static inline size_t
10556 size_t whitespace = 0;
10559 case PM_HEREDOC_INDENT_NONE:
10564 case PM_HEREDOC_INDENT_DASH:
10566 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10568 case PM_HEREDOC_INDENT_TILDE:
10571 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10572 if (**cursor ==
'\t') {
10573 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10592 size_t eol_length = match_eol(parser);
10599 parser_flush_heredoc_end(parser);
10605 uint8_t delimiter = *parser->
current.end;
10609 if (eol_length == 2) {
10610 delimiter = *(parser->
current.end + 1);
10613 parser->
current.end += eol_length;
10617 return *parser->
current.end++;
10624#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10643 bool lexed_comment =
false;
10651 case PM_LEX_DEFAULT:
10652 case PM_LEX_EMBEXPR:
10653 case PM_LEX_EMBVAR:
10669 bool space_seen =
false;
10673 bool chomping =
true;
10674 while (parser->
current.end < parser->
end && chomping) {
10675 switch (*parser->
current.end) {
10684 if (match_eol_offset(parser, 1)) {
10687 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10693 size_t eol_length = match_eol_offset(parser, 1);
10699 parser->
current.end += eol_length + 1;
10703 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10736 switch (*parser->
current.end++) {
10744 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10745 parser->
current.end = ending == NULL ? parser->
end : ending;
10750 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10753 if (ending) parser->
current.end++;
10755 parser_lex_callback(parser);
10767 parser_lex_magic_comment_encoding(parser);
10771 lexed_comment =
true;
10777 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10789 if (!lexed_comment) {
10790 parser->
current.end += eol_length - 1;
10799 parser_flush_heredoc_end(parser);
10804 switch (lex_state_ignored_p(parser)) {
10805 case PM_IGNORED_NEWLINE_NONE:
10807 case PM_IGNORED_NEWLINE_PATTERN:
10809 if (!lexed_comment) parser_lex_ignored_newline(parser);
10810 lex_state_set(parser, PM_LEX_STATE_BEG);
10816 case PM_IGNORED_NEWLINE_ALL:
10817 if (!lexed_comment) parser_lex_ignored_newline(parser);
10818 lexed_comment =
false;
10819 goto lex_next_token;
10827 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10829 if (next_content < parser->end) {
10835 if (next_content[0] ==
'#') {
10837 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10839 while (following && (following + 1 < parser->
end)) {
10841 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10845 if (peek_at(parser, following) !=
'#')
break;
10849 following = next_newline(following, parser->
end - following);
10855 lex_state_ignored_p(parser) ||
10857 (peek_at(parser, following) ==
'.') ||
10858 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10861 if (!lexed_comment) parser_lex_ignored_newline(parser);
10862 lexed_comment =
false;
10863 goto lex_next_token;
10869 if (next_content[0] ==
'.') {
10873 if (peek_at(parser, next_content + 1) ==
'.') {
10874 if (!lexed_comment) parser_lex_ignored_newline(parser);
10875 lex_state_set(parser, PM_LEX_STATE_BEG);
10881 if (!lexed_comment) parser_lex_ignored_newline(parser);
10882 lex_state_set(parser, PM_LEX_STATE_DOT);
10883 parser->
current.start = next_content;
10884 parser->
current.end = next_content + 1;
10891 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10892 if (!lexed_comment) parser_lex_ignored_newline(parser);
10893 lex_state_set(parser, PM_LEX_STATE_DOT);
10894 parser->
current.start = next_content;
10895 parser->
current.end = next_content + 2;
10903 lex_state_set(parser, PM_LEX_STATE_BEG);
10906 if (!lexed_comment) parser_lex_callback(parser);
10916 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10923 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10928 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10929 pm_do_loop_stack_push(parser,
false);
10936 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10937 pm_do_loop_stack_pop(parser);
10942 lex_state_set(parser, PM_LEX_STATE_BEG);
10951 if (lex_state_operator_p(parser)) {
10952 if (match(parser,
']')) {
10954 lex_state_set(parser, PM_LEX_STATE_ARG);
10958 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10962 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10966 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10967 pm_do_loop_stack_push(parser,
false);
10973 lex_state_set(parser, PM_LEX_STATE_END);
10974 pm_do_loop_stack_pop(parser);
10984 lex_state_set(parser, PM_LEX_STATE_BEG);
10986 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10988 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10989 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10992 lex_state_set(parser, PM_LEX_STATE_BEG);
10993 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10996 lex_state_set(parser, PM_LEX_STATE_BEG);
10999 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11004 pm_do_loop_stack_push(parser,
false);
11012 pm_do_loop_stack_pop(parser);
11015 lex_mode_pop(parser);
11020 lex_state_set(parser, PM_LEX_STATE_END);
11025 if (match(parser,
'*')) {
11026 if (match(parser,
'=')) {
11027 lex_state_set(parser, PM_LEX_STATE_BEG);
11033 if (lex_state_spcarg_p(parser, space_seen)) {
11034 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11036 }
else if (lex_state_beg_p(parser)) {
11038 }
else if (ambiguous_operator_p(parser, space_seen)) {
11039 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11042 if (lex_state_operator_p(parser)) {
11043 lex_state_set(parser, PM_LEX_STATE_ARG);
11045 lex_state_set(parser, PM_LEX_STATE_BEG);
11051 if (match(parser,
'=')) {
11052 lex_state_set(parser, PM_LEX_STATE_BEG);
11058 if (lex_state_spcarg_p(parser, space_seen)) {
11059 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11061 }
else if (lex_state_beg_p(parser)) {
11063 }
else if (ambiguous_operator_p(parser, space_seen)) {
11064 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11067 if (lex_state_operator_p(parser)) {
11068 lex_state_set(parser, PM_LEX_STATE_ARG);
11070 lex_state_set(parser, PM_LEX_STATE_BEG);
11078 if (lex_state_operator_p(parser)) {
11079 lex_state_set(parser, PM_LEX_STATE_ARG);
11080 if (match(parser,
'@')) {
11084 lex_state_set(parser, PM_LEX_STATE_BEG);
11087 if (match(parser,
'=')) {
11091 if (match(parser,
'~')) {
11100 current_token_starts_line(parser) &&
11102 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11103 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11110 goto lex_next_token;
11113 if (lex_state_operator_p(parser)) {
11114 lex_state_set(parser, PM_LEX_STATE_ARG);
11116 lex_state_set(parser, PM_LEX_STATE_BEG);
11119 if (match(parser,
'>')) {
11123 if (match(parser,
'~')) {
11127 if (match(parser,
'=')) {
11135 if (match(parser,
'<')) {
11137 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11138 !lex_state_end_p(parser) &&
11139 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11141 const uint8_t *end = parser->
current.end;
11146 if (match(parser,
'-')) {
11147 indent = PM_HEREDOC_INDENT_DASH;
11149 else if (match(parser,
'~')) {
11150 indent = PM_HEREDOC_INDENT_TILDE;
11153 if (match(parser,
'`')) {
11154 quote = PM_HEREDOC_QUOTE_BACKTICK;
11156 else if (match(parser,
'"')) {
11157 quote = PM_HEREDOC_QUOTE_DOUBLE;
11159 else if (match(parser,
'\'')) {
11160 quote = PM_HEREDOC_QUOTE_SINGLE;
11163 const uint8_t *ident_start = parser->
current.end;
11168 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
11171 if (quote == PM_HEREDOC_QUOTE_NONE) {
11172 parser->
current.end += width;
11174 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
11175 parser->
current.end += width;
11181 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11186 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11187 bool ident_error =
false;
11189 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11190 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11191 ident_error =
true;
11196 .mode = PM_LEX_HEREDOC,
11199 .ident_start = ident_start,
11200 .ident_length = ident_length,
11204 .next_start = parser->
current.end,
11206 .line_continuation =
false
11211 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11213 if (body_start == NULL) {
11218 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11219 body_start = parser->
end;
11223 pm_newline_list_append(&parser->
newline_list, body_start);
11236 if (match(parser,
'=')) {
11237 lex_state_set(parser, PM_LEX_STATE_BEG);
11241 if (ambiguous_operator_p(parser, space_seen)) {
11242 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11245 if (lex_state_operator_p(parser)) {
11246 lex_state_set(parser, PM_LEX_STATE_ARG);
11248 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11249 lex_state_set(parser, PM_LEX_STATE_BEG);
11255 if (lex_state_operator_p(parser)) {
11256 lex_state_set(parser, PM_LEX_STATE_ARG);
11258 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11259 lex_state_set(parser, PM_LEX_STATE_BEG);
11262 if (match(parser,
'=')) {
11263 if (match(parser,
'>')) {
11274 if (match(parser,
'>')) {
11275 if (lex_state_operator_p(parser)) {
11276 lex_state_set(parser, PM_LEX_STATE_ARG);
11278 lex_state_set(parser, PM_LEX_STATE_BEG);
11283 if (lex_state_operator_p(parser)) {
11284 lex_state_set(parser, PM_LEX_STATE_ARG);
11286 lex_state_set(parser, PM_LEX_STATE_BEG);
11293 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11294 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11300 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11301 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11305 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11306 if (previous_command_start) {
11307 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11309 lex_state_set(parser, PM_LEX_STATE_ARG);
11315 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11321 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11322 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11328 LEX(lex_question_mark(parser));
11332 if (match(parser,
'&')) {
11333 lex_state_set(parser, PM_LEX_STATE_BEG);
11335 if (match(parser,
'=')) {
11342 if (match(parser,
'=')) {
11343 lex_state_set(parser, PM_LEX_STATE_BEG);
11347 if (match(parser,
'.')) {
11348 lex_state_set(parser, PM_LEX_STATE_DOT);
11353 if (lex_state_spcarg_p(parser, space_seen)) {
11354 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11355 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11357 const uint8_t delim = peek_offset(parser, 1);
11359 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
11360 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11365 }
else if (lex_state_beg_p(parser)) {
11367 }
else if (ambiguous_operator_p(parser, space_seen)) {
11368 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11371 if (lex_state_operator_p(parser)) {
11372 lex_state_set(parser, PM_LEX_STATE_ARG);
11374 lex_state_set(parser, PM_LEX_STATE_BEG);
11382 if (match(parser,
'|')) {
11383 if (match(parser,
'=')) {
11384 lex_state_set(parser, PM_LEX_STATE_BEG);
11388 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11393 lex_state_set(parser, PM_LEX_STATE_BEG);
11397 if (match(parser,
'=')) {
11398 lex_state_set(parser, PM_LEX_STATE_BEG);
11402 if (lex_state_operator_p(parser)) {
11403 lex_state_set(parser, PM_LEX_STATE_ARG);
11405 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11412 if (lex_state_operator_p(parser)) {
11413 lex_state_set(parser, PM_LEX_STATE_ARG);
11415 if (match(parser,
'@')) {
11422 if (match(parser,
'=')) {
11423 lex_state_set(parser, PM_LEX_STATE_BEG);
11428 lex_state_beg_p(parser) ||
11429 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11431 lex_state_set(parser, PM_LEX_STATE_BEG);
11433 if (pm_char_is_decimal_digit(peek(parser))) {
11436 lex_state_set(parser, PM_LEX_STATE_END);
11443 if (ambiguous_operator_p(parser, space_seen)) {
11444 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11447 lex_state_set(parser, PM_LEX_STATE_BEG);
11453 if (lex_state_operator_p(parser)) {
11454 lex_state_set(parser, PM_LEX_STATE_ARG);
11456 if (match(parser,
'@')) {
11463 if (match(parser,
'=')) {
11464 lex_state_set(parser, PM_LEX_STATE_BEG);
11468 if (match(parser,
'>')) {
11469 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11473 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11474 bool is_beg = lex_state_beg_p(parser);
11475 if (!is_beg && spcarg) {
11476 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11479 if (is_beg || spcarg) {
11480 lex_state_set(parser, PM_LEX_STATE_BEG);
11484 if (ambiguous_operator_p(parser, space_seen)) {
11485 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11488 lex_state_set(parser, PM_LEX_STATE_BEG);
11494 bool beg_p = lex_state_beg_p(parser);
11496 if (match(parser,
'.')) {
11497 if (match(parser,
'.')) {
11500 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11501 lex_state_set(parser, PM_LEX_STATE_BEG);
11503 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11509 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11512 lex_state_set(parser, PM_LEX_STATE_BEG);
11516 lex_state_set(parser, PM_LEX_STATE_BEG);
11520 lex_state_set(parser, PM_LEX_STATE_DOT);
11536 lex_state_set(parser, PM_LEX_STATE_END);
11542 if (match(parser,
':')) {
11543 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)) {
11544 lex_state_set(parser, PM_LEX_STATE_BEG);
11548 lex_state_set(parser, PM_LEX_STATE_DOT);
11552 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11553 lex_state_set(parser, PM_LEX_STATE_BEG);
11557 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11558 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11562 lex_state_set(parser, PM_LEX_STATE_FNAME);
11567 if (lex_state_beg_p(parser)) {
11568 lex_mode_push_regexp(parser,
'\0',
'/');
11572 if (match(parser,
'=')) {
11573 lex_state_set(parser, PM_LEX_STATE_BEG);
11577 if (lex_state_spcarg_p(parser, space_seen)) {
11578 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11579 lex_mode_push_regexp(parser,
'\0',
'/');
11583 if (ambiguous_operator_p(parser, space_seen)) {
11584 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11587 if (lex_state_operator_p(parser)) {
11588 lex_state_set(parser, PM_LEX_STATE_ARG);
11590 lex_state_set(parser, PM_LEX_STATE_BEG);
11597 if (lex_state_operator_p(parser)) {
11598 lex_state_set(parser, PM_LEX_STATE_ARG);
11600 lex_state_set(parser, PM_LEX_STATE_BEG);
11606 if (lex_state_operator_p(parser)) {
11607 (void) match(parser,
'@');
11608 lex_state_set(parser, PM_LEX_STATE_ARG);
11610 lex_state_set(parser, PM_LEX_STATE_BEG);
11621 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11622 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11626 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11627 lex_state_set(parser, PM_LEX_STATE_BEG);
11630 lex_state_beg_p(parser) ||
11631 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11632 lex_state_spcarg_p(parser, space_seen)
11635 if (*parser->
current.end >= 0x80) {
11636 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11639 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11640 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11646 uint8_t delimiter = peek_offset(parser, 1);
11648 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11649 goto lex_next_token;
11652 switch (peek(parser)) {
11657 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11659 lex_mode_push_list_eof(parser);
11668 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11670 lex_mode_push_list_eof(parser);
11679 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11680 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11682 lex_mode_push_regexp(parser,
'\0',
'\0');
11691 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11692 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11694 lex_mode_push_string_eof(parser);
11703 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11704 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11706 lex_mode_push_string_eof(parser);
11715 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11716 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11717 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11719 lex_mode_push_string_eof(parser);
11728 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11730 lex_mode_push_list_eof(parser);
11739 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11741 lex_mode_push_list_eof(parser);
11750 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11751 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11753 lex_mode_push_string_eof(parser);
11763 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11764 goto lex_next_token;
11768 if (ambiguous_operator_p(parser, space_seen)) {
11769 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11772 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11783 lex_mode_pop(parser);
11786 lex_state_set(parser, PM_LEX_STATE_END);
11792 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11793 LEX(lex_at_variable(parser));
11796 if (*parser->
current.start !=
'_') {
11797 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
11804 if (*parser->
current.start >= 0x80) {
11805 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11806 }
else if (*parser->
current.start ==
'\\') {
11807 switch (peek_at(parser, parser->
current.start + 1)) {
11810 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11814 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11818 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11822 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11825 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11827 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11832 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11835 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11836 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11838 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11841 goto lex_next_token;
11855 current_token_starts_line(parser) &&
11856 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11857 (parser->
current.end == parser->
end || match_eol(parser))
11862 const uint8_t *cursor = parser->
current.end;
11863 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11864 pm_newline_list_append(&parser->
newline_list, cursor++);
11869 parser_lex_callback(parser);
11880 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11881 if (previous_command_start) {
11882 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11884 lex_state_set(parser, PM_LEX_STATE_ARG);
11886 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11887 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11889 lex_state_set(parser, PM_LEX_STATE_END);
11894 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11896 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11897 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11899 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11906 case PM_LEX_LIST: {
11920 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11921 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11928 if (whitespace > 0) {
11929 parser->
current.end += whitespace;
11930 if (peek_offset(parser, -1) ==
'\n') {
11932 parser_flush_heredoc_end(parser);
11946 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11947 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11953 while (breakpoint != NULL) {
11956 if (pm_char_is_whitespace(*breakpoint)) {
11957 parser->
current.end = breakpoint;
11958 pm_token_buffer_flush(parser, &token_buffer);
11968 parser->
current.end = breakpoint + 1;
11969 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11976 if (breakpoint > parser->
current.start) {
11977 parser->
current.end = breakpoint;
11978 pm_token_buffer_flush(parser, &token_buffer);
11984 parser->
current.end = breakpoint + 1;
11985 lex_mode_pop(parser);
11986 lex_state_set(parser, PM_LEX_STATE_END);
11991 if (*breakpoint ==
'\0') {
11992 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11999 if (*breakpoint ==
'\\') {
12000 parser->
current.end = breakpoint + 1;
12009 pm_token_buffer_escape(parser, &token_buffer);
12010 uint8_t peeked = peek(parser);
12018 pm_token_buffer_push_byte(&token_buffer, peeked);
12023 if (peek(parser) !=
'\n') {
12024 pm_token_buffer_push_byte(&token_buffer,
'\r');
12029 pm_token_buffer_push_byte(&token_buffer,
'\n');
12035 parser_flush_heredoc_end(parser);
12036 pm_token_buffer_copy(parser, &token_buffer);
12047 pm_token_buffer_push_byte(&token_buffer, peeked);
12050 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12052 pm_token_buffer_push_byte(&token_buffer,
'\\');
12053 pm_token_buffer_push_escaped(&token_buffer, parser);
12060 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12065 if (*breakpoint ==
'#') {
12073 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12078 pm_token_buffer_flush(parser, &token_buffer);
12087 parser->
current.end = breakpoint + 1;
12088 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12094 pm_token_buffer_flush(parser, &token_buffer);
12101 pm_token_buffer_flush(parser, &token_buffer);
12104 case PM_LEX_REGEXP: {
12126 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12127 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12130 while (breakpoint != NULL) {
12132 bool is_terminator = (*breakpoint == term);
12137 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12138 if (term ==
'\n') {
12139 is_terminator =
true;
12145 if (term ==
'\r') {
12146 is_terminator =
false;
12152 if (is_terminator) {
12154 parser->
current.end = breakpoint + 1;
12155 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12163 if (breakpoint > parser->
current.start) {
12164 parser->
current.end = breakpoint;
12165 pm_regexp_token_buffer_flush(parser, &token_buffer);
12170 size_t eol_length = match_eol_at(parser, breakpoint);
12172 parser->
current.end = breakpoint + eol_length;
12175 parser->
current.end = breakpoint + 1;
12182 lex_mode_pop(parser);
12183 lex_state_set(parser, PM_LEX_STATE_END);
12189 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12190 parser->
current.end = breakpoint + 1;
12191 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12196 switch (*breakpoint) {
12199 parser->
current.end = breakpoint + 1;
12200 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12203 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12204 parser->
current.end = breakpoint + 1;
12205 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12210 parser->
current.end = breakpoint;
12211 pm_regexp_token_buffer_escape(parser, &token_buffer);
12219 pm_newline_list_append(&parser->
newline_list, breakpoint);
12220 parser->
current.end = breakpoint + 1;
12221 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12225 parser->
current.end = breakpoint + 1;
12226 parser_flush_heredoc_end(parser);
12227 pm_regexp_token_buffer_flush(parser, &token_buffer);
12233 parser->
current.end = breakpoint + 1;
12242 pm_regexp_token_buffer_escape(parser, &token_buffer);
12243 uint8_t peeked = peek(parser);
12248 if (peek(parser) !=
'\n') {
12250 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12252 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12253 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12262 parser_flush_heredoc_end(parser);
12263 pm_regexp_token_buffer_copy(parser, &token_buffer);
12285 case '$':
case ')':
case '*':
case '+':
12286 case '.':
case '>':
case '?':
case ']':
12287 case '^':
case '|':
case '}':
12288 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12294 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12295 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12300 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12301 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12306 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12319 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12324 pm_regexp_token_buffer_flush(parser, &token_buffer);
12330 assert(
false &&
"unreachable");
12336 pm_regexp_token_buffer_flush(parser, &token_buffer);
12343 pm_regexp_token_buffer_flush(parser, &token_buffer);
12346 case PM_LEX_STRING: {
12365 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12366 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12372 while (breakpoint != NULL) {
12377 parser->
current.end = breakpoint + 1;
12378 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12383 bool is_terminator = (*breakpoint == term);
12388 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12389 if (term ==
'\n') {
12390 is_terminator =
true;
12396 if (term ==
'\r') {
12397 is_terminator =
false;
12404 if (is_terminator) {
12408 parser->
current.end = breakpoint + 1;
12409 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12416 if (breakpoint > parser->
current.start) {
12417 parser->
current.end = breakpoint;
12418 pm_token_buffer_flush(parser, &token_buffer);
12424 size_t eol_length = match_eol_at(parser, breakpoint);
12426 parser->
current.end = breakpoint + eol_length;
12429 parser->
current.end = breakpoint + 1;
12432 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12434 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12435 lex_mode_pop(parser);
12439 lex_state_set(parser, PM_LEX_STATE_END);
12440 lex_mode_pop(parser);
12444 switch (*breakpoint) {
12447 parser->
current.end = breakpoint + 1;
12448 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12451 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12452 parser->
current.end = breakpoint + 1;
12453 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12460 parser->
current.end = breakpoint;
12461 pm_token_buffer_escape(parser, &token_buffer);
12462 token_buffer.
cursor = breakpoint;
12471 pm_newline_list_append(&parser->
newline_list, breakpoint);
12472 parser->
current.end = breakpoint + 1;
12473 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12477 parser->
current.end = breakpoint + 1;
12478 parser_flush_heredoc_end(parser);
12479 pm_token_buffer_flush(parser, &token_buffer);
12483 parser->
current.end = breakpoint + 1;
12492 pm_token_buffer_escape(parser, &token_buffer);
12493 uint8_t peeked = peek(parser);
12497 pm_token_buffer_push_byte(&token_buffer,
'\\');
12502 if (peek(parser) !=
'\n') {
12504 pm_token_buffer_push_byte(&token_buffer,
'\\');
12506 pm_token_buffer_push_byte(&token_buffer,
'\r');
12512 pm_token_buffer_push_byte(&token_buffer,
'\\');
12513 pm_token_buffer_push_byte(&token_buffer,
'\n');
12520 parser_flush_heredoc_end(parser);
12521 pm_token_buffer_copy(parser, &token_buffer);
12532 pm_token_buffer_push_byte(&token_buffer, peeked);
12535 pm_token_buffer_push_byte(&token_buffer, peeked);
12538 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12540 pm_token_buffer_push_byte(&token_buffer,
'\\');
12541 pm_token_buffer_push_escaped(&token_buffer, parser);
12548 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12559 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12564 pm_token_buffer_flush(parser, &token_buffer);
12570 assert(
false &&
"unreachable");
12575 pm_token_buffer_flush(parser, &token_buffer);
12582 pm_token_buffer_flush(parser, &token_buffer);
12585 case PM_LEX_HEREDOC: {
12612 lex_state_set(parser, PM_LEX_STATE_END);
12613 lex_mode_pop(parser);
12617 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12622 if (current_token_starts_line(parser)) {
12623 const uint8_t *start = parser->
current.start;
12625 if (!line_continuation && (start + ident_length <= parser->end)) {
12626 const uint8_t *newline = next_newline(start, parser->
end - start);
12627 const uint8_t *ident_end = newline;
12628 const uint8_t *terminator_end = newline;
12630 if (newline == NULL) {
12631 terminator_end = parser->
end;
12632 ident_end = parser->
end;
12635 if (newline[-1] ==
'\r') {
12640 const uint8_t *terminator_start = ident_end - ident_length;
12641 const uint8_t *cursor = start;
12643 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12644 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12650 (cursor == terminator_start) &&
12651 (memcmp(terminator_start, ident_start, ident_length) == 0)
12653 if (newline != NULL) {
12654 pm_newline_list_append(&parser->
newline_list, newline);
12657 parser->
current.end = terminator_end;
12665 lex_state_set(parser, PM_LEX_STATE_END);
12666 lex_mode_pop(parser);
12671 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12673 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12676 peek_at(parser, start) !=
'\n'
12685 uint8_t breakpoints[] =
"\r\n\\#";
12688 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12689 breakpoints[3] =
'\0';
12692 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12694 bool was_line_continuation =
false;
12696 while (breakpoint != NULL) {
12697 switch (*breakpoint) {
12700 parser->
current.end = breakpoint + 1;
12701 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12704 parser->
current.end = breakpoint + 1;
12706 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12707 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12714 pm_token_buffer_escape(parser, &token_buffer);
12715 token_buffer.
cursor = breakpoint;
12720 parser_flush_heredoc_end(parser);
12721 parser->
current.end = breakpoint + 1;
12722 pm_token_buffer_flush(parser, &token_buffer);
12726 pm_newline_list_append(&parser->
newline_list, breakpoint);
12730 const uint8_t *start = breakpoint + 1;
12732 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12735 const uint8_t *newline = next_newline(start, parser->
end - start);
12737 if (newline == NULL) {
12738 newline = parser->
end;
12739 }
else if (newline[-1] ==
'\r') {
12744 const uint8_t *terminator_start = newline - ident_length;
12748 const uint8_t *cursor = start;
12750 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12751 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12757 cursor == terminator_start &&
12758 (memcmp(terminator_start, ident_start, ident_length) == 0)
12760 parser->
current.end = breakpoint + 1;
12761 pm_token_buffer_flush(parser, &token_buffer);
12766 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12773 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12778 parser->
current.end = breakpoint + 1;
12779 pm_token_buffer_flush(parser, &token_buffer);
12785 parser->
current.end = breakpoint + 1;
12786 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12796 parser->
current.end = breakpoint + 1;
12805 pm_token_buffer_escape(parser, &token_buffer);
12806 uint8_t peeked = peek(parser);
12808 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12812 if (peek(parser) !=
'\n') {
12813 pm_token_buffer_push_byte(&token_buffer,
'\\');
12814 pm_token_buffer_push_byte(&token_buffer,
'\r');
12819 pm_token_buffer_push_byte(&token_buffer,
'\\');
12820 pm_token_buffer_push_byte(&token_buffer,
'\n');
12822 breakpoint = parser->
current.end;
12825 pm_token_buffer_push_byte(&token_buffer,
'\\');
12826 pm_token_buffer_push_escaped(&token_buffer, parser);
12833 if (peek(parser) !=
'\n') {
12834 pm_token_buffer_push_byte(&token_buffer,
'\r');
12842 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12843 const uint8_t *end = parser->
current.end;
12848 parser->
current.end = breakpoint;
12849 pm_token_buffer_flush(parser, &token_buffer);
12853 parser->
current.end = end + 1;
12858 was_line_continuation =
true;
12860 breakpoint = parser->
current.end;
12863 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12869 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12881 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12886 pm_token_buffer_flush(parser, &token_buffer);
12892 assert(
false &&
"unreachable");
12895 was_line_continuation =
false;
12900 pm_token_buffer_flush(parser, &token_buffer);
12907 pm_token_buffer_flush(parser, &token_buffer);
12912 assert(
false &&
"unreachable");
12930 PM_BINDING_POWER_UNSET = 0,
12931 PM_BINDING_POWER_STATEMENT = 2,
12932 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12933 PM_BINDING_POWER_MODIFIER = 6,
12934 PM_BINDING_POWER_COMPOSITION = 8,
12935 PM_BINDING_POWER_NOT = 10,
12936 PM_BINDING_POWER_MATCH = 12,
12937 PM_BINDING_POWER_DEFINED = 14,
12938 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12939 PM_BINDING_POWER_ASSIGNMENT = 18,
12940 PM_BINDING_POWER_TERNARY = 20,
12941 PM_BINDING_POWER_RANGE = 22,
12942 PM_BINDING_POWER_LOGICAL_OR = 24,
12943 PM_BINDING_POWER_LOGICAL_AND = 26,
12944 PM_BINDING_POWER_EQUALITY = 28,
12945 PM_BINDING_POWER_COMPARISON = 30,
12946 PM_BINDING_POWER_BITWISE_OR = 32,
12947 PM_BINDING_POWER_BITWISE_AND = 34,
12948 PM_BINDING_POWER_SHIFT = 36,
12949 PM_BINDING_POWER_TERM = 38,
12950 PM_BINDING_POWER_FACTOR = 40,
12951 PM_BINDING_POWER_UMINUS = 42,
12952 PM_BINDING_POWER_EXPONENT = 44,
12953 PM_BINDING_POWER_UNARY = 46,
12954 PM_BINDING_POWER_INDEX = 48,
12955 PM_BINDING_POWER_CALL = 50,
12956 PM_BINDING_POWER_MAX = 52
12957} pm_binding_power_t;
12980#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12981#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12982#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12983#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12984#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
13046 [
PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13050 [
PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13051 [
PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13067 [
PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13068 [
PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13071 [
PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13079 [
PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13080 [
PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13081 [
PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13088 [
PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13092#undef BINDING_POWER_ASSIGNMENT
13093#undef LEFT_ASSOCIATIVE
13094#undef RIGHT_ASSOCIATIVE
13095#undef RIGHT_ASSOCIATIVE_UNARY
13110 return match1(parser, type1) || match1(parser, type2);
13118 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13126 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13134 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13142 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8);
13150 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);
13161 if (match1(parser,
type)) {
13162 parser_lex(parser);
13174 if (match2(parser, type1, type2)) {
13175 parser_lex(parser);
13194 if (accept1(parser,
type))
return;
13197 pm_parser_err(parser, location, location, diag_id);
13209 if (accept2(parser, type1, type2))
return;
13212 pm_parser_err(parser, location, location, diag_id);
13223expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13225 parser_lex(parser);
13227 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13234parse_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);
13241parse_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) {
13242 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13243 pm_assert_value_expression(parser, node);
13297 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13317 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13326parse_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) {
13329 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13330 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13333 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13347 size_t length = constant->
length;
13348 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13349 if (name == NULL)
return;
13351 memcpy(name, constant->
start, length);
13352 name[length] =
'=';
13357 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13369 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13370 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13371 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13372 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13373 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13374 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13375 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13382 pm_node_destroy(parser, target);
13395 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13396 if (implicit_parameters->
nodes[index] == node) {
13400 if (index != implicit_parameters->
size - 1) {
13401 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13404 implicit_parameters->
size--;
13432 return parse_unwriteable_target(parser, target);
13439 if (context_def_p(parser)) {
13440 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13448 if (context_def_p(parser)) {
13449 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13458 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13467 parse_target_implicit_parameter(parser, target);
13471 uint32_t name = cast->
name;
13472 uint32_t depth = cast->
depth;
13473 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13484 parse_target_implicit_parameter(parser, target);
13485 pm_node_destroy(parser, target);
13494 if (splat_parent) {
13497 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13522 (call->
block == NULL)
13537 pm_node_destroy(parser, target);
13539 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13544 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13547 parse_write_name(parser, &call->
name);
13548 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13556 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13564 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13575 pm_node_t *result = parse_target(parser, target, multiple,
false);
13584 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13598 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13599 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13612 pm_node_destroy(parser, value);
13616 pm_node_destroy(parser, target);
13622 if (context_def_p(parser)) {
13623 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13626 return parse_shareable_constant_write(parser, node);
13631 if (context_def_p(parser)) {
13632 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13635 pm_node_destroy(parser, target);
13636 return parse_shareable_constant_write(parser, node);
13640 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13644 pm_node_destroy(parser, target);
13653 uint32_t depth = local_read->
depth;
13654 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13657 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13659 parse_target_implicit_parameter(parser, target);
13662 pm_locals_unread(&scope->
locals, name);
13663 pm_node_destroy(parser, target);
13665 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13671 parse_target_implicit_parameter(parser, target);
13672 pm_node_destroy(parser, target);
13678 pm_node_destroy(parser, target);
13691 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13693 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13707 (call->
block == NULL)
13721 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13722 pm_node_destroy(parser, target);
13725 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13727 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13745 pm_arguments_node_arguments_append(arguments, value);
13748 parse_write_name(parser, &call->
name);
13760 call->
arguments = pm_arguments_node_create(parser);
13763 pm_arguments_node_arguments_append(call->
arguments, value);
13767 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13781 pm_node_destroy(parser, value);
13788 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13802 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13803 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13804 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13805 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13806 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13807 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13808 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13815 pm_node_destroy(parser, target);
13830parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13834 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13842 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13848 if (token_begins_expression_p(parser->
current.type)) {
13849 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13850 name = parse_target(parser, name,
true,
true);
13853 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13854 pm_multi_target_node_targets_append(parser, result, splat);
13858 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13859 target = parse_target(parser, target,
true,
false);
13861 pm_multi_target_node_targets_append(parser, result, target);
13862 context_pop(parser);
13863 }
else if (token_begins_expression_p(parser->
current.type)) {
13864 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13865 target = parse_target(parser, target,
true,
false);
13867 pm_multi_target_node_targets_append(parser, result, target);
13872 pm_multi_target_node_targets_append(parser, result, rest);
13885parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13886 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13891 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13907 if (context_terminator(context, &parser->
current))
return NULL;
13913 context_push(parser, context);
13916 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13917 pm_statements_node_body_append(parser, statements, node,
true);
13934 if (context_terminator(context, &parser->
current))
break;
13944 if (context_terminator(context, &parser->
current))
break;
13957 parser_lex(parser);
13969 if (context_terminator(context, &parser->
current))
break;
13980 context_pop(parser);
13981 bool last_value =
true;
13985 last_value =
false;
13990 pm_void_statements_check(parser, statements, last_value);
14003 if (duplicated != NULL) {
14007 pm_diagnostic_list_append_format(
14011 PM_WARN_DUPLICATED_HASH_KEY,
14012 (
int) pm_buffer_length(&buffer),
14013 pm_buffer_value(&buffer),
14017 pm_buffer_free(&buffer);
14029 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14030 pm_diagnostic_list_append_format(
14034 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14047 bool contains_keyword_splat =
false;
14052 switch (parser->
current.type) {
14054 parser_lex(parser);
14064 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14065 }
else if (token_begins_expression_p(parser->
current.type)) {
14066 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14068 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14071 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14072 contains_keyword_splat =
true;
14077 parser_lex(parser);
14080 pm_hash_key_static_literals_add(parser, literals, key);
14085 if (token_begins_expression_p(parser->
current.type)) {
14086 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14090 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14095 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14096 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14098 depth = pm_parser_local_depth(parser, &identifier);
14102 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14104 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14109 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14112 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14116 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14124 pm_hash_key_static_literals_add(parser, literals, key);
14127 if (pm_symbol_node_label_p(key)) {
14128 operator = not_provided(parser);
14134 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14135 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14155 if (token_begins_expression_p(parser->
current.type))
continue;
14161 return contains_keyword_splat;
14170 arguments->
arguments = pm_arguments_node_create(parser);
14173 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14181 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
14187 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14193 bool parsed_first_argument =
false;
14194 bool parsed_bare_hash =
false;
14195 bool parsed_block_argument =
false;
14196 bool parsed_forwarding_arguments =
false;
14199 if (parsed_forwarding_arguments) {
14200 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14205 switch (parser->
current.type) {
14208 if (parsed_bare_hash) {
14209 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14216 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14218 parse_arguments_append(parser, arguments, argument);
14224 pm_static_literals_free(&hash_keys);
14225 parsed_bare_hash =
true;
14230 parser_lex(parser);
14234 if (token_begins_expression_p(parser->
current.type)) {
14235 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14237 pm_parser_scope_forwarding_block_check(parser, &
operator);
14240 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14241 if (parsed_block_argument) {
14242 parse_arguments_append(parser, arguments, argument);
14244 arguments->
block = argument;
14248 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14251 parsed_block_argument =
true;
14255 parser_lex(parser);
14259 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14260 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14261 if (parsed_bare_hash) {
14262 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14265 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14267 if (parsed_bare_hash) {
14268 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14271 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14274 parse_arguments_append(parser, arguments, argument);
14278 if (accepts_forwarding) {
14279 parser_lex(parser);
14281 if (token_begins_expression_p(parser->
current.type)) {
14286 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14293 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14296 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14298 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14299 if (parsed_first_argument && terminator ==
PM_TOKEN_EOF) {
14300 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14303 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14304 parse_arguments_append(parser, arguments, argument);
14307 parsed_forwarding_arguments =
true;
14314 if (argument == NULL) {
14315 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14318 bool contains_keywords =
false;
14319 bool contains_keyword_splat =
false;
14322 if (parsed_bare_hash) {
14323 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14330 operator = not_provided(parser);
14334 contains_keywords =
true;
14338 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14341 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14342 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14344 pm_keyword_hash_node_elements_append(bare_hash, argument);
14349 token_begins_expression_p(parser->
current.type) ||
14352 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14355 pm_static_literals_free(&hash_keys);
14356 parsed_bare_hash =
true;
14359 parse_arguments_append(parser, arguments, argument);
14370 parsed_first_argument =
true;
14378 bool accepted_newline =
false;
14390 if (accepted_newline) {
14391 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14401 if (match1(parser, terminator))
break;
14416parse_required_destructured_parameter(
pm_parser_t *parser) {
14420 pm_multi_target_node_opening_set(node, &parser->
previous);
14431 pm_multi_target_node_targets_append(parser, node, param);
14432 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14437 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14444 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14445 if (pm_parser_parameter_name_check(parser, &name)) {
14446 pm_node_flag_set_repeated_parameter(value);
14448 pm_parser_local_add_token(parser, &name, 1);
14451 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14456 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14457 if (pm_parser_parameter_name_check(parser, &name)) {
14458 pm_node_flag_set_repeated_parameter(param);
14460 pm_parser_local_add_token(parser, &name, 1);
14463 pm_multi_target_node_targets_append(parser, node, param);
14468 pm_multi_target_node_closing_set(node, &parser->
previous);
14478 PM_PARAMETERS_NO_CHANGE = 0,
14479 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14480 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14481 PM_PARAMETERS_ORDER_KEYWORDS,
14482 PM_PARAMETERS_ORDER_REST,
14483 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14484 PM_PARAMETERS_ORDER_OPTIONAL,
14485 PM_PARAMETERS_ORDER_NAMED,
14486 PM_PARAMETERS_ORDER_NONE,
14487} pm_parameters_order_t;
14493 [0] = PM_PARAMETERS_NO_CHANGE,
14516 pm_parameters_order_t state = parameters_ordering[token->type];
14517 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14521 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14522 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14524 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14528 if (token->type ==
PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14529 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14531 }
else if (token->type ==
PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14532 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14534 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14536 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14540 if (state < *current) *current = state;
14550 pm_binding_power_t binding_power,
14551 bool uses_parentheses,
14552 bool allows_trailing_comma,
14553 bool allows_forwarding_parameters,
14554 bool accepts_blocks_in_defaults,
14558 pm_do_loop_stack_push(parser,
false);
14561 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14564 bool parsing =
true;
14566 switch (parser->
current.type) {
14568 update_parameter_state(parser, &parser->
current, &order);
14571 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14572 pm_parameters_node_requireds_append(params, param);
14574 pm_parameters_node_posts_append(params, param);
14580 update_parameter_state(parser, &parser->
current, &order);
14581 parser_lex(parser);
14586 bool repeated =
false;
14589 repeated = pm_parser_parameter_name_check(parser, &name);
14590 pm_parser_local_add_token(parser, &name, 1);
14592 name = not_provided(parser);
14598 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14600 if (params->
block == NULL) {
14601 pm_parameters_node_block_set(params, param);
14603 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14604 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14610 if (!allows_forwarding_parameters) {
14611 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14614 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14615 parser_lex(parser);
14624 pm_parameters_node_posts_append(params, keyword_rest);
14625 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14629 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14638 parser_lex(parser);
14641 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14644 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14647 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14650 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14653 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14659 update_parameter_state(parser, &parser->
current, &order);
14661 update_parameter_state(parser, &parser->
previous, &order);
14665 bool repeated = pm_parser_parameter_name_check(parser, &name);
14666 pm_parser_local_add_token(parser, &name, 1);
14671 parser_lex(parser);
14676 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14677 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14678 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14683 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14685 pm_parameters_node_optionals_append(params, param);
14691 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14694 context_pop(parser);
14703 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14706 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14708 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14712 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14714 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14720 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14721 update_parameter_state(parser, &parser->
current, &order);
14724 parser_lex(parser);
14731 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14732 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14733 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14736 bool repeated = pm_parser_parameter_name_check(parser, &local);
14737 pm_parser_local_add_token(parser, &local, 1);
14739 switch (parser->
current.type) {
14743 context_pop(parser);
14745 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14747 pm_node_flag_set_repeated_parameter(param);
14750 pm_parameters_node_keywords_append(params, param);
14755 context_pop(parser);
14757 if (uses_parentheses) {
14762 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14764 pm_node_flag_set_repeated_parameter(param);
14767 pm_parameters_node_keywords_append(params, param);
14773 if (token_begins_expression_p(parser->
current.type)) {
14777 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14778 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14779 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14782 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14785 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14788 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14792 pm_node_flag_set_repeated_parameter(param);
14795 context_pop(parser);
14796 pm_parameters_node_keywords_append(params, param);
14813 update_parameter_state(parser, &parser->
current, &order);
14814 parser_lex(parser);
14818 bool repeated =
false;
14822 repeated = pm_parser_parameter_name_check(parser, &name);
14823 pm_parser_local_add_token(parser, &name, 1);
14825 name = not_provided(parser);
14829 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14831 pm_node_flag_set_repeated_parameter(param);
14834 if (params->
rest == NULL) {
14835 pm_parameters_node_rest_set(params, param);
14837 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14838 pm_parameters_node_posts_append(params, param);
14845 pm_parameters_order_t previous_order = order;
14846 update_parameter_state(parser, &parser->
current, &order);
14847 parser_lex(parser);
14853 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14854 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14857 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14861 bool repeated =
false;
14864 repeated = pm_parser_parameter_name_check(parser, &name);
14865 pm_parser_local_add_token(parser, &name, 1);
14867 name = not_provided(parser);
14871 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14873 pm_node_flag_set_repeated_parameter(param);
14878 pm_parameters_node_keyword_rest_set(params, param);
14880 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14881 pm_parameters_node_posts_append(params, param);
14888 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14893 if (params->
rest == NULL) {
14894 pm_parameters_node_rest_set(params, param);
14896 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14897 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14900 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14911 if (!parsing)
break;
14913 bool accepted_newline =
false;
14914 if (uses_parentheses) {
14921 if (accepted_newline) {
14922 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14930 pm_do_loop_stack_pop(parser);
14934 pm_node_destroy(parser, (
pm_node_t *) params);
14966token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14968 const uint8_t *end = token->start;
14972 newline_index == 0 &&
14973 parser->
start[0] == 0xef &&
14974 parser->
start[1] == 0xbb &&
14975 parser->
start[2] == 0xbf
14978 int64_t column = 0;
14979 for (; cursor < end; cursor++) {
14982 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14989 if (break_on_non_space)
return -1;
15002parser_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) {
15007 size_t closing_newline_index = token_newline_index(parser);
15008 if (opening_newline_index == closing_newline_index)
return;
15013 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15014 if (!if_after_else && (opening_column == -1))
return;
15021 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15022 if ((closing_column == -1) || (opening_column == closing_column))
return;
15026 if (allow_indent && (closing_column > opening_column))
return;
15029 PM_PARSER_WARN_FORMAT(
15031 closing_token->
start,
15032 closing_token->
end,
15033 PM_WARN_INDENTATION_MISMATCH,
15034 (
int) (closing_token->
end - closing_token->
start),
15035 (
const char *) closing_token->
start,
15036 (
int) (opening_token->
end - opening_token->
start),
15037 (
const char *) opening_token->
start,
15038 ((int32_t) opening_newline_index) + parser->
start_line
15043 PM_RESCUES_BEGIN = 1,
15050} pm_rescues_type_t;
15061 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15062 parser_lex(parser);
15066 switch (parser->
current.type) {
15071 parser_lex(parser);
15072 pm_rescue_node_operator_set(rescue, &parser->
previous);
15074 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15075 reference = parse_target(parser, reference,
false,
false);
15077 pm_rescue_node_reference_set(rescue, reference);
15092 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15093 pm_rescue_node_exceptions_append(rescue, expression);
15102 pm_rescue_node_operator_set(rescue, &parser->
previous);
15104 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15105 reference = parse_target(parser, reference,
false,
false);
15107 pm_rescue_node_reference_set(rescue, reference);
15125 pm_accepts_block_stack_push(parser,
true);
15140 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15142 pm_accepts_block_stack_pop(parser);
15146 if (current == NULL) {
15147 pm_begin_node_rescue_clause_set(parent_node, rescue);
15149 pm_rescue_node_subsequent_set(current, rescue);
15158 if (current != NULL) {
15162 while (clause != NULL) {
15170 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15171 opening_newline_index = token_newline_index(parser);
15173 else_keyword = parser->
current;
15174 opening = &else_keyword;
15176 parser_lex(parser);
15181 pm_accepts_block_stack_push(parser,
true);
15195 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15196 pm_accepts_block_stack_pop(parser);
15201 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15202 pm_begin_node_else_clause_set(parent_node, else_clause);
15206 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15210 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15213 parser_lex(parser);
15218 pm_accepts_block_stack_push(parser,
true);
15232 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15233 pm_accepts_block_stack_pop(parser);
15238 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15239 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15243 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15244 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15247 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15257 pm_token_t begin_keyword = not_provided(parser);
15258 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15260 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15270parse_block_parameters(
15272 bool allows_trailing_comma,
15274 bool is_lambda_literal,
15275 bool accepts_blocks_in_defaults,
15280 parameters = parse_parameters(
15282 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15284 allows_trailing_comma,
15286 accepts_blocks_in_defaults,
15288 (uint16_t) (depth + 1)
15298 switch (parser->
current.type) {
15300 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15301 parser_lex(parser);
15304 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15305 parser_lex(parser);
15308 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15309 parser_lex(parser);
15312 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15313 parser_lex(parser);
15320 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15321 pm_parser_local_add_token(parser, &parser->
previous, 1);
15324 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15326 pm_block_parameters_node_append_local(block_parameters, local);
15331 return block_parameters;
15339outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15341 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15352static const char *
const pm_numbered_parameter_names[] = {
15353 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15367 if (parameters != NULL) {
15369 if (implicit_parameters->
size > 0) {
15373 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15375 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15377 assert(
false &&
"unreachable");
15386 if (implicit_parameters->
size == 0) {
15393 uint8_t numbered_parameter = 0;
15394 bool it_parameter =
false;
15396 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15400 if (it_parameter) {
15401 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15402 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15403 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15405 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15407 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15409 assert(
false &&
"unreachable");
15412 if (numbered_parameter > 0) {
15413 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15415 it_parameter =
true;
15420 if (numbered_parameter > 0) {
15424 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15428 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15431 if (it_parameter) {
15432 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15442parse_block(
pm_parser_t *parser, uint16_t depth) {
15446 pm_accepts_block_stack_push(parser,
true);
15447 pm_parser_scope_push(parser,
false);
15454 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15456 parser_lex(parser);
15458 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15461 expect1(parser,
PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15464 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15479 pm_accepts_block_stack_push(parser,
true);
15481 pm_accepts_block_stack_pop(parser);
15486 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));
15494 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15497 pm_parser_scope_pop(parser);
15498 pm_accepts_block_stack_pop(parser);
15500 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15509parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15510 bool found =
false;
15519 pm_accepts_block_stack_push(parser,
true);
15528 pm_accepts_block_stack_pop(parser);
15533 pm_accepts_block_stack_push(parser,
false);
15538 parse_arguments(parser, arguments, accepts_block,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
15547 pm_accepts_block_stack_pop(parser);
15553 if (accepts_block) {
15558 block = parse_block(parser, (uint16_t) (depth + 1));
15559 pm_arguments_validate_block(parser, arguments, block);
15562 block = parse_block(parser, (uint16_t) (depth + 1));
15565 if (block != NULL) {
15569 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15571 if (arguments->
block != NULL) {
15573 arguments->
arguments = pm_arguments_node_create(parser);
15575 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15591 bool in_sclass =
false;
15593 switch (context_node->
context) {
15638 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15660 assert(
false &&
"unreachable");
15665 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15676 switch (context_node->
context) {
15750 assert(
false &&
"unreachable");
15764 return previous_block_exits;
15782 default: assert(
false &&
"unreachable");
type =
"";
break;
15785 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15802 }
else if (previous_block_exits != NULL) {
15814 flush_block_exits(parser, previous_block_exits);
15822 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15828 predicate_closed =
true;
15832 if (!predicate_closed) {
15833 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15836 context_pop(parser);
15841parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15843 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15846 pm_token_t then_keyword = not_provided(parser);
15848 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15852 pm_accepts_block_stack_push(parser,
true);
15853 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15854 pm_accepts_block_stack_pop(parser);
15858 pm_token_t end_keyword = not_provided(parser);
15863 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15866 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15869 assert(
false &&
"unreachable");
15879 if (parser_end_of_line_p(parser)) {
15880 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15883 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15885 parser_lex(parser);
15887 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15888 pm_accepts_block_stack_push(parser,
true);
15891 pm_accepts_block_stack_pop(parser);
15894 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15901 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15902 opening_newline_index = token_newline_index(parser);
15904 parser_lex(parser);
15907 pm_accepts_block_stack_push(parser,
true);
15909 pm_accepts_block_stack_pop(parser);
15912 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15915 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15925 assert(
false &&
"unreachable");
15929 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15937 bool recursing =
true;
15939 while (recursing) {
15944 recursing = current != NULL;
15962 assert(
false &&
"unreachable");
15966 pop_block_exits(parser, previous_block_exits);
15967 pm_node_list_free(¤t_block_exits);
15976#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15977 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15978 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15979 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15980 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15981 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15982 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15983 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15984 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15985 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15986 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15992#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15993 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15994 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15995 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15996 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15997 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15998 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15999 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16006#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16007 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16008 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16009 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16010 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16011 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16012 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16013 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16014 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16020#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16021 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16022 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16023 case PM_TOKEN_CLASS_VARIABLE
16029#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16030 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16031 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16032 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16043parse_unescaped_encoding(
const pm_parser_t *parser) {
16065parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16066 switch (parser->
current.type) {
16078 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16080 parser_lex(parser);
16098 lex_state_set(parser, PM_LEX_STATE_BEG);
16099 parser_lex(parser);
16105 pm_accepts_block_stack_push(parser,
true);
16107 pm_accepts_block_stack_pop(parser);
16111 lex_state_set(parser, state);
16119 if (statements != NULL && statements->
body.
size == 1) {
16123 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16137 lex_state_set(parser, PM_LEX_STATE_BEG);
16138 parser_lex(parser);
16143 switch (parser->
current.type) {
16147 parser_lex(parser);
16148 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16153 parser_lex(parser);
16154 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16159 parser_lex(parser);
16160 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16165 parser_lex(parser);
16166 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16171 parser_lex(parser);
16172 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16183 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16186 parser_lex(parser);
16187 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16197static const uint8_t *
16198parse_operator_symbol_name(
const pm_token_t *name) {
16199 switch (name->type) {
16202 if (name->end[-1] ==
'@')
return name->end - 1;
16214 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16216 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16217 parser_lex(parser);
16234 if (lex_mode->
mode != PM_LEX_STRING) {
16235 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16237 switch (parser->
current.type) {
16238 case PM_CASE_OPERATOR:
16239 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16248 case PM_CASE_KEYWORD:
16249 parser_lex(parser);
16260 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16268 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16269 parser_lex(parser);
16273 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16277 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16282 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16289 if (part) pm_interpolated_symbol_node_append(symbol, part);
16292 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16293 pm_interpolated_symbol_node_append(symbol, part);
16297 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16299 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16304 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16314 parser_lex(parser);
16329 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16330 pm_interpolated_symbol_node_append(symbol, part);
16333 pm_interpolated_symbol_node_append(symbol, part);
16335 if (next_state != PM_LEX_STATE_NONE) {
16336 lex_state_set(parser, next_state);
16339 parser_lex(parser);
16342 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16347 pm_string_shared_init(&unescaped, content.
start, content.
end);
16350 if (next_state != PM_LEX_STATE_NONE) {
16351 lex_state_set(parser, next_state);
16355 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16360 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16368parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16369 switch (parser->
current.type) {
16370 case PM_CASE_OPERATOR: {
16371 const pm_token_t opening = not_provided(parser);
16372 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16374 case PM_CASE_KEYWORD:
16378 parser_lex(parser);
16385 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16391 parser_lex(parser);
16393 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16396 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16408parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16409 switch (parser->
current.type) {
16410 case PM_CASE_OPERATOR: {
16411 const pm_token_t opening = not_provided(parser);
16412 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16414 case PM_CASE_KEYWORD:
16418 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16419 parser_lex(parser);
16426 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16432 parser_lex(parser);
16434 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16437 parser_lex(parser);
16438 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16440 parser_lex(parser);
16441 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16443 parser_lex(parser);
16444 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16446 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16461 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16462 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16466 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16467 if (is_numbered_param) {
16472 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16473 for (uint8_t number = 1; number <= maximum; number++) {
16474 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16481 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16504 pm_node_t *node = parse_variable(parser);
16505 if (node != NULL)
return node;
16510 pm_node_flag_set((
pm_node_t *)node, flags);
16521parse_method_definition_name(
pm_parser_t *parser) {
16522 switch (parser->
current.type) {
16523 case PM_CASE_KEYWORD:
16526 parser_lex(parser);
16529 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16530 parser_lex(parser);
16532 case PM_CASE_OPERATOR:
16533 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16534 parser_lex(parser);
16543parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16546 pm_string_ensure_owned(
string);
16551 size_t dest_length = pm_string_length(
string);
16552 const uint8_t *source_cursor = (uint8_t *) string->
source;
16553 const uint8_t *source_end = source_cursor + dest_length;
16558 size_t trimmed_whitespace = 0;
16564 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16565 if (*source_cursor ==
'\t') {
16566 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16567 if (trimmed_whitespace > common_whitespace)
break;
16569 trimmed_whitespace++;
16576 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16577 string->length = dest_length;
16587 bool dedent_next =
true;
16592 size_t write_index = 0;
16600 nodes->
nodes[write_index++] = node;
16601 dedent_next =
false;
16607 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16611 pm_node_destroy(parser, node);
16613 nodes->
nodes[write_index++] = node;
16617 dedent_next =
true;
16620 nodes->
size = write_index;
16627parse_strings_empty_content(
const uint8_t *location) {
16637 bool concating =
false;
16645 assert(lex_mode->
mode == PM_LEX_STRING);
16647 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16650 parser_lex(parser);
16672 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16673 }
else if (!lex_interpolation) {
16681 content = not_provided(parser);
16702 pm_token_t delimiters = not_provided(parser);
16703 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16704 pm_node_list_append(&parts, part);
16707 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16708 pm_node_list_append(&parts, part);
16709 parser_lex(parser);
16713 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16715 pm_node_list_free(&parts);
16717 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16718 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16720 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16721 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16723 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16728 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16737 parser_lex(parser);
16740 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16741 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16749 if (location > parser->
start && location[-1] ==
'\n') location--;
16750 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16756 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16757 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16762 pm_token_t string_opening = not_provided(parser);
16763 pm_token_t string_closing = not_provided(parser);
16765 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16766 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16767 pm_node_list_append(&parts, part);
16770 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16771 pm_node_list_append(&parts, part);
16776 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16777 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16779 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16780 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16783 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16786 pm_node_list_free(&parts);
16796 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16797 pm_node_list_append(&parts, part);
16802 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16803 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16805 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16806 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16809 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16812 pm_node_list_free(&parts);
16815 if (current == NULL) {
16831 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16838 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16845 pm_interpolated_string_node_append(container, current);
16856#define PM_PARSE_PATTERN_SINGLE 0
16857#define PM_PARSE_PATTERN_TOP 1
16858#define PM_PARSE_PATTERN_MULTI 2
16871 if (*location->
start ==
'_')
return;
16873 if (pm_constant_id_list_includes(captures, capture)) {
16874 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16876 pm_constant_id_list_append(captures, capture);
16890 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16909 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16916 parser_lex(parser);
16921 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16932 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16948 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16949 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16964 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16965 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16980 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16981 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16995 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16996 pm_array_pattern_node_requireds_append(pattern_node, inner);
17014 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
17017 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17018 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
17021 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
17022 name = (
pm_node_t *) pm_local_variable_target_node_create(
17024 &PM_LOCATION_TOKEN_VALUE(&identifier),
17026 (uint32_t) (depth == -1 ? 0 : depth)
17031 return pm_splat_node_create(parser, &
operator, name);
17040 parser_lex(parser);
17046 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17053 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17057 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17058 value = (
pm_node_t *) pm_local_variable_target_node_create(
17060 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17062 (uint32_t) (depth == -1 ? 0 : depth)
17066 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17074pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17075 ptrdiff_t length = end - start;
17076 if (length == 0)
return false;
17079 size_t width = char_is_identifier_start(parser, start, end - start);
17080 if (width == 0)
return false;
17086 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17091 const uint8_t *cursor = start + width;
17092 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17093 return cursor == end;
17107 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17108 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17110 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17112 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17113 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);
17118 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17121 parse_pattern_capture(parser, captures, constant_id, value_loc);
17126 (uint32_t) (depth == -1 ? 0 : depth)
17139 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17158 if (pm_symbol_node_label_p(first_node)) {
17159 parse_pattern_hash_key(parser, &keys, first_node);
17165 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17169 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17173 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17175 pm_node_list_append(&assocs, assoc);
17185 pm_parser_err_node(parser, first_node, diag_id);
17189 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17191 pm_node_list_append(&assocs, assoc);
17201 if (rest != NULL) {
17202 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17209 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17211 if (rest == NULL) {
17214 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17215 pm_node_list_append(&assocs, assoc);
17221 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17224 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17225 }
else if (!pm_symbol_node_label_p(key)) {
17226 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17229 expect1(parser,
PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17233 parse_pattern_hash_key(parser, &keys, key);
17237 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17239 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17243 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17245 if (rest != NULL) {
17246 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17249 pm_node_list_append(&assocs, assoc);
17256 pm_static_literals_free(&keys);
17265 switch (parser->
current.type) {
17268 parser_lex(parser);
17272 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17276 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17277 return (
pm_node_t *) pm_local_variable_target_node_create(
17279 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17281 (uint32_t) (depth == -1 ? 0 : depth)
17286 parser_lex(parser);
17291 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17296 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17309 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17310 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17323 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17324 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17336 pm_array_pattern_node_requireds_append(node, inner);
17345 parser_lex(parser);
17350 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17354 switch (parser->
current.type) {
17356 parser_lex(parser);
17357 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17360 first_node = parse_pattern_keyword_rest(parser, captures);
17363 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17367 parser_lex(parser);
17374 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17383 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17384 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17393 parser_lex(parser);
17397 switch (parser->
current.type) {
17398 case PM_CASE_PRIMITIVE: {
17399 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17400 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17403 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17404 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17405 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17409 case PM_CASE_PRIMITIVE: {
17410 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17413 if (pm_symbol_node_label_p(node))
return node;
17422 switch (parser->
current.type) {
17423 case PM_CASE_PRIMITIVE: {
17424 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17425 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17428 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17435 parser_lex(parser);
17440 switch (parser->
current.type) {
17442 parser_lex(parser);
17445 if (variable == NULL) {
17446 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17447 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17450 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17453 parser_lex(parser);
17456 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17459 parser_lex(parser);
17462 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17465 parser_lex(parser);
17468 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17471 parser_lex(parser);
17474 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17477 parser_lex(parser);
17480 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17487 parser_lex(parser);
17489 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17494 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17499 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17500 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17501 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17507 parser_lex(parser);
17512 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17516 parser_lex(parser);
17519 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17522 pm_parser_err_current(parser, diag_id);
17538 switch (parser->
current.type) {
17547 case PM_CASE_PRIMITIVE: {
17548 if (node == NULL) {
17549 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17551 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17552 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17560 parser_lex(parser);
17562 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17567 if (node == NULL) {
17570 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17576 pm_parser_err_current(parser, diag_id);
17579 if (node == NULL) {
17582 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17599 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17603 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17606 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17608 (uint32_t) (depth == -1 ? 0 : depth)
17611 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17624 bool leading_rest =
false;
17625 bool trailing_rest =
false;
17627 switch (parser->
current.type) {
17629 parser_lex(parser);
17631 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17633 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17634 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17640 node = parse_pattern_keyword_rest(parser, captures);
17641 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17643 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17644 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17652 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17654 if (pm_symbol_node_label_p(node)) {
17655 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17657 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17658 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17664 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17668 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17669 parser_lex(parser);
17670 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17671 leading_rest =
true;
17677 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17683 if (pm_symbol_node_label_p(node)) {
17684 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17687 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser,
PM_TOKEN_COMMA)) {
17692 pm_node_list_append(&nodes, node);
17699 pm_node_list_append(&nodes, node);
17700 trailing_rest =
true;
17705 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17710 if (trailing_rest) {
17711 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17714 trailing_rest =
true;
17716 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17719 pm_node_list_append(&nodes, node);
17727 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17729 if (nodes.
size == 2) {
17730 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17733 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17735 if (leading_rest && trailing_rest) {
17736 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17741 }
else if (leading_rest) {
17744 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17756parse_negative_numeric(
pm_node_t *node) {
17781 assert(
false &&
"unreachable");
17794 case PM_ERR_HASH_KEY: {
17798 case PM_ERR_HASH_VALUE:
17799 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17803 case PM_ERR_UNARY_RECEIVER: {
17808 case PM_ERR_UNARY_DISALLOWED:
17809 case PM_ERR_EXPECT_ARGUMENT: {
17814 pm_parser_err_previous(parser, diag_id);
17824#define CONTEXT_NONE 0
17825#define CONTEXT_THROUGH_ENSURE 1
17826#define CONTEXT_THROUGH_ELSE 2
17829 int context = CONTEXT_NONE;
17831 while (context_node != NULL) {
17832 switch (context_node->
context) {
17853 if (context == CONTEXT_NONE) {
17854 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17855 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17856 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17857 }
else if (context == CONTEXT_THROUGH_ELSE) {
17858 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17870 context = CONTEXT_THROUGH_ELSE;
17881 context = CONTEXT_THROUGH_ENSURE;
17885 assert(
false &&
"unreachable");
17915 context_node = context_node->
prev;
17919#undef CONTEXT_ENSURE
17930 while (context_node != NULL) {
17931 switch (context_node->
context) {
17956 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17960 assert(
false &&
"unreachable");
18001 context_node = context_node->
prev;
18033parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18037 if (callback_data->
shared) {
18043 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18056 .shared = unescaped->
type == PM_STRING_SHARED
18066parse_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) {
18067 switch (parser->
current.type) {
18069 parser_lex(parser);
18072 pm_accepts_block_stack_push(parser,
true);
18073 bool parsed_bare_hash =
false;
18089 if (accepted_newline) {
18090 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18115 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18117 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18120 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18122 if (parsed_bare_hash) {
18123 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18126 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18130 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18133 pm_static_literals_free(&hash_keys);
18134 parsed_bare_hash =
true;
18136 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18139 if (parsed_bare_hash) {
18140 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18145 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18151 operator = not_provided(parser);
18154 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18155 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18156 pm_keyword_hash_node_elements_append(hash, assoc);
18160 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18163 pm_static_literals_free(&hash_keys);
18164 parsed_bare_hash =
true;
18168 pm_array_node_elements_append(array, element);
18180 pm_array_node_close_set(array, &parser->
previous);
18181 pm_accepts_block_stack_pop(parser);
18191 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18193 parser_lex(parser);
18207 pop_block_exits(parser, previous_block_exits);
18208 pm_node_list_free(¤t_block_exits);
18210 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags);
18215 pm_accepts_block_stack_push(parser,
true);
18217 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18218 context_pop(parser);
18223 bool terminator_found =
false;
18226 terminator_found =
true;
18229 terminator_found =
true;
18232 if (terminator_found) {
18247 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18250 parser_lex(parser);
18251 pm_accepts_block_stack_pop(parser);
18253 pop_block_exits(parser, previous_block_exits);
18254 pm_node_list_free(¤t_block_exits);
18265 multi_target = pm_multi_target_node_create(parser);
18266 pm_multi_target_node_targets_append(parser, multi_target, statement);
18269 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18278 if (match1(parser,
PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18279 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18291 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18294 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18299 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18309 pm_statements_node_body_append(parser, statements, statement,
true);
18321 pm_statements_node_body_append(parser, statements, statement,
true);
18325 if (!terminator_found && !match1(parser,
PM_TOKEN_EOF)) {
18331 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18332 pm_statements_node_body_append(parser, statements, node,
true);
18361 context_pop(parser);
18362 pm_accepts_block_stack_pop(parser);
18374 pm_multi_target_node_targets_append(parser, multi_target, statement);
18376 statement = (
pm_node_t *) multi_target;
18388 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18392 pop_block_exits(parser, previous_block_exits);
18393 pm_node_list_free(¤t_block_exits);
18395 pm_void_statements_check(parser, statements,
true);
18409 pm_accepts_block_stack_push(parser,
true);
18410 parser_lex(parser);
18415 if (current_hash_keys != NULL) {
18416 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18419 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18420 pm_static_literals_free(&hash_keys);
18426 pm_accepts_block_stack_pop(parser);
18428 pm_hash_node_closing_loc_set(node, &parser->
previous);
18433 parser_lex(parser);
18444 pm_node_t *node = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18445 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18450 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18456 parser_lex(parser);
18459 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18460 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18466 parser_lex(parser);
18478 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18479 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18484 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18487 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18493 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));
18508 parser_lex(parser);
18510 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));
18517 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18520 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18523 parser_lex(parser);
18526 parser_lex(parser);
18527 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18529 parser_lex(parser);
18532 parser_lex(parser);
18533 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18535 parser_lex(parser);
18538 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18539 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18545 parser_lex(parser);
18548 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18549 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18555 parser_lex(parser);
18558 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18559 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18566 parser_lex(parser);
18568 pm_node_t *node = parse_variable_call(parser);
18578 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18588 if (arguments.
block != NULL) {
18610 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18611 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18617 parse_target_implicit_parameter(parser, node);
18625 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18626 parse_target_implicit_parameter(parser, node);
18629 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
18633 pm_node_destroy(parser, node);
18638 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18639 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18650 size_t common_whitespace = (size_t) -1;
18653 parser_lex(parser);
18665 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18672 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18685 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18688 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18692 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18697 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18698 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18708 pm_node_list_append(&parts, part);
18711 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18712 pm_node_list_append(&parts, part);
18718 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18720 cast->
parts = parts;
18723 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18729 pm_node_list_free(&parts);
18732 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18740 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18742 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18748 parse_heredoc_dedent(parser, nodes, common_whitespace);
18753 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18759 parser_lex(parser);
18762 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18763 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18770 parser_lex(parser);
18775 parser_lex(parser);
18776 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18780 parser_lex(parser);
18781 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18785 parser_lex(parser);
18786 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18789 parser_lex(parser);
18790 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18792 parser_lex(parser);
18795 parser_lex(parser);
18798 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18799 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18802 parser_lex(parser);
18805 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18806 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18814 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18817 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18820 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18825 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18830 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18834 size_t opening_newline_index = token_newline_index(parser);
18835 parser_lex(parser);
18841 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18848 }
else if (!token_begins_expression_p(parser->
current.type)) {
18851 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18856 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18857 parser_lex(parser);
18859 pop_block_exits(parser, previous_block_exits);
18860 pm_node_list_free(¤t_block_exits);
18862 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18863 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18868 pm_token_t end_keyword = not_provided(parser);
18872 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18879 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18880 parser_lex(parser);
18883 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18888 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18890 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18891 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18895 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18896 pm_when_node_conditions_append(when_node, condition);
18907 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18910 pm_when_clause_static_literals_add(parser, &literals, condition);
18916 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18920 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18925 if (statements != NULL) {
18926 pm_when_node_statements_set(when_node, statements);
18930 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18936 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18939 pm_static_literals_free(&literals);
18942 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18946 if (predicate == NULL) {
18947 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18954 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18959 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18961 parser_lex(parser);
18966 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));
18969 pm_constant_id_list_free(&captures);
18976 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18977 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
18980 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18981 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
18992 then_keyword = not_provided(parser);
19010 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
19011 pm_case_match_node_condition_append(case_node, condition);
19017 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
19029 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
19031 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
19035 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
19041 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
19050 pop_block_exits(parser, previous_block_exits);
19051 pm_node_list_free(¤t_block_exits);
19056 size_t opening_newline_index = token_newline_index(parser);
19057 parser_lex(parser);
19063 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19067 pm_accepts_block_stack_push(parser,
true);
19068 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19069 pm_accepts_block_stack_pop(parser);
19073 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19074 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19078 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19080 pop_block_exits(parser, previous_block_exits);
19081 pm_node_list_free(¤t_block_exits);
19087 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19089 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19090 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19093 parser_lex(parser);
19103 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19106 flush_block_exits(parser, previous_block_exits);
19107 pm_node_list_free(¤t_block_exits);
19109 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19114 parser_lex(parser);
19120 token_begins_expression_p(parser->
current.type) ||
19123 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
19125 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19126 parse_arguments(parser, &arguments,
false,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
19130 switch (keyword.
type) {
19143 parse_return(parser, node);
19147 assert(
false &&
"unreachable");
19152 parser_lex(parser);
19156 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19163 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19166 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19169 parser_lex(parser);
19173 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19179 if (arguments.
block != NULL) {
19180 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19181 pm_node_destroy(parser, arguments.
block);
19182 arguments.
block = NULL;
19191 size_t opening_newline_index = token_newline_index(parser);
19192 parser_lex(parser);
19195 pm_do_loop_stack_push(parser,
false);
19198 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19202 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));
19204 pm_parser_scope_push(parser,
true);
19211 pm_accepts_block_stack_push(parser,
true);
19213 pm_accepts_block_stack_pop(parser);
19218 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));
19220 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19228 pm_parser_scope_pop(parser);
19229 pm_do_loop_stack_pop(parser);
19231 flush_block_exits(parser, previous_block_exits);
19232 pm_node_list_free(¤t_block_exits);
19234 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19237 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19240 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19247 inheritance_operator = parser->
current;
19248 lex_state_set(parser, PM_LEX_STATE_BEG);
19251 parser_lex(parser);
19253 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19255 inheritance_operator = not_provided(parser);
19259 pm_parser_scope_push(parser,
true);
19269 pm_accepts_block_stack_push(parser,
true);
19271 pm_accepts_block_stack_pop(parser);
19276 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));
19278 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19283 if (context_def_p(parser)) {
19284 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19290 pm_parser_scope_pop(parser);
19291 pm_do_loop_stack_pop(parser);
19294 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19297 pop_block_exits(parser, previous_block_exits);
19298 pm_node_list_free(¤t_block_exits);
19300 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19304 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19307 size_t opening_newline_index = token_newline_index(parser);
19317 parser_lex(parser);
19321 bool valid_name =
true;
19323 switch (parser->
current.type) {
19324 case PM_CASE_OPERATOR:
19325 pm_parser_scope_push(parser,
true);
19326 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19327 parser_lex(parser);
19332 parser_lex(parser);
19335 receiver = parse_variable_call(parser);
19337 pm_parser_scope_push(parser,
true);
19338 lex_state_set(parser, PM_LEX_STATE_FNAME);
19339 parser_lex(parser);
19342 name = parse_method_definition_name(parser);
19345 pm_parser_scope_push(parser,
true);
19355 valid_name =
false;
19365 pm_parser_scope_push(parser,
true);
19366 parser_lex(parser);
19371 lex_state_set(parser, PM_LEX_STATE_FNAME);
19372 parser_lex(parser);
19375 switch (identifier.
type) {
19377 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19380 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19383 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19386 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19389 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19392 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19395 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19398 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19401 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19404 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19407 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19413 name = parse_method_definition_name(parser);
19428 context_pop(parser);
19429 parser_lex(parser);
19432 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19438 lex_state_set(parser, PM_LEX_STATE_FNAME);
19442 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0);
19446 pm_parser_scope_push(parser,
true);
19448 name = parse_method_definition_name(parser);
19452 pm_parser_scope_push(parser,
true);
19453 name = parse_method_definition_name(parser);
19461 switch (parser->
current.type) {
19463 parser_lex(parser);
19469 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19472 lex_state_set(parser, PM_LEX_STATE_BEG);
19475 context_pop(parser);
19485 case PM_CASE_PARAMETER: {
19489 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19492 lparen = not_provided(parser);
19493 rparen = not_provided(parser);
19494 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19496 context_pop(parser);
19500 lparen = not_provided(parser);
19501 rparen = not_provided(parser);
19504 context_pop(parser);
19514 if (token_is_setter_name(&name)) {
19515 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19520 pm_do_loop_stack_push(parser,
false);
19521 statements = (
pm_node_t *) pm_statements_node_create(parser);
19523 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));
19530 context_pop(parser);
19532 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19535 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19536 pm_do_loop_stack_pop(parser);
19537 context_pop(parser);
19538 end_keyword = not_provided(parser);
19540 equal = not_provided(parser);
19543 lex_state_set(parser, PM_LEX_STATE_BEG);
19550 pm_accepts_block_stack_push(parser,
true);
19551 pm_do_loop_stack_push(parser,
false);
19554 pm_accepts_block_stack_push(parser,
true);
19556 pm_accepts_block_stack_pop(parser);
19561 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));
19563 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19566 pm_accepts_block_stack_pop(parser);
19567 pm_do_loop_stack_pop(parser);
19575 pm_parser_scope_pop(parser);
19582 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
19584 flush_block_exits(parser, previous_block_exits);
19585 pm_node_list_free(¤t_block_exits);
19587 return (
pm_node_t *) pm_def_node_create(
19604 parser_lex(parser);
19618 expression = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19619 lparen = not_provided(parser);
19620 rparen = not_provided(parser);
19622 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19625 rparen = not_provided(parser);
19633 lparen = not_provided(parser);
19634 rparen = not_provided(parser);
19635 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19638 context_pop(parser);
19639 return (
pm_node_t *) pm_defined_node_create(
19644 &PM_LOCATION_TOKEN_VALUE(&keyword)
19648 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19649 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19652 parser_lex(parser);
19655 if (context_def_p(parser)) {
19656 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19664 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19667 parser_lex(parser);
19670 size_t opening_newline_index = token_newline_index(parser);
19671 parser_lex(parser);
19683 if (token_begins_expression_p(parser->
current.type)) {
19684 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19687 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19688 }
else if (token_begins_expression_p(parser->
current.type)) {
19689 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19691 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19692 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19697 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19699 index = parse_target(parser, index,
false,
false);
19702 context_pop(parser);
19703 pm_do_loop_stack_push(parser,
true);
19708 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19709 pm_do_loop_stack_pop(parser);
19715 do_keyword = not_provided(parser);
19723 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19726 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19729 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19732 if (parser_end_of_line_p(parser)) {
19733 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19736 size_t opening_newline_index = token_newline_index(parser);
19738 parser_lex(parser);
19740 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19742 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19743 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19746 parser_lex(parser);
19748 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19751 pm_node_destroy(parser, name);
19753 pm_undef_node_append(undef, name);
19756 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19757 parser_lex(parser);
19758 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19761 pm_node_destroy(parser, name);
19765 pm_undef_node_append(undef, name);
19772 parser_lex(parser);
19784 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0);
19786 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19787 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19796 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19799 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19802 size_t opening_newline_index = token_newline_index(parser);
19803 parser_lex(parser);
19805 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19809 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19811 size_t opening_newline_index = token_newline_index(parser);
19812 parser_lex(parser);
19815 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19821 pop_block_exits(parser, previous_block_exits);
19822 pm_node_list_free(¤t_block_exits);
19825 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19832 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19840 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19843 pm_parser_scope_push(parser,
true);
19848 pm_accepts_block_stack_push(parser,
true);
19850 pm_accepts_block_stack_pop(parser);
19855 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));
19857 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19863 pm_parser_scope_pop(parser);
19866 if (context_def_p(parser)) {
19867 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19870 pop_block_exits(parser, previous_block_exits);
19871 pm_node_list_free(¤t_block_exits);
19873 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19876 parser_lex(parser);
19879 parser_lex(parser);
19887 parser_lex(parser);
19890 parse_retry(parser, node);
19895 parser_lex(parser);
19898 parser_lex(parser);
19901 size_t opening_newline_index = token_newline_index(parser);
19904 pm_do_loop_stack_push(parser,
true);
19906 parser_lex(parser);
19908 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19910 pm_do_loop_stack_pop(parser);
19911 context_pop(parser);
19917 do_keyword = not_provided(parser);
19923 pm_accepts_block_stack_push(parser,
true);
19924 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19925 pm_accepts_block_stack_pop(parser);
19929 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19932 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19935 size_t opening_newline_index = token_newline_index(parser);
19938 pm_do_loop_stack_push(parser,
true);
19940 parser_lex(parser);
19942 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19944 pm_do_loop_stack_pop(parser);
19945 context_pop(parser);
19951 do_keyword = not_provided(parser);
19957 pm_accepts_block_stack_push(parser,
true);
19958 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19959 pm_accepts_block_stack_pop(parser);
19963 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19966 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19969 parser_lex(parser);
19980 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19988 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19993 pm_array_node_close_set(array, &closing);
19998 parser_lex(parser);
20007 switch (parser->
current.type) {
20009 if (current == NULL) {
20015 pm_array_node_elements_append(array, current);
20019 parser_lex(parser);
20026 if (current == NULL) {
20030 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
20031 parser_lex(parser);
20037 parser_lex(parser);
20049 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
20050 parser_lex(parser);
20053 pm_interpolated_symbol_node_append(interpolated, first_string);
20054 pm_interpolated_symbol_node_append(interpolated, second_string);
20059 assert(
false &&
"unreachable");
20065 bool start_location_set =
false;
20066 if (current == NULL) {
20072 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20082 pm_interpolated_symbol_node_append(interpolated, current);
20084 start_location_set =
true;
20091 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20093 if (!start_location_set) {
20099 bool start_location_set =
false;
20100 if (current == NULL) {
20106 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20117 pm_interpolated_symbol_node_append(interpolated, current);
20119 start_location_set =
true;
20125 assert(
false &&
"unreachable");
20128 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20130 if (!start_location_set) {
20137 parser_lex(parser);
20144 pm_array_node_elements_append(array, current);
20149 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20154 pm_array_node_close_set(array, &closing);
20159 parser_lex(parser);
20175 pm_array_node_elements_append(array,
string);
20183 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20189 pm_array_node_close_set(array, &closing);
20193 parser_lex(parser);
20202 switch (parser->
current.type) {
20208 if (current == NULL) {
20215 pm_array_node_elements_append(array, current);
20219 parser_lex(parser);
20227 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20228 parser_lex(parser);
20230 if (current == NULL) {
20247 pm_interpolated_string_node_append(interpolated, current);
20248 pm_interpolated_string_node_append(interpolated,
string);
20251 assert(
false &&
"unreachable");
20257 if (current == NULL) {
20264 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20273 pm_interpolated_string_node_append(interpolated, current);
20281 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20286 if (current == NULL) {
20293 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20302 pm_interpolated_string_node_append(interpolated, current);
20309 assert(
false &&
"unreachable");
20312 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20318 parser_lex(parser);
20325 pm_array_node_elements_append(array, current);
20330 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20336 pm_array_node_close_set(array, &closing);
20341 parser_lex(parser);
20353 parser_lex(parser);
20371 parser_lex(parser);
20384 parse_regular_expression_errors(parser, node);
20387 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20393 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20406 pm_interpolated_regular_expression_node_append(interpolated, part);
20411 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20418 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20419 pm_interpolated_regular_expression_node_append(interpolated, part);
20425 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20431 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20436 parser_lex(parser);
20453 parser_lex(parser);
20454 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20466 parser_lex(parser);
20469 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20470 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20471 parser_lex(parser);
20477 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20483 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20485 pm_interpolated_xstring_node_append(node, part);
20490 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20495 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20496 pm_interpolated_xstring_node_append(node, part);
20502 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20507 pm_interpolated_xstring_node_closing_set(node, &closing);
20512 parser_lex(parser);
20517 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20518 pm_parser_err_prefix(parser, diag_id);
20525 if (token_begins_expression_p(parser->
current.type)) {
20526 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20532 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20534 return parse_target_validate(parser, splat,
true);
20538 if (binding_power > PM_BINDING_POWER_UNARY) {
20539 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20542 parser_lex(parser);
20545 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));
20546 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20548 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20552 if (binding_power > PM_BINDING_POWER_UNARY) {
20553 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20555 parser_lex(parser);
20558 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20559 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20564 if (binding_power > PM_BINDING_POWER_UNARY) {
20565 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20567 parser_lex(parser);
20570 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20571 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20576 parser_lex(parser);
20579 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20583 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20584 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20585 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20592 parse_negative_numeric(node);
20595 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20606 size_t opening_newline_index = token_newline_index(parser);
20607 pm_accepts_block_stack_push(parser,
true);
20608 parser_lex(parser);
20611 pm_parser_scope_push(parser,
false);
20615 switch (parser->
current.type) {
20618 parser_lex(parser);
20621 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20623 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20629 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20632 case PM_CASE_PARAMETER: {
20633 pm_accepts_block_stack_push(parser,
false);
20635 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20636 pm_accepts_block_stack_pop(parser);
20640 block_parameters = NULL;
20656 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20663 pm_accepts_block_stack_push(parser,
true);
20665 pm_accepts_block_stack_pop(parser);
20670 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));
20672 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20679 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20682 pm_parser_scope_pop(parser);
20683 pm_accepts_block_stack_pop(parser);
20685 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20688 if (binding_power > PM_BINDING_POWER_UNARY) {
20689 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20691 parser_lex(parser);
20694 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20695 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20700 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20703 parser_lex(parser);
20705 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20716 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20717 pm_parser_err_prefix(parser, diag_id);
20723 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20724 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20730 pm_parser_err_prefix(parser, diag_id);
20748parse_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) {
20749 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));
20757 parser_lex(parser);
20760 context_pop(parser);
20762 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20782 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20787 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20795 parse_assignment_value_local(parser, statement);
20817parse_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) {
20818 bool permitted =
true;
20819 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_USTAR)) permitted =
false;
20821 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));
20822 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20824 parse_assignment_value_local(parser, value);
20825 bool single_value =
true;
20828 single_value =
false;
20833 pm_array_node_elements_append(array, value);
20837 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20839 pm_array_node_elements_append(array, element);
20842 parse_assignment_value_local(parser, element);
20852 parser_lex(parser);
20854 bool accepts_command_call_inner =
false;
20861 accepts_command_call_inner =
true;
20866 context_pop(parser);
20868 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20884 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20889 if (call_node->
block != NULL) {
20890 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20892 call_node->
block = NULL;
20921static inline const uint8_t *
20922pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20925 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20926 uint8_t value = escape_hexadecimal_digit(*cursor);
20929 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20930 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20934 pm_buffer_append_byte(unescaped, value);
20936 pm_buffer_append_string(unescaped,
"\\x", 2);
20942static inline const uint8_t *
20943pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20944 uint8_t value = (uint8_t) (*cursor -
'0');
20947 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20948 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20951 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20952 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20957 pm_buffer_append_byte(unescaped, value);
20961static inline const uint8_t *
20962pm_named_capture_escape_unicode(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20963 const uint8_t *start = cursor - 1;
20966 if (cursor >= end) {
20967 pm_buffer_append_string(unescaped,
"\\u", 2);
20971 if (*cursor !=
'{') {
20972 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20973 uint32_t value = escape_unicode(parser, cursor, length);
20975 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20976 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20979 return cursor + length;
20984 while (cursor < end && *cursor ==
' ') cursor++;
20986 if (cursor >= end)
break;
20987 if (*cursor ==
'}') {
20992 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20993 uint32_t value = escape_unicode(parser, cursor, length);
20995 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21003pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor) {
21004 const uint8_t *end = source + length;
21005 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21008 if (++cursor >= end) {
21009 pm_buffer_append_byte(unescaped,
'\\');
21015 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21017 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21018 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21021 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end);
21024 pm_buffer_append_byte(unescaped,
'\\');
21028 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
21029 if (next_cursor == NULL)
break;
21031 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21032 cursor = next_cursor;
21035 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21043parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
21050 const uint8_t *source = pm_string_source(capture);
21051 size_t length = pm_string_length(capture);
21064 pm_named_capture_escape(parser, &unescaped, source, length, cursor);
21065 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21066 length = pm_buffer_length(&unescaped);
21074 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21075 pm_buffer_free(&unescaped);
21079 if (callback_data->
shared) {
21083 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
21089 void *memory =
xmalloc(length);
21090 if (memory == NULL) abort();
21092 memcpy(memory, source, length);
21093 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
21098 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21099 pm_constant_id_list_append(names, name);
21102 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21105 if (pm_local_is_keyword((
const char *) source, length)) {
21106 pm_buffer_free(&unescaped);
21112 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
21117 if (callback_data->
match == NULL) {
21118 callback_data->
match = pm_match_write_node_create(parser, call);
21123 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
21124 pm_node_list_append(&callback_data->
match->
targets, target);
21127 pm_buffer_free(&unescaped);
21140 .shared = content->
type == PM_STRING_SHARED
21147 .shared = content->
type == PM_STRING_SHARED
21150 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);
21151 pm_constant_id_list_free(&callback_data.
names);
21153 if (callback_data.
match != NULL) {
21161parse_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) {
21164 switch (token.type) {
21178 case PM_CASE_WRITABLE: {
21179 parser_lex(parser);
21180 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));
21183 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21186 return parse_write(parser, node, &token, value);
21190 pm_multi_target_node_targets_append(parser, multi_target, node);
21192 parser_lex(parser);
21193 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));
21194 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
21205 parser_lex(parser);
21206 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));
21207 return parse_unwriteable_write(parser, node, &token, value);
21213 parser_lex(parser);
21214 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21222 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21225 parser_lex(parser);
21227 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21228 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21230 pm_node_destroy(parser, node);
21234 parser_lex(parser);
21236 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));
21239 pm_node_destroy(parser, node);
21243 parser_lex(parser);
21245 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));
21248 return parse_shareable_constant_write(parser, write);
21251 parser_lex(parser);
21253 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));
21256 pm_node_destroy(parser, node);
21257 return parse_shareable_constant_write(parser, write);
21260 parser_lex(parser);
21262 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));
21265 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_AMPAMPEQ, (uint16_t) (depth + 1));
21273 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
21275 parse_target_implicit_parameter(parser, node);
21276 pm_node_destroy(parser, node);
21282 parse_target_implicit_parameter(parser, node);
21286 parser_lex(parser);
21288 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));
21291 pm_node_destroy(parser, node);
21302 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21305 parser_lex(parser);
21307 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));
21308 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21310 pm_node_destroy(parser, (
pm_node_t *) cast);
21316 parser_lex(parser);
21322 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));
21323 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21327 if (pm_call_node_writable_p(parser, cast)) {
21328 parse_write_name(parser, &cast->
name);
21330 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21333 parse_call_operator_write(parser, cast, &token);
21334 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));
21335 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21338 parser_lex(parser);
21339 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21343 parser_lex(parser);
21348 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21356 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21359 parser_lex(parser);
21361 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));
21362 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21364 pm_node_destroy(parser, node);
21368 parser_lex(parser);
21370 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));
21373 pm_node_destroy(parser, node);
21377 parser_lex(parser);
21379 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));
21382 return parse_shareable_constant_write(parser, write);
21385 parser_lex(parser);
21387 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));
21390 pm_node_destroy(parser, node);
21391 return parse_shareable_constant_write(parser, write);
21394 parser_lex(parser);
21396 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));
21399 pm_node_destroy(parser, node);
21404 parser_lex(parser);
21406 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));
21407 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
21409 parse_target_implicit_parameter(parser, node);
21410 pm_node_destroy(parser, node);
21416 parse_target_implicit_parameter(parser, node);
21420 parser_lex(parser);
21422 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));
21425 pm_node_destroy(parser, node);
21436 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21439 parser_lex(parser);
21441 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));
21442 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21444 pm_node_destroy(parser, (
pm_node_t *) cast);
21450 parser_lex(parser);
21456 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));
21457 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21461 if (pm_call_node_writable_p(parser, cast)) {
21462 parse_write_name(parser, &cast->
name);
21464 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21467 parse_call_operator_write(parser, cast, &token);
21468 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));
21469 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21472 parser_lex(parser);
21473 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21477 parser_lex(parser);
21482 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21500 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21503 parser_lex(parser);
21505 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));
21506 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21508 pm_node_destroy(parser, node);
21512 parser_lex(parser);
21514 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));
21517 pm_node_destroy(parser, node);
21521 parser_lex(parser);
21523 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));
21526 return parse_shareable_constant_write(parser, write);
21529 parser_lex(parser);
21531 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));
21534 pm_node_destroy(parser, node);
21535 return parse_shareable_constant_write(parser, write);
21538 parser_lex(parser);
21540 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));
21543 pm_node_destroy(parser, node);
21548 parser_lex(parser);
21550 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));
21551 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
21553 parse_target_implicit_parameter(parser, node);
21554 pm_node_destroy(parser, node);
21560 parse_target_implicit_parameter(parser, node);
21564 parser_lex(parser);
21566 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));
21567 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21569 pm_node_destroy(parser, node);
21573 parser_lex(parser);
21581 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21584 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));
21585 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21587 pm_node_destroy(parser, (
pm_node_t *) cast);
21595 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));
21596 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21600 if (pm_call_node_writable_p(parser, cast)) {
21601 parse_write_name(parser, &cast->
name);
21603 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21606 parse_call_operator_write(parser, cast, &token);
21607 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));
21608 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21611 parser_lex(parser);
21612 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21616 parser_lex(parser);
21627 parser_lex(parser);
21630 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21634 parser_lex(parser);
21637 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21647 parser_lex(parser);
21648 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21651 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21664 bool interpolated =
false;
21665 size_t total_length = 0;
21670 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21672 interpolated =
true;
21677 if (!interpolated && total_length > 0) {
21678 void *memory =
xmalloc(total_length);
21679 if (!memory) abort();
21681 uint8_t *cursor = memory;
21684 size_t length = pm_string_length(unescaped);
21686 memcpy(cursor, pm_string_source(unescaped), length);
21691 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21694 pm_string_free(&owned);
21726 parser_lex(parser);
21732 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21739 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21746 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21754 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21755 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21762 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21765 parser_lex(parser);
21766 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21767 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21771 parser_lex(parser);
21777 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21778 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21785 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21792 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21799 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21809 switch (parser->
current.type) {
21810 case PM_CASE_OPERATOR:
21811 case PM_CASE_KEYWORD:
21815 parser_lex(parser);
21825 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21826 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21829 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21834 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21841 parser_lex(parser);
21844 if (token_begins_expression_p(parser->
current.type)) {
21845 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21848 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21852 parser_lex(parser);
21854 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21855 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21859 parser_lex(parser);
21861 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21862 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21865 parser_lex(parser);
21867 pm_statements_node_body_append(parser, statements, node,
true);
21869 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21873 parser_lex(parser);
21875 pm_statements_node_body_append(parser, statements, node,
true);
21877 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21883 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21886 parser_lex(parser);
21888 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21900 context_pop(parser);
21901 pop_block_exits(parser, previous_block_exits);
21902 pm_node_list_free(¤t_block_exits);
21904 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21911 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21913 context_pop(parser);
21914 pop_block_exits(parser, previous_block_exits);
21915 pm_node_list_free(¤t_block_exits);
21917 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21920 parser_lex(parser);
21923 switch (parser->
current.type) {
21925 parser_lex(parser);
21941 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21942 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21945 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21949 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21950 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21955 case PM_CASE_OPERATOR:
21956 case PM_CASE_KEYWORD:
21959 parser_lex(parser);
21965 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21966 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21969 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21970 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21979 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21981 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
21985 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21991 parser_lex(parser);
21994 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21995 context_pop(parser);
21997 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
22000 parser_lex(parser);
22006 pm_accepts_block_stack_push(parser,
true);
22008 pm_accepts_block_stack_pop(parser);
22016 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
22017 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22018 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22026 block = parse_block(parser, (uint16_t) (depth + 1));
22027 pm_arguments_validate_block(parser, &arguments, block);
22029 block = parse_block(parser, (uint16_t) (depth + 1));
22032 if (block != NULL) {
22033 if (arguments.
block != NULL) {
22034 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
22036 arguments.
arguments = pm_arguments_node_create(parser);
22038 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
22044 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
22052 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22053 parser_lex(parser);
22056 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));
22059 pm_constant_id_list_free(&captures);
22061 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
22069 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22070 parser_lex(parser);
22073 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));
22076 pm_constant_id_list_free(&captures);
22078 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
22081 assert(
false &&
"unreachable");
22086#undef PM_PARSE_PATTERN_SINGLE
22087#undef PM_PARSE_PATTERN_TOP
22088#undef PM_PARSE_PATTERN_MULTI
22112parse_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) {
22114 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22118 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
22133 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22143 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
22151 if (pm_symbol_node_label_p(node)) {
22165 current_token_type = parser->
current.type,
22166 current_binding_powers = pm_binding_powers[current_token_type],
22167 binding_power <= current_binding_powers.
left &&
22168 current_binding_powers.
binary
22170 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
22176 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22188 if (
PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22196 if (
PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22206 if (current_binding_powers.
nonassoc) {
22209 if (match1(parser, current_token_type)) {
22227 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
22230 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
22235 if (accepts_command_call) {
22244 switch (node->
type) {
22259 cast->
block == NULL &&
22272 accepts_command_call =
false;
22280 accepts_command_call =
false;
22295 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22296 if (statements == NULL) {
22297 statements = pm_statements_node_create(parser);
22301 pm_arguments_node_arguments_append(
22303 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22306 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22309 pm_parser_constant_id_constant(parser,
"print", 5)
22313 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22314 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22315 if (statements == NULL) {
22316 statements = pm_statements_node_create(parser);
22320 pm_arguments_node_arguments_append(
22322 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22325 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22326 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22330 pm_parser_constant_id_constant(parser,
"$F", 2),
22334 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22338 pm_arguments_node_arguments_append(
22340 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22343 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22345 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22347 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22349 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22352 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22357 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22359 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22363 statements = wrapped_statements;
22378 pm_parser_scope_push(parser,
true);
22382 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22384 parser_lex(parser);
22391 assert(statements->
body.
size > 0);
22392 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22397 pm_parser_scope_pop(parser);
22402 statements = wrap_statements(parser, statements);
22404 flush_block_exits(parser, previous_block_exits);
22405 pm_node_list_free(¤t_block_exits);
22411 if (statements == NULL) {
22412 statements = pm_statements_node_create(parser);
22413 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22416 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22433pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22434 size_t little_length = strlen(little);
22436 for (
const char *big_end = big + big_length; big < big_end; big++) {
22437 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22444#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22452pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22453 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22454 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22465 const char *switches = pm_strnstr(engine,
" -", length);
22466 if (switches == NULL)
return;
22471 (
const uint8_t *) (switches + 1),
22472 length - ((
size_t) (switches - engine)) - 1,
22476 size_t encoding_length;
22477 if ((encoding_length = pm_string_length(&next_options.
encoding)) > 0) {
22478 const uint8_t *encoding_source = pm_string_source(&next_options.
encoding);
22479 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22491 assert(source != NULL);
22495 .lex_state = PM_LEX_STATE_BEG,
22496 .enclosure_nesting = 0,
22497 .lambda_enclosure_nesting = -1,
22498 .brace_nesting = 0,
22499 .do_loop_stack = 0,
22500 .accepts_block_stack = 0,
22503 .stack = {{ .mode = PM_LEX_DEFAULT }},
22507 .end = source + size,
22508 .previous = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22509 .current = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22510 .next_start = NULL,
22511 .heredoc_end = NULL,
22512 .data_loc = { .start = NULL, .end = NULL },
22513 .comment_list = { 0 },
22514 .magic_comment_list = { 0 },
22515 .warning_list = { 0 },
22516 .error_list = { 0 },
22517 .current_scope = NULL,
22518 .current_context = NULL,
22520 .encoding_changed_callback = NULL,
22521 .encoding_comment_start = source,
22522 .lex_callback = NULL,
22524 .constant_pool = { 0 },
22525 .newline_list = { 0 },
22529 .explicit_encoding = NULL,
22531 .parsing_eval =
false,
22532 .partial_script =
false,
22533 .command_start =
true,
22534 .recovering =
false,
22535 .encoding_locked =
false,
22536 .encoding_changed =
false,
22537 .pattern_matching_newlines =
false,
22538 .in_keyword_arg =
false,
22539 .current_block_exits = NULL,
22540 .semantic_token_seen =
false,
22542 .current_regular_expression_ascii_only =
false,
22543 .warn_mismatched_indentation =
true
22560 uint32_t constant_size = ((uint32_t) size) / 95;
22561 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22566 size_t newline_size = size / 22;
22567 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22570 if (options != NULL) {
22578 size_t encoding_length = pm_string_length(&options->
encoding);
22579 if (encoding_length > 0) {
22580 const uint8_t *encoding_source = pm_string_source(&options->
encoding);
22581 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22603 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22605 pm_parser_scope_push(parser, scope_index == 0);
22611 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22612 const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
22614 const uint8_t *source = pm_string_source(local);
22615 size_t length = pm_string_length(local);
22617 void *allocated =
xmalloc(length);
22618 if (allocated == NULL)
continue;
22620 memcpy(allocated, source, length);
22621 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22626 pm_accepts_block_stack_push(parser,
true);
22629 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22642 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22659 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22660 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22662 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22663 const char *engine;
22665 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22666 if (newline != NULL) {
22670 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22675 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22678 search_shebang =
false;
22680 search_shebang =
true;
22686 if (search_shebang) {
22689 bool found_shebang =
false;
22693 const uint8_t *cursor = parser->
start;
22697 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22699 while (newline != NULL) {
22700 pm_newline_list_append(&parser->
newline_list, newline);
22702 cursor = newline + 1;
22703 newline = next_newline(cursor, parser->
end - cursor);
22705 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22706 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22707 const char *engine;
22708 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22709 found_shebang =
true;
22711 if (newline != NULL) {
22712 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22717 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22725 if (found_shebang) {
22729 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22756 for (node = list->
head; node != NULL; node = next) {
22768pm_magic_comment_list_free(
pm_list_t *list) {
22771 for (node = list->
head; node != NULL; node = next) {
22784 pm_string_free(&parser->
filepath);
22785 pm_diagnostic_list_free(&parser->
error_list);
22797 pm_parser_scope_pop(parser);
22801 lex_mode_pop(parser);
22810 return parse_program(parser);
22820#define LINE_SIZE 4096
22821 char line[LINE_SIZE];
22823 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22824 size_t length = LINE_SIZE;
22825 while (length > 0 && line[length - 1] ==
'\n') length--;
22827 if (length == LINE_SIZE) {
22832 pm_buffer_append_string(buffer, line, length);
22838 pm_buffer_append_string(buffer, line, length);
22846 if (strncmp(line,
"__END__", 7) == 0)
return false;
22849 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22852 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22871pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22874 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22875 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22891 pm_buffer_init(buffer);
22893 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets);
22894 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22898 pm_node_destroy(parser, node);
22899 eof = pm_parse_stream_read(buffer, stream, stream_fgets);
22901 pm_parser_free(parser);
22902 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22903 node = pm_parse(parser);
22913pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22915 pm_options_read(&options, data);
22918 pm_parser_init(&parser, source, size, &options);
22921 pm_node_destroy(&parser, node);
22924 pm_parser_free(&parser);
22925 pm_options_free(&options);
22930#undef PM_CASE_KEYWORD
22931#undef PM_CASE_OPERATOR
22932#undef PM_CASE_WRITABLE
22933#undef PM_STRING_EMPTY
22934#undef PM_LOCATION_NODE_BASE_VALUE
22935#undef PM_LOCATION_NODE_VALUE
22936#undef PM_LOCATION_NULL_VALUE
22937#undef PM_LOCATION_TOKEN_VALUE
22942#ifndef PRISM_EXCLUDE_SERIALIZATION
22946 pm_buffer_append_string(buffer,
"PRISM", 5);
22958 pm_serialize_header(buffer);
22960 pm_buffer_append_byte(buffer,
'\0');
22968pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22970 pm_options_read(&options, data);
22973 pm_parser_init(&parser, source, size, &options);
22977 pm_serialize_header(buffer);
22979 pm_buffer_append_byte(buffer,
'\0');
22981 pm_node_destroy(&parser, node);
22982 pm_parser_free(&parser);
22983 pm_options_free(&options);
22994 pm_options_read(&options, data);
22997 pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, &options);
22998 pm_serialize_header(buffer);
23000 pm_buffer_append_byte(buffer,
'\0');
23002 pm_node_destroy(&parser, node);
23003 pm_buffer_free(&parser_buffer);
23004 pm_parser_free(&parser);
23005 pm_options_free(&options);
23012pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23014 pm_options_read(&options, data);
23017 pm_parser_init(&parser, source, size, &options);
23020 pm_serialize_header(buffer);
23022 pm_buffer_append_varsint(buffer, parser.
start_line);
23025 pm_node_destroy(&parser, node);
23026 pm_parser_free(&parser);
23027 pm_options_free(&options);
23039 PM_SLICE_TYPE_ERROR = -1,
23042 PM_SLICE_TYPE_NONE,
23045 PM_SLICE_TYPE_LOCAL,
23048 PM_SLICE_TYPE_CONSTANT,
23051 PM_SLICE_TYPE_METHOD_NAME
23058pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23060 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
23061 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
23064 if (length == 0)
return PM_SLICE_TYPE_NONE;
23067 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
23069 }
else if (*source ==
'_') {
23072 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
23076 return PM_SLICE_TYPE_NONE;
23080 const uint8_t *end = source + length;
23081 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
23087 while (source < end) {
23088 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
23091 }
else if (*source ==
'_') {
23094 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
23104 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
23106 result = PM_SLICE_TYPE_METHOD_NAME;
23110 return source == end ? result : PM_SLICE_TYPE_NONE;
23117pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23118 switch (pm_slice_type(source, length, encoding_name)) {
23119 case PM_SLICE_TYPE_ERROR:
23121 case PM_SLICE_TYPE_NONE:
23122 case PM_SLICE_TYPE_CONSTANT:
23123 case PM_SLICE_TYPE_METHOD_NAME:
23125 case PM_SLICE_TYPE_LOCAL:
23129 assert(
false &&
"unreachable");
23137pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23138 switch (pm_slice_type(source, length, encoding_name)) {
23139 case PM_SLICE_TYPE_ERROR:
23141 case PM_SLICE_TYPE_NONE:
23142 case PM_SLICE_TYPE_LOCAL:
23143 case PM_SLICE_TYPE_METHOD_NAME:
23145 case PM_SLICE_TYPE_CONSTANT:
23149 assert(
false &&
"unreachable");
23157pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
23158#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
23159#define C1(c) (*source == c)
23160#define C2(s) (memcmp(source, s, 2) == 0)
23161#define C3(s) (memcmp(source, s, 3) == 0)
23163 switch (pm_slice_type(source, length, encoding_name)) {
23164 case PM_SLICE_TYPE_ERROR:
23166 case PM_SLICE_TYPE_NONE:
23168 case PM_SLICE_TYPE_LOCAL:
23170 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
23171 case PM_SLICE_TYPE_CONSTANT:
23173 case PM_SLICE_TYPE_METHOD_NAME:
23180 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
23182 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
23184 return B(C3(
"===") || C3(
"<=>") || C3(
"[]="));
@ PM_RANGE_FLAGS_EXCLUDE_END
... operator
@ PM_DEFINED_NODE
DefinedNode.
@ PM_PRE_EXECUTION_NODE
PreExecutionNode.
@ PM_RETRY_NODE
RetryNode.
@ PM_CONSTANT_PATH_WRITE_NODE
ConstantPathWriteNode.
@ PM_SOURCE_LINE_NODE
SourceLineNode.
@ PM_UNLESS_NODE
UnlessNode.
@ PM_GLOBAL_VARIABLE_READ_NODE
GlobalVariableReadNode.
@ PM_RATIONAL_NODE
RationalNode.
@ PM_FIND_PATTERN_NODE
FindPatternNode.
@ PM_ARRAY_NODE
ArrayNode.
@ PM_CONSTANT_PATH_TARGET_NODE
ConstantPathTargetNode.
@ PM_MULTI_WRITE_NODE
MultiWriteNode.
@ PM_INTERPOLATED_STRING_NODE
InterpolatedStringNode.
@ PM_FALSE_NODE
FalseNode.
@ PM_MATCH_PREDICATE_NODE
MatchPredicateNode.
@ PM_X_STRING_NODE
XStringNode.
@ PM_GLOBAL_VARIABLE_TARGET_NODE
GlobalVariableTargetNode.
@ PM_CONSTANT_TARGET_NODE
ConstantTargetNode.
@ PM_IT_LOCAL_VARIABLE_READ_NODE
ItLocalVariableReadNode.
@ PM_SOURCE_FILE_NODE
SourceFileNode.
@ PM_NO_KEYWORDS_PARAMETER_NODE
NoKeywordsParameterNode.
@ PM_MULTI_TARGET_NODE
MultiTargetNode.
@ PM_SPLAT_NODE
SplatNode.
@ PM_CLASS_VARIABLE_READ_NODE
ClassVariableReadNode.
@ PM_INTERPOLATED_MATCH_LAST_LINE_NODE
InterpolatedMatchLastLineNode.
@ PM_SYMBOL_NODE
SymbolNode.
@ PM_RESCUE_MODIFIER_NODE
RescueModifierNode.
@ PM_ALIAS_METHOD_NODE
AliasMethodNode.
@ PM_MATCH_REQUIRED_NODE
MatchRequiredNode.
@ PM_BACK_REFERENCE_READ_NODE
BackReferenceReadNode.
@ PM_BLOCK_ARGUMENT_NODE
BlockArgumentNode.
@ PM_MISSING_NODE
MissingNode.
@ PM_ASSOC_SPLAT_NODE
AssocSplatNode.
@ PM_RANGE_NODE
RangeNode.
@ PM_LOCAL_VARIABLE_READ_NODE
LocalVariableReadNode.
@ PM_REGULAR_EXPRESSION_NODE
RegularExpressionNode.
@ PM_CONSTANT_WRITE_NODE
ConstantWriteNode.
@ PM_HASH_PATTERN_NODE
HashPatternNode.
@ PM_UNDEF_NODE
UndefNode.
@ PM_ENSURE_NODE
EnsureNode.
@ PM_LOCAL_VARIABLE_WRITE_NODE
LocalVariableWriteNode.
@ PM_KEYWORD_HASH_NODE
KeywordHashNode.
@ PM_PARENTHESES_NODE
ParenthesesNode.
@ PM_CLASS_VARIABLE_WRITE_NODE
ClassVariableWriteNode.
@ PM_POST_EXECUTION_NODE
PostExecutionNode.
@ PM_RETURN_NODE
ReturnNode.
@ PM_ARRAY_PATTERN_NODE
ArrayPatternNode.
@ PM_MATCH_LAST_LINE_NODE
MatchLastLineNode.
@ PM_CONSTANT_PATH_NODE
ConstantPathNode.
@ PM_INTERPOLATED_SYMBOL_NODE
InterpolatedSymbolNode.
@ PM_CLASS_VARIABLE_TARGET_NODE
ClassVariableTargetNode.
@ PM_BREAK_NODE
BreakNode.
@ PM_IMAGINARY_NODE
ImaginaryNode.
@ PM_CONSTANT_READ_NODE
ConstantReadNode.
@ PM_GLOBAL_VARIABLE_WRITE_NODE
GlobalVariableWriteNode.
@ PM_SOURCE_ENCODING_NODE
SourceEncodingNode.
@ PM_BEGIN_NODE
BeginNode.
@ PM_INSTANCE_VARIABLE_READ_NODE
InstanceVariableReadNode.
@ PM_FLIP_FLOP_NODE
FlipFlopNode.
@ PM_INSTANCE_VARIABLE_WRITE_NODE
InstanceVariableWriteNode.
@ PM_INSTANCE_VARIABLE_TARGET_NODE
InstanceVariableTargetNode.
@ PM_FLOAT_NODE
FloatNode.
@ PM_ASSOC_NODE
AssocNode.
@ PM_INTEGER_NODE
IntegerNode.
@ PM_LOCAL_VARIABLE_TARGET_NODE
LocalVariableTargetNode.
@ PM_STRING_NODE
StringNode.
@ PM_ALIAS_GLOBAL_VARIABLE_NODE
AliasGlobalVariableNode.
@ PM_NUMBERED_REFERENCE_READ_NODE
NumberedReferenceReadNode.
@ PM_STATEMENTS_NODE
StatementsNode.
@ PM_BLOCK_NODE
BlockNode.
@ PM_INTERPOLATED_REGULAR_EXPRESSION_NODE
InterpolatedRegularExpressionNode.
static const pm_node_flags_t PM_NODE_FLAG_NEWLINE
We store the flags enum in every node in the tree.
@ PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING
internal bytes forced the encoding to US-ASCII
@ PM_STRING_FLAGS_FROZEN
frozen by virtue of a frozen_string_literal: true comment or --enable-frozen-string-literal
@ PM_STRING_FLAGS_FORCED_BINARY_ENCODING
internal bytes forced the encoding to binary
@ PM_STRING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING
if the arguments contain forwarding
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS
if the arguments contain keywords
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT
if the arguments contain a keyword splat
#define PM_NODE_FLAG_P(node, flag)
Return true if the given flag is set on the given node.
#define PM_NODE_TYPE_P(node, type)
Return true if the type of the given node matches the given type.
#define PM_NODE_TYPE(node)
Cast the type to an enum to allow the compiler to provide exhaustiveness checking.
@ PM_INTEGER_BASE_FLAGS_HEXADECIMAL
0x prefix
@ PM_INTEGER_BASE_FLAGS_OCTAL
0o or 0 prefix
@ PM_INTEGER_BASE_FLAGS_DECIMAL
0d or no prefix
@ PM_INTEGER_BASE_FLAGS_BINARY
0b prefix
enum pm_token_type pm_token_type_t
This enum represents every type of token in the Ruby source.
@ PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS
parentheses that contain multiple potentially void statements
#define PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
When we're serializing to Java, we want to skip serializing the location fields as they won't be used...
@ PM_CALL_NODE_FLAGS_SAFE_NAVIGATION
&.
@ PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE
a call that is an attribute write, so the value being written should be returned
@ PM_CALL_NODE_FLAGS_VARIABLE_CALL
a call that could have been a local variable
@ PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING
internal bytes forced the encoding to US-ASCII
@ PM_REGULAR_EXPRESSION_FLAGS_EXTENDED
x - ignores whitespace and allows comments in regular expressions
uint16_t pm_node_flags_t
These are the flags embedded in the node struct.
@ PM_TOKEN_DOT_DOT_DOT
the ... range operator or forwarding parameter
@ PM_TOKEN_IGNORED_NEWLINE
an ignored newline
@ PM_TOKEN_KEYWORD___FILE__
FILE
@ PM_TOKEN_KEYWORD_WHEN
when
@ PM_TOKEN_FLOAT
a floating point number
@ PM_TOKEN_UDOT_DOT
unary .
@ PM_TOKEN_AMPERSAND_DOT
&.
@ PM_TOKEN_NEWLINE
a newline character outside of other tokens
@ PM_TOKEN_NUMBERED_REFERENCE
a numbered reference to a capture group in the previous regular expression match
@ PM_TOKEN_KEYWORD_YIELD
yield
@ PM_TOKEN_KEYWORD_END
end
@ PM_TOKEN_KEYWORD_UNTIL_MODIFIER
until in the modifier form
@ PM_TOKEN_EQUAL_EQUAL_EQUAL
===
@ PM_TOKEN_INTEGER_RATIONAL
an integer with a rational suffix
@ PM_TOKEN_KEYWORD___ENCODING__
ENCODING
@ PM_TOKEN_REGEXP_END
the end of a regular expression
@ PM_TOKEN_KEYWORD_UNTIL
until
@ PM_TOKEN_MAXIMUM
The maximum token value.
@ PM_TOKEN_INTEGER
an integer (any base)
@ PM_TOKEN_UMINUS_NUM
-@ for a number
@ PM_TOKEN_KEYWORD_UNLESS_MODIFIER
unless in the modifier form
@ PM_TOKEN_INTEGER_RATIONAL_IMAGINARY
an integer with a rational and imaginary suffix
@ PM_TOKEN_FLOAT_RATIONAL_IMAGINARY
a floating pointer number with a rational and imaginary suffix
@ PM_TOKEN_BRACKET_LEFT_RIGHT
[]
@ PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL
&&=
@ PM_TOKEN_KEYWORD_CLASS
class
@ PM_TOKEN_KEYWORD_BEGIN
begin
@ PM_TOKEN_NOT_PROVIDED
a token that was not present but it is okay
@ PM_TOKEN_USTAR_STAR
unary **
@ PM_TOKEN_GREATER_GREATER_EQUAL
>=
@ PM_TOKEN_PERCENT_EQUAL
%=
@ PM_TOKEN_KEYWORD_NOT
not
@ PM_TOKEN_BRACKET_LEFT_ARRAY
[ for the beginning of an array
@ PM_TOKEN_HEREDOC_END
the end of a heredoc
@ PM_TOKEN_HEREDOC_START
the start of a heredoc
@ PM_TOKEN_KEYWORD_DEFINED
defined?
@ PM_TOKEN_UCOLON_COLON
unary ::
@ PM_TOKEN_LABEL_END
the end of a label
@ PM_TOKEN_EQUAL_GREATER
=>
@ PM_TOKEN_KEYWORD_UNLESS
unless
@ PM_TOKEN_KEYWORD_ENSURE
ensure
@ PM_TOKEN_AMPERSAND_EQUAL
&=
@ PM_TOKEN_FLOAT_IMAGINARY
a floating pointer number with an imaginary suffix
@ PM_TOKEN_KEYWORD_BEGIN_UPCASE
BEGIN.
@ PM_TOKEN_LESS_EQUAL_GREATER
<=>
@ PM_TOKEN_KEYWORD_RESCUE_MODIFIER
rescue in the modifier form
@ PM_TOKEN_MISSING
a token that was expected but not found
@ PM_TOKEN_MINUS_GREATER
->
@ PM_TOKEN_KEYWORD_FALSE
false
@ PM_TOKEN_PIPE_PIPE_EQUAL
||=
@ PM_TOKEN_EMBEXPR_BEGIN
#{
@ PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES
( for a parentheses node
@ PM_TOKEN_EMBDOC_END
=end
@ PM_TOKEN_KEYWORD_ELSE
else
@ PM_TOKEN_BACK_REFERENCE
a back reference
@ PM_TOKEN_EOF
final token in the file
@ PM_TOKEN_KEYWORD_NIL
nil
@ PM_TOKEN_PERCENT_UPPER_W
W
@ PM_TOKEN_KEYWORD_RETURN
return
@ PM_TOKEN_CLASS_VARIABLE
a class variable
@ PM_TOKEN_PARENTHESIS_LEFT
(
@ PM_TOKEN_PARENTHESIS_RIGHT
)
@ PM_TOKEN_KEYWORD_RESCUE
rescue
@ PM_TOKEN_INSTANCE_VARIABLE
an instance variable
@ PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL
[]=
@ PM_TOKEN_UAMPERSAND
unary &
@ PM_TOKEN_CONSTANT
a constant
@ PM_TOKEN_IDENTIFIER
an identifier
@ PM_TOKEN_EMBDOC_BEGIN
=begin
@ PM_TOKEN_KEYWORD_AND
and
@ PM_TOKEN_KEYWORD_BREAK
break
@ PM_TOKEN_PERCENT_LOWER_W
w
@ PM_TOKEN_SYMBOL_BEGIN
the beginning of a symbol
@ PM_TOKEN_METHOD_NAME
a method name
@ PM_TOKEN_KEYWORD_CASE
case
@ PM_TOKEN_WORDS_SEP
a separator between words in a list
@ PM_TOKEN_FLOAT_RATIONAL
a floating pointer number with a rational suffix
@ PM_TOKEN_LESS_LESS_EQUAL
<<=
@ PM_TOKEN_EMBDOC_LINE
a line inside of embedded documentation
@ PM_TOKEN_KEYWORD_SUPER
super
@ PM_TOKEN_KEYWORD_REDO
redo
@ PM_TOKEN_KEYWORD_END_UPCASE
END.
@ PM_TOKEN_KEYWORD___LINE__
LINE
@ PM_TOKEN_STRING_END
the end of a string
@ PM_TOKEN_STRING_CONTENT
the contents of a string
@ PM_TOKEN_GREATER_GREATER
@ PM_TOKEN_PERCENT_LOWER_X
x
@ PM_TOKEN_KEYWORD_SELF
self
@ PM_TOKEN_PERCENT_LOWER_I
i
@ PM_TOKEN_KEYWORD_ALIAS
alias
@ PM_TOKEN_GLOBAL_VARIABLE
a global variable
@ PM_TOKEN_KEYWORD_IF_MODIFIER
if in the modifier form
@ PM_TOKEN_KEYWORD_RETRY
retry
@ PM_TOKEN_KEYWORD_UNDEF
undef
@ PM_TOKEN_BRACKET_RIGHT
]
@ PM_TOKEN_KEYWORD_FOR
for
@ PM_TOKEN_KEYWORD_THEN
then
@ PM_TOKEN_QUESTION_MARK
?
@ PM_TOKEN___END__
marker for the point in the file at which the parser should stop
@ PM_TOKEN_KEYWORD_WHILE
while
@ PM_TOKEN_KEYWORD_DEF
def
@ PM_TOKEN_UDOT_DOT_DOT
unary ... operator
@ PM_TOKEN_KEYWORD_WHILE_MODIFIER
while in the modifier form
@ PM_TOKEN_KEYWORD_TRUE
true
@ PM_TOKEN_REGEXP_BEGIN
the beginning of a regular expression
@ PM_TOKEN_PERCENT_UPPER_I
I
@ PM_TOKEN_KEYWORD_DO_LOOP
do keyword for a predicate in a while, until, or for loop
@ PM_TOKEN_KEYWORD_MODULE
module
@ PM_TOKEN_KEYWORD_NEXT
next
@ PM_TOKEN_INTEGER_IMAGINARY
an integer with an imaginary suffix
@ PM_TOKEN_STAR_STAR_EQUAL
**=
@ PM_TOKEN_CHARACTER_LITERAL
a character literal
@ PM_TOKEN_AMPERSAND_AMPERSAND
&&
@ PM_TOKEN_GREATER_EQUAL
>=
@ PM_TOKEN_COMMENT
a comment
@ PM_TOKEN_KEYWORD_ELSIF
elsif
@ PM_TOKEN_STRING_BEGIN
the beginning of a string
@ PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
@ PM_LOOP_FLAGS_BEGIN_MODIFIER
a loop after a begin statement, so the body is executed first before the condition
pm_diagnostic_id_t
The diagnostic IDs of all of the diagnostics, used to communicate the types of errors between the par...
#define xfree
Old name of ruby_xfree.
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
VALUE type(ANYARGS)
ANYARGS-ed function type.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
String literals may be frozen or mutable depending on the implementation default.
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
pm_heredoc_indent_t
The type of indentation that a heredoc uses.
struct pm_context_node pm_context_node_t
This is a node in a linked list of contexts.
#define PM_LEX_STACK_SIZE
We pre-allocate a certain number of lex states in order to avoid having to call malloc too many times...
struct pm_parser pm_parser_t
The parser used to parse Ruby source.
struct pm_comment pm_comment_t
This is a node in the linked list of comments that we've found while parsing.
pm_lex_state_t
This enum combines the various bits from the above enum into individual values that represent the var...
struct pm_scope pm_scope_t
This struct represents a node in a linked list of scopes.
pm_heredoc_quote_t
The type of quote that a heredoc uses.
void(* pm_encoding_changed_callback_t)(pm_parser_t *parser)
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
pm_context_t
While parsing, we keep track of a stack of contexts.
@ PM_CONTEXT_CLASS_RESCUE
a rescue statement within a class statement
@ PM_CONTEXT_ELSIF
an elsif clause
@ PM_CONTEXT_DEF_RESCUE
a rescue statement within a method definition
@ PM_CONTEXT_ELSE
an else clause
@ PM_CONTEXT_FOR_INDEX
a for loop's index
@ PM_CONTEXT_CASE_WHEN
a case when statements
@ PM_CONTEXT_BLOCK_RESCUE
a rescue statement within a do..end block
@ PM_CONTEXT_MODULE
a module declaration
@ PM_CONTEXT_DEF_PARAMS
a method definition's parameters
@ PM_CONTEXT_CASE_IN
a case in statements
@ PM_CONTEXT_BLOCK_ELSE
a rescue else statement within a do..end block
@ PM_CONTEXT_LOOP_PREDICATE
the predicate clause of a loop statement
@ PM_CONTEXT_SCLASS
a singleton class definition
@ PM_CONTEXT_UNLESS
an unless statement
@ PM_CONTEXT_POSTEXE
an END block
@ PM_CONTEXT_IF
an if statement
@ PM_CONTEXT_MULTI_TARGET
a multiple target expression
@ PM_CONTEXT_LAMBDA_RESCUE
a rescue statement within a lambda expression
@ PM_CONTEXT_BEGIN_ELSE
a rescue else statement with an explicit begin
@ PM_CONTEXT_NONE
a null context, used for returning a value from a function
@ PM_CONTEXT_CLASS_ELSE
a rescue else statement within a class statement
@ PM_CONTEXT_LAMBDA_ENSURE
an ensure statement within a lambda expression
@ PM_CONTEXT_BLOCK_ENSURE
an ensure statement within a do..end block
@ PM_CONTEXT_CLASS_ENSURE
an ensure statement within a class statement
@ PM_CONTEXT_LAMBDA_BRACES
a lambda expression with braces
@ PM_CONTEXT_MODULE_ELSE
a rescue else statement within a module statement
@ PM_CONTEXT_PARENS
a parenthesized expression
@ PM_CONTEXT_BLOCK_BRACES
expressions in block arguments using braces
@ PM_CONTEXT_DEF_ENSURE
an ensure statement within a method definition
@ PM_CONTEXT_SCLASS_RESCUE
a rescue statement with a singleton class
@ PM_CONTEXT_PREEXE
a BEGIN block
@ PM_CONTEXT_DEFINED
a defined? expression
@ PM_CONTEXT_MODULE_ENSURE
an ensure statement within a module statement
@ PM_CONTEXT_BEGIN_RESCUE
a rescue statement with an explicit begin
@ PM_CONTEXT_UNTIL
an until statement
@ PM_CONTEXT_DEF_ELSE
a rescue else statement within a method definition
@ PM_CONTEXT_FOR
a for loop
@ PM_CONTEXT_PREDICATE
a predicate inside an if/elsif/unless statement
@ PM_CONTEXT_BEGIN_ENSURE
an ensure statement with an explicit begin
@ PM_CONTEXT_SCLASS_ENSURE
an ensure statement with a singleton class
@ PM_CONTEXT_DEFAULT_PARAMS
a method definition's default parameter
@ PM_CONTEXT_LAMBDA_ELSE
a rescue else statement within a lambda expression
@ PM_CONTEXT_CLASS
a class declaration
@ PM_CONTEXT_MAIN
the top level context
@ PM_CONTEXT_LAMBDA_DO_END
a lambda expression with do..end
@ PM_CONTEXT_BEGIN
a begin statement
@ PM_CONTEXT_RESCUE_MODIFIER
a modifier rescue clause
@ PM_CONTEXT_EMBEXPR
an interpolated expression
@ PM_CONTEXT_TERNARY
a ternary expression
@ PM_CONTEXT_DEF
a method definition
@ PM_CONTEXT_SCLASS_ELSE
a rescue else statement with a singleton class
@ PM_CONTEXT_MODULE_RESCUE
a rescue statement within a module statement
@ PM_CONTEXT_BLOCK_KEYWORDS
expressions in block arguments using do..end
@ PM_CONTEXT_WHILE
a while statement
uint8_t pm_scope_parameters_t
The flags about scope parameters that can be set.
uint8_t pm_shareable_constant_value_t
The type of shareable constant value that can be set.
pm_comment_type_t
This is the type of a comment that we've found while parsing.
#define PM_CONSTANT_ID_UNSET
When we allocate constants into the pool, we reserve 0 to mean that the slot is not yet filled.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
#define PM_STRING_EMPTY
Defines an empty string.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_DEPTH_MAXIMUM
When we are parsing using recursive descent, we want to protect against malicious payloads that could...
#define PM_STATIC_ASSERT(line, condition, message)
We want to be able to use static assertions, but they weren't standardized until C11.
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
#define PM_ENCODING_US_ASCII_ENTRY
This is the US-ASCII encoding.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PRISM_ENCODING_ALPHABETIC_BIT
All of the lookup tables use the first bit of each embedded byte to indicate whether the codepoint is...
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
The main header file for the prism parser.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the encoding, metadata, nodes, and constant pool.
char *() pm_parse_stream_fgets_t(char *string, int size, void *stream)
This function is used in pm_parse_stream to retrieve a line of input from a stream.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer)
Serialize the given list of comments to the given buffer.
const char * pm_token_type_human(pm_token_type_t token_type)
Returns the human name of the given token type.
This struct is used to pass information between the regular expression parser and the error callback.
pm_parser_t * parser
The parser that we are parsing the regular expression for.
const uint8_t * start
The start of the regular expression.
bool shared
Whether or not the source of the regular expression is shared.
const uint8_t * end
The end of the regular expression.
This struct is used to pass information between the regular expression parser and the named capture c...
pm_constant_id_list_t names
The list of names that have been parsed.
pm_parser_t * parser
The parser that is parsing the regular expression.
pm_match_write_node_t * match
The match write node that is being created.
pm_call_node_t * call
The call node wrapping the regular expression node.
bool shared
Whether the content of the regular expression is shared.
struct pm_node * left
AndNode::left.
struct pm_node * right
AndNode::right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode::arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode::elements.
struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
struct pm_node * value
AssocNode::value.
struct pm_node * key
AssocNode::key.
struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
struct pm_statements_node * statements
BeginNode::statements.
pm_node_t base
The embedded base node.
struct pm_else_node * else_clause
BeginNode::else_clause.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
size_t length
The length of the buffer in bytes.
char * value
A pointer to the start of the buffer.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
struct pm_node * receiver
CallNode::receiver.
pm_constant_id_t name
CallNode::name.
pm_node_t base
The embedded base node.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
struct pm_arguments_node * arguments
CallNode::arguments.
struct pm_node * block
CallNode::block.
struct pm_node_list conditions
CaseMatchNode::conditions.
struct pm_node_list conditions
CaseNode::conditions.
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
This is a node in a linked list of contexts.
pm_context_t context
The context that this node represents.
struct pm_context_node * prev
A pointer to the previous context in the linked list.
This struct represents a diagnostic generated during parsing.
struct pm_statements_node * statements
ElseNode::statements.
This struct defines the functions necessary to implement the encoding interface so we can determine h...
size_t(* alpha_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphab...
size_t(* char_width)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding.
bool(* isupper_char)(const uint8_t *b, ptrdiff_t n)
Return true if the next character is valid in the encoding and is an uppercase character.
const char * name
The name of the encoding.
size_t(* alnum_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphan...
struct pm_statements_node * statements
EnsureNode::statements.
struct pm_node * constant
FindPatternNode::constant.
pm_location_t opening_loc
FindPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
GlobalVariableTargetNode.
struct pm_node_list elements
HashNode::elements.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
HashPatternNode::closing_loc.
struct pm_node * constant
HashPatternNode::constant.
All of the information necessary to store to lexing a heredoc.
size_t ident_length
The length of the heredoc identifier.
pm_heredoc_quote_t quote
The type of quote that the heredoc uses.
pm_heredoc_indent_t indent
The type of indentation that the heredoc uses.
const uint8_t * ident_start
A pointer to the start of the heredoc identifier.
struct pm_statements_node * statements
IfNode::statements.
struct pm_node * subsequent
IfNode::subsequent.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
void(* callback)(void *data, pm_parser_t *parser, pm_token_t *token)
This is the callback that is called when a token is lexed.
void * data
This opaque pointer is used to provide whatever information the user deemed necessary to the callback...
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
enum pm_lex_mode::@92 mode
The type of this lex mode.
uint8_t terminator
This is the terminator of the list literal.
size_t nesting
This keeps track of the nesting level of the list.
bool interpolation
Whether or not interpolation is allowed in this list.
uint8_t incrementor
When lexing a list, it takes into account balancing the terminator if the terminator is one of (),...
uint8_t breakpoints[11]
This is the character set that should be used to delimit the tokens within the list.
pm_heredoc_lex_mode_t base
All of the data necessary to lex a heredoc.
bool line_continuation
True if the previous token ended with a line continuation.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
union pm_lex_mode::@93 as
The data associated with this type of lex mode.
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
size_t * common_whitespace
This is used to track the amount of common whitespace on each line so that we know how much to dedent...
int32_t line
The line number.
This struct represents an abstract linked list that provides common functionality.
struct pm_list_node * next
A pointer to the next node in the list.
This represents the overall linked list.
pm_list_node_t * head
A pointer to the head of the list.
size_t size
The size of the list.
This tracks an individual local variable in a certain lexical context, as well as the number of times...
pm_constant_id_t name
The name of the local variable.
pm_location_t location
The location of the local variable in the source.
uint32_t hash
The hash of the local variable.
uint32_t index
The index of the local variable in the local table.
uint32_t reads
The number of times the local variable is read.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
uint32_t depth
LocalVariableWriteNode::depth.
pm_constant_id_t name
LocalVariableWriteNode::name.
This is a set of local variables in a certain lexical context (method, class, module,...
pm_local_t * locals
The nullable allocated memory for the local variables in the set.
uint32_t capacity
The capacity of the local variables set.
uint32_t size
The number of local variables in the set.
This represents a range of bytes in the source string to which a node or token corresponds.
const uint8_t * start
A pointer to the start location of the range in the source.
const uint8_t * end
A pointer to the end location of the range in the source.
struct pm_node_list targets
MatchWriteNode::targets.
pm_node_t base
The embedded base node.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
size_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_node_flags_t flags
This represents any flags on the node.
pm_location_t location
This is the location of the node in the source.
A scope of locals surrounding the code that is being parsed.
size_t locals_count
The number of locals in the scope.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
The options that can be passed to the parser.
uint8_t command_line
A bitset of the various options that were set on the command line.
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
bool encoding_locked
Whether or not the encoding magic comments should be respected.
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
pm_string_t encoding
The name of the encoding that the source file is in.
int32_t line
The line within the file that the parse starts on.
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
bool partial_script
When the file being parsed is considered a "partial" script, jumps will not be marked as errors if th...
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
pm_string_t filepath
The name of the file that is currently being parsed.
pm_options_version_t version
The version of prism that we should be parsing with.
struct pm_node * left
OrNode::left.
struct pm_node * right
OrNode::right.
struct pm_node * rest
ParametersNode::rest.
struct pm_block_parameter_node * block
ParametersNode::block.
pm_node_t base
The embedded base node.
struct pm_node * keyword_rest
ParametersNode::keyword_rest.
struct pm_node * body
ParenthesesNode::body.
This struct represents the overall parser.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
pm_lex_state_t lex_state
The current state of the lexer.
uint8_t command_line
The command line flags given from the options.
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool partial_script
Whether or not we are parsing a "partial" script, which is a script that will be evaluated in the con...
bool pattern_matching_newlines
This flag indicates that we are currently parsing a pattern matching expression and impacts that calc...
const uint8_t * end
The pointer to the end of the source.
bool recovering
Whether or not we're currently recovering from a syntax error.
pm_node_flags_t integer_base
We want to add a flag to integer nodes that indicates their base.
bool warn_mismatched_indentation
By default, Ruby always warns about mismatched indentation.
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
bool in_keyword_arg
This flag indicates that we are currently parsing a keyword argument.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
struct pm_parser::@98 lex_modes
A stack of lex modes.
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.
pm_list_t comment_list
The list of comments that have been found while parsing.
size_t index
The current index into the lexer mode stack.
pm_string_t filepath
This is the path of the file being parsed.
pm_scope_t * current_scope
The current local scope.
bool command_start
Whether or not we're at the beginning of a command.
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
bool semantic_token_seen
Whether or not the parser has seen a token that has semantic meaning (i.e., a token that is not a com...
uint32_t node_id
The next node identifier that will be assigned.
struct pm_node * right
RangeNode::right.
struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode::unescaped.
struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
pm_node_t base
The embedded base node.
This struct represents a node in a linked list of scopes.
struct pm_scope * previous
A pointer to the previous scope in the linked list.
pm_node_list_t implicit_parameters
This is a list of the implicit parameters contained within the block.
pm_shareable_constant_value_t shareable_constant
The current state of constant shareability for this scope.
pm_locals_t locals
The IDs of the locals in the given scope.
pm_scope_parameters_t parameters
This is a bitfield that indicates the parameters that are being used in this scope.
bool closed
A boolean indicating whether or not this scope can see into its parent.
struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
size_t length
The length of the string in bytes of memory.
enum pm_string_t::@99 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.