15#define PM_TAB_WHITESPACE_SIZE 8
18#define MIN(a,b) (((a)<(b))?(a):(b))
19#define MAX(a,b) (((a)>(b))?(a):(b))
30lex_mode_incrementor(
const uint8_t start) {
47lex_mode_terminator(
const uint8_t start) {
89lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
90 uint8_t incrementor = lex_mode_incrementor(delimiter);
91 uint8_t terminator = lex_mode_terminator(delimiter);
97 .interpolation = interpolation,
98 .incrementor = incrementor,
99 .terminator = terminator
106 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.
as.list.
breakpoints));
111 if (terminator !=
'\0') {
112 breakpoints[index++] = terminator;
118 breakpoints[index++] =
'#';
122 if (incrementor !=
'\0') {
123 breakpoints[index++] = incrementor;
127 return lex_mode_push(parser, lex_mode);
137 return lex_mode_push_list(parser,
false,
'\0');
144lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
146 .mode = PM_LEX_REGEXP,
149 .incrementor = incrementor,
150 .terminator = terminator
158 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.
as.regexp.
breakpoints));
162 if (terminator !=
'\0') {
163 breakpoints[index++] = terminator;
167 if (incrementor !=
'\0') {
168 breakpoints[index++] = incrementor;
172 return lex_mode_push(parser, lex_mode);
179lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
181 .mode = PM_LEX_STRING,
184 .interpolation = interpolation,
185 .label_allowed = label_allowed,
186 .incrementor = incrementor,
187 .terminator = terminator
194 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.
as.string.
breakpoints));
199 if (terminator !=
'\0') {
200 breakpoints[index++] = terminator;
206 breakpoints[index++] =
'#';
211 if (incrementor !=
'\0') {
212 breakpoints[index++] = incrementor;
216 return lex_mode_push(parser, lex_mode);
226 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
258 PM_IGNORED_NEWLINE_NONE = 0,
259 PM_IGNORED_NEWLINE_ALL,
260 PM_IGNORED_NEWLINE_PATTERN
261} pm_ignored_newline_type_t;
263static inline pm_ignored_newline_type_t
265 bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
268 return PM_IGNORED_NEWLINE_ALL;
269 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
270 return PM_IGNORED_NEWLINE_PATTERN;
272 return PM_IGNORED_NEWLINE_NONE;
278 return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->
lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
283 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
287lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
291 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.end);
296 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
304 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
316#ifndef PM_DEBUG_LOGGING
321#define PM_DEBUG_LOGGING 0
327 fprintf(stderr,
"STATE: ");
330 if (parser->
lex_state == PM_LEX_STATE_NONE) {
331 fprintf(stderr,
"NONE\n");
335#define CHECK_STATE(state) \
336 if (parser->lex_state & state) { \
337 if (!first) fprintf(stderr, "|"); \
338 fprintf(stderr, "%s", #state); \
342 CHECK_STATE(PM_LEX_STATE_BEG)
343 CHECK_STATE(PM_LEX_STATE_END)
344 CHECK_STATE(PM_LEX_STATE_ENDARG)
345 CHECK_STATE(PM_LEX_STATE_ENDFN)
346 CHECK_STATE(PM_LEX_STATE_ARG)
347 CHECK_STATE(PM_LEX_STATE_CMDARG)
348 CHECK_STATE(PM_LEX_STATE_MID)
349 CHECK_STATE(PM_LEX_STATE_FNAME)
350 CHECK_STATE(PM_LEX_STATE_DOT)
351 CHECK_STATE(PM_LEX_STATE_CLASS)
352 CHECK_STATE(PM_LEX_STATE_LABEL)
353 CHECK_STATE(PM_LEX_STATE_LABELED)
354 CHECK_STATE(PM_LEX_STATE_FITEM)
358 fprintf(stderr,
"\n");
363 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
365 lex_state_set(parser, state);
366 fprintf(stderr,
"Now: ");
368 fprintf(stderr,
"\n");
371#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
379#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
382#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
385#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
388#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
391#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
394#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
397#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
408 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
414#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
415 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
423 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
430#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
431 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
446#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
447 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
453#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
454 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
471 pm_parser_err(parser, token->start, token->end, diag_id);
478#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
479 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
485#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
486 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
493 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
502 pm_parser_warn(parser, token->start, token->end, diag_id);
517#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
518 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
524#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
525 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
531#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
532 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
538#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
539 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
547pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
548 PM_PARSER_ERR_FORMAT(
551 ident_start + ident_length,
554 (
const char *) ident_start
566pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
568 if (scope == NULL)
return false;
573 .parameters = PM_SCOPE_PARAMETERS_NONE,
574 .implicit_parameters = { 0 },
592 if (scope->
previous == NULL)
return true;
593 if (scope->
closed)
return false;
594 }
while ((scope = scope->
previous) != NULL);
596 assert(
false &&
"unreachable");
604pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
607 while (depth-- > 0) {
608 assert(scope != NULL);
616 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
617 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
618 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
619} pm_scope_forwarding_param_check_result_t;
621static pm_scope_forwarding_param_check_result_t
622pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
624 bool conflict =
false;
626 while (scope != NULL) {
630 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
632 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
643 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
648 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
649 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
652 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
653 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
655 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
656 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
663 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
664 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
668 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
678 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
679 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
687 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
688 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
695 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
696 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
699 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
700 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
702 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
703 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
712pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
736#define PM_LOCALS_HASH_THRESHOLD 9
751 name = ((name >> 16) ^ name) * 0x45d9f3b;
752 name = ((name >> 16) ^ name) * 0x45d9f3b;
753 name = (name >> 16) ^ name;
763 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
764 assert(next_capacity > locals->
capacity);
767 if (next_locals == NULL) abort();
769 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
770 if (locals->
size > 0) {
776 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
777 uint32_t mask = next_capacity - 1;
779 for (uint32_t index = 0; index < locals->
capacity; index++) {
783 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
785 uint32_t hash = local->
hash;
787 next_locals[hash & mask] = *local;
792 pm_locals_free(locals);
793 locals->
locals = next_locals;
815 pm_locals_resize(locals);
818 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
819 for (uint32_t index = 0; index < locals->
capacity; index++) {
825 .location = { .start = start, .end = end },
826 .index = locals->
size++,
831 }
else if (local->
name == name) {
836 uint32_t mask = locals->
capacity - 1;
837 uint32_t hash = pm_locals_hash(name);
838 uint32_t initial_hash = hash;
846 .location = { .start = start, .end = end },
847 .index = locals->
size++,
852 }
else if (local->
name == name) {
857 }
while ((hash & mask) != initial_hash);
860 assert(
false &&
"unreachable");
870 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
871 for (uint32_t index = 0; index < locals->
size; index++) {
873 if (local->
name == name)
return index;
876 uint32_t mask = locals->
capacity - 1;
877 uint32_t hash = pm_locals_hash(name);
878 uint32_t initial_hash = hash & mask;
885 }
else if (local->
name == name) {
890 }
while ((hash & mask) != initial_hash);
902 uint32_t index = pm_locals_find(locals, name);
903 assert(index != UINT32_MAX);
906 assert(local->
reads < UINT32_MAX);
917 uint32_t index = pm_locals_find(locals, name);
918 assert(index != UINT32_MAX);
921 assert(local->
reads > 0);
931 uint32_t index = pm_locals_find(locals, name);
932 assert(index != UINT32_MAX);
947 pm_constant_id_list_init_capacity(list, locals->
size);
952 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
956 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
958 for (uint32_t index = 0; index < capacity; index++) {
962 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
964 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
965 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
967 if (constant->
length >= 1 && *constant->
start !=
'_') {
968 PM_PARSER_WARN_FORMAT(
972 PM_WARN_UNUSED_LOCAL_VARIABLE,
974 (
const char *) constant->
start
990pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
991 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
998pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
999 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1006pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1007 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1015 return pm_parser_constant_id_location(parser, token->start, token->end);
1036 while (node != NULL) {
1044 return void_node != NULL ? void_node : node;
1053 if (vn != NULL)
return vn;
1058 if (vn != NULL)
return vn;
1066 if (vn == NULL)
return NULL;
1067 if (void_node == NULL) void_node = vn;
1070 pm_node_t *vn = pm_check_value_expression(parser, (
pm_node_t *) rescue_clause->statements);
1075 if (void_node == NULL) {
1115 if (void_node == NULL) {
1130 if (void_node == NULL) {
1155 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1170 pm_node_t *void_node = pm_check_value_expression(parser, node);
1171 if (void_node != NULL) {
1172 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1181 const char *
type = NULL;
1191 type =
"a variable";
1199 switch (message->
length) {
1201 switch (message->
start[0]) {
1218 switch (message->
start[1]) {
1220 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1226 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1232 if (message->
start[0] ==
'*') {
1240 if (memcmp(message->
start,
"<=>", 3) == 0) {
1254 type =
"a constant";
1310 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1321 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1322 for (
size_t index = 0; index < size; index++) {
1323 pm_void_statement_check(parser, node->
body.
nodes[index]);
1333 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1334 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1335 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1336} pm_conditional_predicate_type_t;
1344 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1345 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1347 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1348 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1350 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1360pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1363 if (
PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1366 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1367 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1373 if (
PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1376 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1381 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1411 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1433 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1434 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1439 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1440 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1448 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1464 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1465 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1484 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1485 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1496 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1497 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1502 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1503 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1504 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1507 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1513 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1517 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1524 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1562#define PM_LOCATION_NULL_VALUE(parser) ((pm_location_t) { .start = (parser)->start, .end = (parser)->start })
1563#define PM_LOCATION_TOKEN_VALUE(token) ((pm_location_t) { .start = (token)->start, .end = (token)->end })
1564#define PM_LOCATION_NODE_VALUE(node) ((pm_location_t) { .start = (node)->location.start, .end = (node)->location.end })
1565#define PM_LOCATION_NODE_BASE_VALUE(node) ((pm_location_t) { .start = (node)->base.location.start, .end = (node)->base.location.end })
1566#define PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE ((pm_location_t) { .start = NULL, .end = NULL })
1567#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE : PM_LOCATION_TOKEN_VALUE(token))
1595static inline const uint8_t *
1597 if (arguments->
block != NULL) {
1638 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1652char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b) {
1657 }
else if (*b ==
'_') {
1659 }
else if (*b >= 0x80) {
1664 }
else if (*b < 0x80) {
1667 return pm_encoding_utf_8_char_width(b, parser->
end - b);
1676char_is_identifier_utf8(
const uint8_t *b,
const uint8_t *end) {
1680 return pm_encoding_utf_8_char_width(b, end - b);
1690char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b) {
1695 }
else if (*b ==
'_') {
1697 }
else if (*b >= 0x80) {
1703 return char_is_identifier_utf8(b, parser->
end);
1709#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1710#define PUNCT(idx) ( \
1711 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1712 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1713 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1714 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1715 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1718const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1724char_is_global_name_punctuation(const uint8_t b) {
1725 const unsigned int i = (const unsigned int) b;
1726 if (i <= 0x20 || 0x7e < i) return false;
1728 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1732token_is_setter_name(pm_token_t *token) {
1734 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1735 ((token->type == PM_TOKEN_IDENTIFIER) &&
1736 (token->end - token->start >= 2) &&
1737 (token->end[-1] == '='))
1745pm_local_is_keyword(const char *source, size_t length) {
1746#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1750 switch (source[0]) {
1751 case 'd': KEYWORD("do"); return false;
1752 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1753 case 'o': KEYWORD("or"); return false;
1754 default: return false;
1757 switch (source[0]) {
1758 case 'a': KEYWORD("and"); return false;
1759 case 'd': KEYWORD("def"); return false;
1760 case 'e': KEYWORD("end"); return false;
1761 case 'f': KEYWORD("for"); return false;
1762 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1763 default: return false;
1766 switch (source[0]) {
1767 case 'c': KEYWORD("case"); return false;
1768 case 'e': KEYWORD("else"); return false;
1769 case 'n': KEYWORD("next"); return false;
1770 case 'r': KEYWORD("redo"); return false;
1771 case 's': KEYWORD("self"); return false;
1772 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1773 case 'w': KEYWORD("when"); return false;
1774 default: return false;
1777 switch (source[0]) {
1778 case 'a': KEYWORD("alias"); return false;
1779 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1780 case 'c': KEYWORD("class"); return false;
1781 case 'e': KEYWORD("elsif"); return false;
1782 case 'f': KEYWORD("false"); return false;
1783 case 'r': KEYWORD("retry"); return false;
1784 case 's': KEYWORD("super"); return false;
1785 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1786 case 'w': KEYWORD("while"); return false;
1787 case 'y': KEYWORD("yield"); return false;
1788 default: return false;
1791 switch (source[0]) {
1792 case 'e': KEYWORD("ensure"); return false;
1793 case 'm': KEYWORD("module"); return false;
1794 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1795 case 'u': KEYWORD("unless"); return false;
1796 default: return false;
1799 KEYWORD("__LINE__");
1800 KEYWORD("__FILE__");
1803 KEYWORD("__ENCODING__");
1812/******************************************************************************/
1813/* Node flag handling functions */
1814/******************************************************************************/
1820pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1821 node->flags |= flag;
1828pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1829 node->flags &= (pm_node_flags_t) ~flag;
1836pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1837 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1838 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1839 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1840 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1841 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1842 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1843 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1844 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1846 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1849/******************************************************************************/
1850/* Node creation functions */
1851/******************************************************************************/
1858#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)
1863static inline pm_node_flags_t
1864pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1865 pm_node_flags_t flags = 0;
1867 if (closing->type == PM_TOKEN_REGEXP_END) {
1868 pm_buffer_t unknown_flags = { 0 };
1870 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1872 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1873 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1874 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1875 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1877 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1878 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1879 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1880 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1882 default: pm_buffer_append_byte(&unknown_flags, *flag);
1886 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1887 if (unknown_flags_length != 0) {
1888 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1889 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1891 pm_buffer_free(&unknown_flags);
1897#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1899static pm_statements_node_t *
1900pm_statements_node_create(pm_parser_t *parser);
1903pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1906pm_statements_node_body_length(pm_statements_node_t *node);
1913pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1914 void *memory = xcalloc(1, size);
1915 if (memory == NULL) {
1916 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1922#define PM_NODE_ALLOC(parser, type) (type *) pm_node_alloc(parser, sizeof(type))
1923#define PM_NODE_IDENTIFY(parser) (++parser->node_id)
1928static pm_missing_node_t *
1929pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1930 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1932 *node = (pm_missing_node_t) {{
1933 .type = PM_MISSING_NODE,
1934 .node_id = PM_NODE_IDENTIFY(parser),
1935 .location = { .start = start, .end = end }
1944static pm_alias_global_variable_node_t *
1945pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1946 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1947 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1949 *node = (pm_alias_global_variable_node_t) {
1951 .type = PM_ALIAS_GLOBAL_VARIABLE_NODE,
1952 .node_id = PM_NODE_IDENTIFY(parser),
1954 .start = keyword->start,
1955 .end = old_name->location.end
1958 .new_name = new_name,
1959 .old_name = old_name,
1960 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1969static pm_alias_method_node_t *
1970pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1971 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1972 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
1974 *node = (pm_alias_method_node_t) {
1976 .type = PM_ALIAS_METHOD_NODE,
1977 .node_id = PM_NODE_IDENTIFY(parser),
1979 .start = keyword->start,
1980 .end = old_name->location.end
1983 .new_name = new_name,
1984 .old_name = old_name,
1985 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1994static pm_alternation_pattern_node_t *
1995pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
1996 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
1998 *node = (pm_alternation_pattern_node_t) {
2000 .type = PM_ALTERNATION_PATTERN_NODE,
2001 .node_id = PM_NODE_IDENTIFY(parser),
2003 .start = left->location.start,
2004 .end = right->location.end
2009 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2018static pm_and_node_t *
2019pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2020 pm_assert_value_expression(parser, left);
2022 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2024 *node = (pm_and_node_t) {
2026 .type = PM_AND_NODE,
2027 .node_id = PM_NODE_IDENTIFY(parser),
2029 .start = left->location.start,
2030 .end = right->location.end
2034 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2044static pm_arguments_node_t *
2045pm_arguments_node_create(pm_parser_t *parser) {
2046 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2048 *node = (pm_arguments_node_t) {
2050 .type = PM_ARGUMENTS_NODE,
2051 .node_id = PM_NODE_IDENTIFY(parser),
2052 .location = PM_LOCATION_NULL_VALUE(parser)
2064pm_arguments_node_size(pm_arguments_node_t *node) {
2065 return node->arguments.size;
2072pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2073 if (pm_arguments_node_size(node) == 0) {
2074 node->base.location.start = argument->location.start;
2077 node->base.location.end = argument->location.end;
2078 pm_node_list_append(&node->arguments, argument);
2080 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2081 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2082 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2084 pm_node_flag_set((pm_node_t *) node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2092static pm_array_node_t *
2093pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2094 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2096 *node = (pm_array_node_t) {
2098 .type = PM_ARRAY_NODE,
2099 .flags = PM_NODE_FLAG_STATIC_LITERAL,
2100 .node_id = PM_NODE_IDENTIFY(parser),
2101 .location = PM_LOCATION_TOKEN_VALUE(opening)
2103 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2104 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2115pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2116 if (!node->elements.size && !node->opening_loc.start) {
2117 node->base.location.start = element->location.start;
2120 pm_node_list_append(&node->elements, element);
2121 node->base.location.end = element->location.end;
2123 // If the element is not a static literal, then the array is not a static
2124 // literal. Turn that flag off.
2125 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)) {
2126 pm_node_flag_unset((pm_node_t *)node, PM_NODE_FLAG_STATIC_LITERAL);
2129 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2130 pm_node_flag_set((pm_node_t *)node, PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2138pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2139 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2140 node->base.location.end = closing->end;
2141 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2148static pm_array_pattern_node_t *
2149pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2150 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2152 *node = (pm_array_pattern_node_t) {
2154 .type = PM_ARRAY_PATTERN_NODE,
2155 .node_id = PM_NODE_IDENTIFY(parser),
2157 .start = nodes->nodes[0]->location.start,
2158 .end = nodes->nodes[nodes->size - 1]->location.end
2165 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2166 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2169 // For now we're going to just copy over each pointer manually. This could be
2170 // much more efficient, as we could instead resize the node list.
2171 bool found_rest = false;
2174 PM_NODE_LIST_FOREACH(nodes, index, child) {
2175 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2178 } else if (found_rest) {
2179 pm_node_list_append(&node->posts, child);
2181 pm_node_list_append(&node->requireds, child);
2191static pm_array_pattern_node_t *
2192pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2193 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2195 *node = (pm_array_pattern_node_t) {
2197 .type = PM_ARRAY_PATTERN_NODE,
2198 .node_id = PM_NODE_IDENTIFY(parser),
2199 .location = rest->location,
2205 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2206 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2216static pm_array_pattern_node_t *
2217pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2218 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2220 *node = (pm_array_pattern_node_t) {
2222 .type = PM_ARRAY_PATTERN_NODE,
2223 .node_id = PM_NODE_IDENTIFY(parser),
2225 .start = constant->location.start,
2229 .constant = constant,
2231 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2232 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2244static pm_array_pattern_node_t *
2245pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2246 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2248 *node = (pm_array_pattern_node_t) {
2250 .type = PM_ARRAY_PATTERN_NODE,
2251 .node_id = PM_NODE_IDENTIFY(parser),
2253 .start = opening->start,
2259 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2260 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2269pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2270 pm_node_list_append(&node->requireds, inner);
2276static pm_assoc_node_t *
2277pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2278 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2281 if (value != NULL && value->location.end > key->location.end) {
2282 end = value->location.end;
2283 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2284 end = operator->end;
2286 end = key->location.end;
2289 // Hash string keys will be frozen, so we can mark them as frozen here so
2290 // that the compiler picks them up and also when we check for static literal
2291 // on the keys it gets factored in.
2292 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2293 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2296 // If the key and value of this assoc node are both static literals, then
2297 // we can mark this node as a static literal.
2298 pm_node_flags_t flags = 0;
2300 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2301 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)
2303 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2306 *node = (pm_assoc_node_t) {
2308 .type = PM_ASSOC_NODE,
2310 .node_id = PM_NODE_IDENTIFY(parser),
2312 .start = key->location.start,
2317 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2327static pm_assoc_splat_node_t *
2328pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2329 assert(operator->type == PM_TOKEN_USTAR_STAR);
2330 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2332 *node = (pm_assoc_splat_node_t) {
2334 .type = PM_ASSOC_SPLAT_NODE,
2335 .node_id = PM_NODE_IDENTIFY(parser),
2337 .start = operator->start,
2338 .end = value == NULL ? operator->end : value->location.end
2342 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2351static pm_back_reference_read_node_t *
2352pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2353 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2354 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2356 *node = (pm_back_reference_read_node_t) {
2358 .type = PM_BACK_REFERENCE_READ_NODE,
2359 .node_id = PM_NODE_IDENTIFY(parser),
2360 .location = PM_LOCATION_TOKEN_VALUE(name),
2362 .name = pm_parser_constant_id_token(parser, name)
2371static pm_begin_node_t *
2372pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2373 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2375 *node = (pm_begin_node_t) {
2377 .type = PM_BEGIN_NODE,
2378 .node_id = PM_NODE_IDENTIFY(parser),
2380 .start = begin_keyword->start,
2381 .end = statements == NULL ? begin_keyword->end : statements->base.location.end
2384 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2385 .statements = statements,
2386 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
2396pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2397 // If the begin keyword doesn't exist, we set the start on the begin_node
2398 if (!node->begin_keyword_loc.start) {
2399 node->base.location.start = rescue_clause->base.location.start;
2401 node->base.location.end = rescue_clause->base.location.end;
2402 node->rescue_clause = rescue_clause;
2409pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2410 node->base.location.end = else_clause->base.location.end;
2411 node->else_clause = else_clause;
2418pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2419 node->base.location.end = ensure_clause->base.location.end;
2420 node->ensure_clause = ensure_clause;
2427pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2428 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2430 node->base.location.end = end_keyword->end;
2431 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2437static pm_block_argument_node_t *
2438pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2439 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2441 *node = (pm_block_argument_node_t) {
2443 .type = PM_BLOCK_ARGUMENT_NODE,
2444 .node_id = PM_NODE_IDENTIFY(parser),
2446 .start = operator->start,
2447 .end = expression == NULL ? operator->end : expression->location.end
2450 .expression = expression,
2451 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2460static pm_block_node_t *
2461pm_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) {
2462 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2464 *node = (pm_block_node_t) {
2466 .type = PM_BLOCK_NODE,
2467 .node_id = PM_NODE_IDENTIFY(parser),
2468 .location = { .start = opening->start, .end = closing->end },
2471 .parameters = parameters,
2473 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2474 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2483static pm_block_parameter_node_t *
2484pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2485 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2486 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2488 *node = (pm_block_parameter_node_t) {
2490 .type = PM_BLOCK_PARAMETER_NODE,
2491 .node_id = PM_NODE_IDENTIFY(parser),
2493 .start = operator->start,
2494 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
2497 .name = pm_parser_optional_constant_id_token(parser, name),
2498 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2499 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2508static pm_block_parameters_node_t *
2509pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2510 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2512 const uint8_t *start;
2513 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2514 start = opening->start;
2515 } else if (parameters != NULL) {
2516 start = parameters->base.location.start;
2522 if (parameters != NULL) {
2523 end = parameters->base.location.end;
2524 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2530 *node = (pm_block_parameters_node_t) {
2532 .type = PM_BLOCK_PARAMETERS_NODE,
2533 .node_id = PM_NODE_IDENTIFY(parser),
2539 .parameters = parameters,
2540 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2541 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2552pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2553 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2555 node->base.location.end = closing->end;
2556 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2562static pm_block_local_variable_node_t *
2563pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2564 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2566 *node = (pm_block_local_variable_node_t) {
2568 .type = PM_BLOCK_LOCAL_VARIABLE_NODE,
2569 .node_id = PM_NODE_IDENTIFY(parser),
2570 .location = PM_LOCATION_TOKEN_VALUE(name),
2572 .name = pm_parser_constant_id_token(parser, name)
2582pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2583 pm_node_list_append(&node->locals, (pm_node_t *) local);
2585 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2586 node->base.location.end = local->base.location.end;
2592static pm_break_node_t *
2593pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2594 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2595 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2597 *node = (pm_break_node_t) {
2599 .type = PM_BREAK_NODE,
2600 .node_id = PM_NODE_IDENTIFY(parser),
2602 .start = keyword->start,
2603 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
2606 .arguments = arguments,
2607 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2613// There are certain flags that we want to use internally but don't want to
2614// expose because they are not relevant beyond parsing. Therefore we'll define
2615// them here and not define them in config.yml/a header file.
2616static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = 0x4;
2617static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = 0x40;
2618static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = 0x80;
2619static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = 0x100;
2626static pm_call_node_t *
2627pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2628 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2630 *node = (pm_call_node_t) {
2632 .type = PM_CALL_NODE,
2634 .node_id = PM_NODE_IDENTIFY(parser),
2635 .location = PM_LOCATION_NULL_VALUE(parser),
2638 .call_operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2639 .message_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2640 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2642 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
2654static inline pm_node_flags_t
2655pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2656 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2663static pm_call_node_t *
2664pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2665 pm_assert_value_expression(parser, receiver);
2667 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2668 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2669 flags |= PM_CALL_NODE_FLAGS_INDEX;
2672 pm_call_node_t *node = pm_call_node_create(parser, flags);
2674 node->base.location.start = receiver->location.start;
2675 node->base.location.end = pm_arguments_end(arguments);
2677 node->receiver = receiver;
2678 node->message_loc.start = arguments->opening_loc.start;
2679 node->message_loc.end = arguments->closing_loc.end;
2681 node->opening_loc = arguments->opening_loc;
2682 node->arguments = arguments->arguments;
2683 node->closing_loc = arguments->closing_loc;
2684 node->block = arguments->block;
2686 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2693static pm_call_node_t *
2694pm_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) {
2695 pm_assert_value_expression(parser, receiver);
2696 pm_assert_value_expression(parser, argument);
2698 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2700 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2701 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2703 node->receiver = receiver;
2704 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2706 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2707 pm_arguments_node_arguments_append(arguments, argument);
2708 node->arguments = arguments;
2710 node->name = pm_parser_constant_id_token(parser, operator);
2717static pm_call_node_t *
2718pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2719 pm_assert_value_expression(parser, receiver);
2721 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2723 node->base.location.start = receiver->location.start;
2724 const uint8_t *end = pm_arguments_end(arguments);
2728 node->base.location.end = end;
2730 node->receiver = receiver;
2731 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2732 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2733 node->opening_loc = arguments->opening_loc;
2734 node->arguments = arguments->arguments;
2735 node->closing_loc = arguments->closing_loc;
2736 node->block = arguments->block;
2738 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2739 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2742 node->name = pm_parser_constant_id_token(parser, message);
2749static pm_call_node_t *
2750pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2751 pm_call_node_t *node = pm_call_node_create(parser, 0);
2752 node->base.location.start = parser->start;
2753 node->base.location.end = parser->end;
2755 node->receiver = receiver;
2756 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2757 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2758 node->arguments = arguments;
2760 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2768static pm_call_node_t *
2769pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2770 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2772 node->base.location.start = message->start;
2773 node->base.location.end = pm_arguments_end(arguments);
2775 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2776 node->opening_loc = arguments->opening_loc;
2777 node->arguments = arguments->arguments;
2778 node->closing_loc = arguments->closing_loc;
2779 node->block = arguments->block;
2781 node->name = pm_parser_constant_id_token(parser, message);
2789static pm_call_node_t *
2790pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2791 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2793 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2794 node->arguments = arguments;
2803static pm_call_node_t *
2804pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2805 pm_assert_value_expression(parser, receiver);
2806 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2808 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2810 node->base.location.start = message->start;
2811 if (arguments->closing_loc.start != NULL) {
2812 node->base.location.end = arguments->closing_loc.end;
2814 assert(receiver != NULL);
2815 node->base.location.end = receiver->location.end;
2818 node->receiver = receiver;
2819 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2820 node->opening_loc = arguments->opening_loc;
2821 node->arguments = arguments->arguments;
2822 node->closing_loc = arguments->closing_loc;
2824 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2831static pm_call_node_t *
2832pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2833 pm_assert_value_expression(parser, receiver);
2835 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2837 node->base.location.start = receiver->location.start;
2838 node->base.location.end = pm_arguments_end(arguments);
2840 node->receiver = receiver;
2841 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2842 node->opening_loc = arguments->opening_loc;
2843 node->arguments = arguments->arguments;
2844 node->closing_loc = arguments->closing_loc;
2845 node->block = arguments->block;
2847 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2848 pm_node_flag_set((pm_node_t *)node, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2851 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2858static pm_call_node_t *
2859pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2860 pm_assert_value_expression(parser, receiver);
2862 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2864 node->base.location.start = operator->start;
2865 node->base.location.end = receiver->location.end;
2867 node->receiver = receiver;
2868 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2870 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2878static pm_call_node_t *
2879pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2880 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2882 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2883 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2885 node->name = pm_parser_constant_id_token(parser, message);
2894pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2896 (node->message_loc.start != NULL) &&
2897 (node->message_loc.end[-1] != '!') &&
2898 (node->message_loc.end[-1] != '?') &&
2899 char_is_identifier_start(parser, node->message_loc.start) &&
2900 (node->opening_loc.start == NULL) &&
2901 (node->arguments == NULL) &&
2902 (node->block == NULL)
2910pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2911 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2913 if (write_constant->length > 0) {
2914 size_t length = write_constant->length - 1;
2916 void *memory = xmalloc(length);
2917 memcpy(memory, write_constant->start, length);
2919 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2921 // We can get here if the message was missing because of a syntax error.
2922 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2929static pm_call_and_write_node_t *
2930pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2931 assert(target->block == NULL);
2932 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2933 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2935 *node = (pm_call_and_write_node_t) {
2937 .type = PM_CALL_AND_WRITE_NODE,
2938 .flags = target->base.flags,
2939 .node_id = PM_NODE_IDENTIFY(parser),
2941 .start = target->base.location.start,
2942 .end = value->location.end
2945 .receiver = target->receiver,
2946 .call_operator_loc = target->call_operator_loc,
2947 .message_loc = target->message_loc,
2949 .write_name = target->name,
2950 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2954 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2956 // Here we're going to free the target, since it is no longer necessary.
2957 // However, we don't want to call `pm_node_destroy` because we want to keep
2958 // around all of its children since we just reused them.
2969pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2970 if (parser->version != PM_OPTIONS_VERSION_CRUBY_3_3) {
2971 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2973 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2974 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2975 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2981 if (block != NULL) {
2982 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2990static pm_index_and_write_node_t *
2991pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2992 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2993 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
2995 pm_index_arguments_check(parser, target->arguments, target->block);
2997 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2998 *node = (pm_index_and_write_node_t) {
3000 .type = PM_INDEX_AND_WRITE_NODE,
3001 .flags = target->base.flags,
3002 .node_id = PM_NODE_IDENTIFY(parser),
3004 .start = target->base.location.start,
3005 .end = value->location.end
3008 .receiver = target->receiver,
3009 .call_operator_loc = target->call_operator_loc,
3010 .opening_loc = target->opening_loc,
3011 .arguments = target->arguments,
3012 .closing_loc = target->closing_loc,
3013 .block = (pm_block_argument_node_t *) target->block,
3014 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3018 // Here we're going to free the target, since it is no longer necessary.
3019 // However, we don't want to call `pm_node_destroy` because we want to keep
3020 // around all of its children since we just reused them.
3029static pm_call_operator_write_node_t *
3030pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3031 assert(target->block == NULL);
3032 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
3034 *node = (pm_call_operator_write_node_t) {
3036 .type = PM_CALL_OPERATOR_WRITE_NODE,
3037 .flags = target->base.flags,
3038 .node_id = PM_NODE_IDENTIFY(parser),
3040 .start = target->base.location.start,
3041 .end = value->location.end
3044 .receiver = target->receiver,
3045 .call_operator_loc = target->call_operator_loc,
3046 .message_loc = target->message_loc,
3048 .write_name = target->name,
3049 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3050 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3054 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3056 // Here we're going to free the target, since it is no longer necessary.
3057 // However, we don't want to call `pm_node_destroy` because we want to keep
3058 // around all of its children since we just reused them.
3067static pm_index_operator_write_node_t *
3068pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3069 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
3071 pm_index_arguments_check(parser, target->arguments, target->block);
3073 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3074 *node = (pm_index_operator_write_node_t) {
3076 .type = PM_INDEX_OPERATOR_WRITE_NODE,
3077 .flags = target->base.flags,
3078 .node_id = PM_NODE_IDENTIFY(parser),
3080 .start = target->base.location.start,
3081 .end = value->location.end
3084 .receiver = target->receiver,
3085 .call_operator_loc = target->call_operator_loc,
3086 .opening_loc = target->opening_loc,
3087 .arguments = target->arguments,
3088 .closing_loc = target->closing_loc,
3089 .block = (pm_block_argument_node_t *) target->block,
3090 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
3091 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3095 // Here we're going to free the target, since it is no longer necessary.
3096 // However, we don't want to call `pm_node_destroy` because we want to keep
3097 // around all of its children since we just reused them.
3106static pm_call_or_write_node_t *
3107pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3108 assert(target->block == NULL);
3109 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3110 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3112 *node = (pm_call_or_write_node_t) {
3114 .type = PM_CALL_OR_WRITE_NODE,
3115 .flags = target->base.flags,
3116 .node_id = PM_NODE_IDENTIFY(parser),
3118 .start = target->base.location.start,
3119 .end = value->location.end
3122 .receiver = target->receiver,
3123 .call_operator_loc = target->call_operator_loc,
3124 .message_loc = target->message_loc,
3126 .write_name = target->name,
3127 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3131 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3133 // Here we're going to free the target, since it is no longer necessary.
3134 // However, we don't want to call `pm_node_destroy` because we want to keep
3135 // around all of its children since we just reused them.
3144static pm_index_or_write_node_t *
3145pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3146 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3147 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3149 pm_index_arguments_check(parser, target->arguments, target->block);
3151 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3152 *node = (pm_index_or_write_node_t) {
3154 .type = PM_INDEX_OR_WRITE_NODE,
3155 .flags = target->base.flags,
3156 .node_id = PM_NODE_IDENTIFY(parser),
3158 .start = target->base.location.start,
3159 .end = value->location.end
3162 .receiver = target->receiver,
3163 .call_operator_loc = target->call_operator_loc,
3164 .opening_loc = target->opening_loc,
3165 .arguments = target->arguments,
3166 .closing_loc = target->closing_loc,
3167 .block = (pm_block_argument_node_t *) target->block,
3168 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3172 // Here we're going to free the target, since it is no longer necessary.
3173 // However, we don't want to call `pm_node_destroy` because we want to keep
3174 // around all of its children since we just reused them.
3184static pm_call_target_node_t *
3185pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3186 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3188 *node = (pm_call_target_node_t) {
3190 .type = PM_CALL_TARGET_NODE,
3191 .flags = target->base.flags,
3192 .node_id = PM_NODE_IDENTIFY(parser),
3193 .location = target->base.location
3195 .receiver = target->receiver,
3196 .call_operator_loc = target->call_operator_loc,
3197 .name = target->name,
3198 .message_loc = target->message_loc
3201 // Here we're going to free the target, since it is no longer necessary.
3202 // However, we don't want to call `pm_node_destroy` because we want to keep
3203 // around all of its children since we just reused them.
3213static pm_index_target_node_t *
3214pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3215 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3216 pm_node_flags_t flags = target->base.flags;
3218 pm_index_arguments_check(parser, target->arguments, target->block);
3220 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3221 *node = (pm_index_target_node_t) {
3223 .type = PM_INDEX_TARGET_NODE,
3224 .flags = flags | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3225 .node_id = PM_NODE_IDENTIFY(parser),
3226 .location = target->base.location
3228 .receiver = target->receiver,
3229 .opening_loc = target->opening_loc,
3230 .arguments = target->arguments,
3231 .closing_loc = target->closing_loc,
3232 .block = (pm_block_argument_node_t *) target->block,
3235 // Here we're going to free the target, since it is no longer necessary.
3236 // However, we don't want to call `pm_node_destroy` because we want to keep
3237 // around all of its children since we just reused them.
3246static pm_capture_pattern_node_t *
3247pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3248 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3250 *node = (pm_capture_pattern_node_t) {
3252 .type = PM_CAPTURE_PATTERN_NODE,
3253 .node_id = PM_NODE_IDENTIFY(parser),
3255 .start = value->location.start,
3256 .end = target->base.location.end
3261 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3270static pm_case_node_t *
3271pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3272 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3274 *node = (pm_case_node_t) {
3276 .type = PM_CASE_NODE,
3277 .node_id = PM_NODE_IDENTIFY(parser),
3279 .start = case_keyword->start,
3280 .end = end_keyword->end
3283 .predicate = predicate,
3284 .else_clause = NULL,
3285 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3286 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3297pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3298 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3300 pm_node_list_append(&node->conditions, condition);
3301 node->base.location.end = condition->location.end;
3308pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3309 node->else_clause = else_clause;
3310 node->base.location.end = else_clause->base.location.end;
3317pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3318 node->base.location.end = end_keyword->end;
3319 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3325static pm_case_match_node_t *
3326pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3327 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3329 *node = (pm_case_match_node_t) {
3331 .type = PM_CASE_MATCH_NODE,
3332 .node_id = PM_NODE_IDENTIFY(parser),
3334 .start = case_keyword->start,
3335 .end = end_keyword->end
3338 .predicate = predicate,
3339 .else_clause = NULL,
3340 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3341 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3352pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3353 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3355 pm_node_list_append(&node->conditions, condition);
3356 node->base.location.end = condition->location.end;
3363pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3364 node->else_clause = else_clause;
3365 node->base.location.end = else_clause->base.location.end;
3372pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3373 node->base.location.end = end_keyword->end;
3374 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3380static pm_class_node_t *
3381pm_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) {
3382 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3384 *node = (pm_class_node_t) {
3386 .type = PM_CLASS_NODE,
3387 .node_id = PM_NODE_IDENTIFY(parser),
3388 .location = { .start = class_keyword->start, .end = end_keyword->end },
3391 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3392 .constant_path = constant_path,
3393 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3394 .superclass = superclass,
3396 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3397 .name = pm_parser_constant_id_token(parser, name)
3406static pm_class_variable_and_write_node_t *
3407pm_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) {
3408 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3409 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3411 *node = (pm_class_variable_and_write_node_t) {
3413 .type = PM_CLASS_VARIABLE_AND_WRITE_NODE,
3414 .node_id = PM_NODE_IDENTIFY(parser),
3416 .start = target->base.location.start,
3417 .end = value->location.end
3420 .name = target->name,
3421 .name_loc = target->base.location,
3422 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3432static pm_class_variable_operator_write_node_t *
3433pm_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) {
3434 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3436 *node = (pm_class_variable_operator_write_node_t) {
3438 .type = PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE,
3439 .node_id = PM_NODE_IDENTIFY(parser),
3441 .start = target->base.location.start,
3442 .end = value->location.end
3445 .name = target->name,
3446 .name_loc = target->base.location,
3447 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3449 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3458static pm_class_variable_or_write_node_t *
3459pm_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) {
3460 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3461 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3463 *node = (pm_class_variable_or_write_node_t) {
3465 .type = PM_CLASS_VARIABLE_OR_WRITE_NODE,
3466 .node_id = PM_NODE_IDENTIFY(parser),
3468 .start = target->base.location.start,
3469 .end = value->location.end
3472 .name = target->name,
3473 .name_loc = target->base.location,
3474 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3484static pm_class_variable_read_node_t *
3485pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3486 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3487 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3489 *node = (pm_class_variable_read_node_t) {
3491 .type = PM_CLASS_VARIABLE_READ_NODE,
3492 .node_id = PM_NODE_IDENTIFY(parser),
3493 .location = PM_LOCATION_TOKEN_VALUE(token)
3495 .name = pm_parser_constant_id_token(parser, token)
3507static inline pm_node_flags_t
3508pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3509 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3518static pm_class_variable_write_node_t *
3519pm_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) {
3520 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3522 *node = (pm_class_variable_write_node_t) {
3524 .type = PM_CLASS_VARIABLE_WRITE_NODE,
3525 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3526 .node_id = PM_NODE_IDENTIFY(parser),
3528 .start = read_node->base.location.start,
3529 .end = value->location.end
3532 .name = read_node->name,
3533 .name_loc = PM_LOCATION_NODE_VALUE((pm_node_t *) read_node),
3534 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3544static pm_constant_path_and_write_node_t *
3545pm_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) {
3546 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3547 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3549 *node = (pm_constant_path_and_write_node_t) {
3551 .type = PM_CONSTANT_PATH_AND_WRITE_NODE,
3552 .node_id = PM_NODE_IDENTIFY(parser),
3554 .start = target->base.location.start,
3555 .end = value->location.end
3559 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3569static pm_constant_path_operator_write_node_t *
3570pm_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) {
3571 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3573 *node = (pm_constant_path_operator_write_node_t) {
3575 .type = PM_CONSTANT_PATH_OPERATOR_WRITE_NODE,
3576 .node_id = PM_NODE_IDENTIFY(parser),
3578 .start = target->base.location.start,
3579 .end = value->location.end
3583 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3585 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3594static pm_constant_path_or_write_node_t *
3595pm_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) {
3596 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3597 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3599 *node = (pm_constant_path_or_write_node_t) {
3601 .type = PM_CONSTANT_PATH_OR_WRITE_NODE,
3602 .node_id = PM_NODE_IDENTIFY(parser),
3604 .start = target->base.location.start,
3605 .end = value->location.end
3609 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3619static pm_constant_path_node_t *
3620pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3621 pm_assert_value_expression(parser, parent);
3622 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3624 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3625 if (name_token->type == PM_TOKEN_CONSTANT) {
3626 name = pm_parser_constant_id_token(parser, name_token);
3629 *node = (pm_constant_path_node_t) {
3631 .type = PM_CONSTANT_PATH_NODE,
3632 .node_id = PM_NODE_IDENTIFY(parser),
3634 .start = parent == NULL ? delimiter->start : parent->location.start,
3635 .end = name_token->end
3640 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3641 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3650static pm_constant_path_write_node_t *
3651pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3652 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3654 *node = (pm_constant_path_write_node_t) {
3656 .type = PM_CONSTANT_PATH_WRITE_NODE,
3657 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3658 .node_id = PM_NODE_IDENTIFY(parser),
3660 .start = target->base.location.start,
3661 .end = value->location.end
3665 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3675static pm_constant_and_write_node_t *
3676pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3677 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3678 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3680 *node = (pm_constant_and_write_node_t) {
3682 .type = PM_CONSTANT_AND_WRITE_NODE,
3683 .node_id = PM_NODE_IDENTIFY(parser),
3685 .start = target->base.location.start,
3686 .end = value->location.end
3689 .name = target->name,
3690 .name_loc = target->base.location,
3691 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3701static pm_constant_operator_write_node_t *
3702pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3703 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3705 *node = (pm_constant_operator_write_node_t) {
3707 .type = PM_CONSTANT_OPERATOR_WRITE_NODE,
3708 .node_id = PM_NODE_IDENTIFY(parser),
3710 .start = target->base.location.start,
3711 .end = value->location.end
3714 .name = target->name,
3715 .name_loc = target->base.location,
3716 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3718 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3727static pm_constant_or_write_node_t *
3728pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3729 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3730 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3732 *node = (pm_constant_or_write_node_t) {
3734 .type = PM_CONSTANT_OR_WRITE_NODE,
3735 .node_id = PM_NODE_IDENTIFY(parser),
3737 .start = target->base.location.start,
3738 .end = value->location.end
3741 .name = target->name,
3742 .name_loc = target->base.location,
3743 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3753static pm_constant_read_node_t *
3754pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3755 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3756 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3758 *node = (pm_constant_read_node_t) {
3760 .type = PM_CONSTANT_READ_NODE,
3761 .node_id = PM_NODE_IDENTIFY(parser),
3762 .location = PM_LOCATION_TOKEN_VALUE(name)
3764 .name = pm_parser_constant_id_token(parser, name)
3773static pm_constant_write_node_t *
3774pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3775 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3777 *node = (pm_constant_write_node_t) {
3779 .type = PM_CONSTANT_WRITE_NODE,
3780 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3781 .node_id = PM_NODE_IDENTIFY(parser),
3783 .start = target->base.location.start,
3784 .end = value->location.end
3787 .name = target->name,
3788 .name_loc = target->base.location,
3789 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3800pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3801 switch (PM_NODE_TYPE(node)) {
3802 case PM_BEGIN_NODE: {
3803 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3804 if (cast->statements != NULL) pm_def_node_receiver_check(parser, (pm_node_t *) cast->statements);
3807 case PM_PARENTHESES_NODE: {
3808 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3809 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3812 case PM_STATEMENTS_NODE: {
3813 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3814 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3819 case PM_IMAGINARY_NODE:
3820 case PM_INTEGER_NODE:
3821 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3822 case PM_INTERPOLATED_STRING_NODE:
3823 case PM_INTERPOLATED_SYMBOL_NODE:
3824 case PM_INTERPOLATED_X_STRING_NODE:
3825 case PM_RATIONAL_NODE:
3826 case PM_REGULAR_EXPRESSION_NODE:
3827 case PM_SOURCE_ENCODING_NODE:
3828 case PM_SOURCE_FILE_NODE:
3829 case PM_SOURCE_LINE_NODE:
3830 case PM_STRING_NODE:
3831 case PM_SYMBOL_NODE:
3832 case PM_X_STRING_NODE:
3833 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3843static pm_def_node_t *
3845 pm_parser_t *parser,
3846 pm_constant_id_t name,
3847 const pm_token_t *name_loc,
3848 pm_node_t *receiver,
3849 pm_parameters_node_t *parameters,
3851 pm_constant_id_list_t *locals,
3852 const pm_token_t *def_keyword,
3853 const pm_token_t *operator,
3854 const pm_token_t *lparen,
3855 const pm_token_t *rparen,
3856 const pm_token_t *equal,
3857 const pm_token_t *end_keyword
3859 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3862 if (end_keyword->type == PM_TOKEN_NOT_PROVIDED) {
3863 end = body->location.end;
3865 end = end_keyword->end;
3868 if ((receiver != NULL) && PM_NODE_TYPE_P(receiver, PM_PARENTHESES_NODE)) {
3869 pm_def_node_receiver_check(parser, receiver);
3872 *node = (pm_def_node_t) {
3874 .type = PM_DEF_NODE,
3875 .node_id = PM_NODE_IDENTIFY(parser),
3876 .location = { .start = def_keyword->start, .end = end },
3879 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3880 .receiver = receiver,
3881 .parameters = parameters,
3884 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3885 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3886 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3887 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3888 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3889 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3898static pm_defined_node_t *
3899pm_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) {
3900 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3902 *node = (pm_defined_node_t) {
3904 .type = PM_DEFINED_NODE,
3905 .node_id = PM_NODE_IDENTIFY(parser),
3907 .start = keyword_loc->start,
3908 .end = (rparen->type == PM_TOKEN_NOT_PROVIDED ? value->location.end : rparen->end)
3911 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3913 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3914 .keyword_loc = *keyword_loc
3923static pm_else_node_t *
3924pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3925 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3926 const uint8_t *end = NULL;
3927 if ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL)) {
3928 end = statements->base.location.end;
3930 end = end_keyword->end;
3933 *node = (pm_else_node_t) {
3935 .type = PM_ELSE_NODE,
3936 .node_id = PM_NODE_IDENTIFY(parser),
3938 .start = else_keyword->start,
3942 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3943 .statements = statements,
3944 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3953static pm_embedded_statements_node_t *
3954pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3955 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3957 *node = (pm_embedded_statements_node_t) {
3959 .type = PM_EMBEDDED_STATEMENTS_NODE,
3960 .node_id = PM_NODE_IDENTIFY(parser),
3962 .start = opening->start,
3966 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3967 .statements = statements,
3968 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3977static pm_embedded_variable_node_t *
3978pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3979 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3981 *node = (pm_embedded_variable_node_t) {
3983 .type = PM_EMBEDDED_VARIABLE_NODE,
3984 .node_id = PM_NODE_IDENTIFY(parser),
3986 .start = operator->start,
3987 .end = variable->location.end
3990 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3991 .variable = variable
4000static pm_ensure_node_t *
4001pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4002 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
4004 *node = (pm_ensure_node_t) {
4006 .type = PM_ENSURE_NODE,
4007 .node_id = PM_NODE_IDENTIFY(parser),
4009 .start = ensure_keyword->start,
4010 .end = end_keyword->end
4013 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
4014 .statements = statements,
4015 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4024static pm_false_node_t *
4025pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4026 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4027 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
4029 *node = (pm_false_node_t) {{
4030 .type = PM_FALSE_NODE,
4031 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4032 .node_id = PM_NODE_IDENTIFY(parser),
4033 .location = PM_LOCATION_TOKEN_VALUE(token)
4043static pm_find_pattern_node_t *
4044pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4045 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
4047 pm_node_t *left = nodes->nodes[0];
4048 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4049 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
4053 if (nodes->size == 1) {
4054 right = (pm_node_t *) pm_missing_node_create(parser, left->location.end, left->location.end);
4056 right = nodes->nodes[nodes->size - 1];
4057 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4060#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
4061 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
4062 // The resulting AST will anyway be ignored, but this file still needs to compile.
4063 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
4065 pm_node_t *right_splat_node = right;
4067 *node = (pm_find_pattern_node_t) {
4069 .type = PM_FIND_PATTERN_NODE,
4070 .node_id = PM_NODE_IDENTIFY(parser),
4072 .start = left->location.start,
4073 .end = right->location.end,
4077 .left = left_splat_node,
4078 .right = right_splat_node,
4080 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4081 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4084 // For now we're going to just copy over each pointer manually. This could be
4085 // much more efficient, as we could instead resize the node list to only point
4087 for (size_t index = 1; index < nodes->size - 1; index++) {
4088 pm_node_list_append(&node->requireds, nodes->nodes[index]);
4099pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4100 ptrdiff_t diff = token->end - token->start;
4101 if (diff <= 0) return 0.0;
4103 // First, get a buffer of the content.
4104 size_t length = (size_t) diff;
4105 char *buffer = xmalloc(sizeof(char) * (length + 1));
4106 memcpy((void *) buffer, token->start, length);
4108 // Next, determine if we need to replace the decimal point because of
4109 // locale-specific options, and then normalize them if we have to.
4110 char decimal_point = *localeconv()->decimal_point;
4111 if (decimal_point != '.') {
4112 for (size_t index = 0; index < length; index++) {
4113 if (buffer[index] == '.') buffer[index] = decimal_point;
4117 // Next, handle underscores by removing them from the buffer.
4118 for (size_t index = 0; index < length; index++) {
4119 if (buffer[index] == '_') {
4120 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4125 // Null-terminate the buffer so that strtod cannot read off the end.
4126 buffer[length] = '\0';
4128 // Now, call strtod to parse the value. Note that CRuby has their own
4129 // version of strtod which avoids locales. We're okay using the locale-aware
4130 // version because we've already validated through the parser that the token
4131 // is in a valid format.
4134 double value = strtod(buffer, &eptr);
4136 // This should never happen, because we've already checked that the token
4137 // is in a valid format. However it's good to be safe.
4138 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4139 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
4140 xfree((void *) buffer);
4144 // If errno is set, then it should only be ERANGE. At this point we need to
4145 // check if it's infinity (it should be).
4146 if (errno == ERANGE && PRISM_ISINF(value)) {
4148 const char *ellipsis;
4154 warn_width = (int) length;
4158 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);
4159 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4162 // Finally we can free the buffer and return the value.
4163 xfree((void *) buffer);
4170static pm_float_node_t *
4171pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4172 assert(token->type == PM_TOKEN_FLOAT);
4173 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
4175 *node = (pm_float_node_t) {
4177 .type = PM_FLOAT_NODE,
4178 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4179 .node_id = PM_NODE_IDENTIFY(parser),
4180 .location = PM_LOCATION_TOKEN_VALUE(token)
4182 .value = pm_double_parse(parser, token)
4191static pm_imaginary_node_t *
4192pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4193 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4195 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4196 *node = (pm_imaginary_node_t) {
4198 .type = PM_IMAGINARY_NODE,
4199 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4200 .node_id = PM_NODE_IDENTIFY(parser),
4201 .location = PM_LOCATION_TOKEN_VALUE(token)
4203 .numeric = (pm_node_t *) pm_float_node_create(parser, &((pm_token_t) {
4204 .type = PM_TOKEN_FLOAT,
4205 .start = token->start,
4206 .end = token->end - 1
4216static pm_rational_node_t *
4217pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4218 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4220 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4221 *node = (pm_rational_node_t) {
4223 .type = PM_RATIONAL_NODE,
4224 .flags = PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4225 .node_id = PM_NODE_IDENTIFY(parser),
4226 .location = PM_LOCATION_TOKEN_VALUE(token)
4229 .denominator = { 0 }
4232 const uint8_t *start = token->start;
4233 const uint8_t *end = token->end - 1; // r
4235 while (start < end && *start == '0') start++; // 0.1 -> .1
4236 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4238 size_t length = (size_t) (end - start);
4240 node->denominator.value = 1;
4244 const uint8_t *point = memchr(start, '.', length);
4245 assert(point && "should have a decimal point");
4247 uint8_t *digits = malloc(length);
4248 if (digits == NULL) {
4249 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4253 memcpy(digits, start, (unsigned long) (point - start));
4254 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4255 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4258 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
4259 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
4262 pm_integers_reduce(&node->numerator, &node->denominator);
4270static pm_imaginary_node_t *
4271pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4272 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4274 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4275 *node = (pm_imaginary_node_t) {
4277 .type = PM_IMAGINARY_NODE,
4278 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4279 .node_id = PM_NODE_IDENTIFY(parser),
4280 .location = PM_LOCATION_TOKEN_VALUE(token)
4282 .numeric = (pm_node_t *) pm_float_node_rational_create(parser, &((pm_token_t) {
4283 .type = PM_TOKEN_FLOAT_RATIONAL,
4284 .start = token->start,
4285 .end = token->end - 1
4295static pm_for_node_t *
4297 pm_parser_t *parser,
4299 pm_node_t *collection,
4300 pm_statements_node_t *statements,
4301 const pm_token_t *for_keyword,
4302 const pm_token_t *in_keyword,
4303 const pm_token_t *do_keyword,
4304 const pm_token_t *end_keyword
4306 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4308 *node = (pm_for_node_t) {
4310 .type = PM_FOR_NODE,
4311 .node_id = PM_NODE_IDENTIFY(parser),
4313 .start = for_keyword->start,
4314 .end = end_keyword->end
4318 .collection = collection,
4319 .statements = statements,
4320 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4321 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4322 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4323 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4332static pm_forwarding_arguments_node_t *
4333pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4334 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4335 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4337 *node = (pm_forwarding_arguments_node_t) {{
4338 .type = PM_FORWARDING_ARGUMENTS_NODE,
4339 .node_id = PM_NODE_IDENTIFY(parser),
4340 .location = PM_LOCATION_TOKEN_VALUE(token)
4349static pm_forwarding_parameter_node_t *
4350pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4351 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4352 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4354 *node = (pm_forwarding_parameter_node_t) {{
4355 .type = PM_FORWARDING_PARAMETER_NODE,
4356 .node_id = PM_NODE_IDENTIFY(parser),
4357 .location = PM_LOCATION_TOKEN_VALUE(token)
4366static pm_forwarding_super_node_t *
4367pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4368 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4369 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4370 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4372 pm_block_node_t *block = NULL;
4373 if (arguments->block != NULL) {
4374 block = (pm_block_node_t *) arguments->block;
4377 *node = (pm_forwarding_super_node_t) {
4379 .type = PM_FORWARDING_SUPER_NODE,
4380 .node_id = PM_NODE_IDENTIFY(parser),
4382 .start = token->start,
4383 .end = block != NULL ? block->base.location.end : token->end
4396static pm_hash_pattern_node_t *
4397pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4398 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4400 *node = (pm_hash_pattern_node_t) {
4402 .type = PM_HASH_PATTERN_NODE,
4403 .node_id = PM_NODE_IDENTIFY(parser),
4405 .start = opening->start,
4410 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4411 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4422static pm_hash_pattern_node_t *
4423pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4424 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4426 const uint8_t *start;
4429 if (elements->size > 0) {
4431 start = elements->nodes[0]->location.start;
4432 end = rest->location.end;
4434 start = elements->nodes[0]->location.start;
4435 end = elements->nodes[elements->size - 1]->location.end;
4438 assert(rest != NULL);
4439 start = rest->location.start;
4440 end = rest->location.end;
4443 *node = (pm_hash_pattern_node_t) {
4445 .type = PM_HASH_PATTERN_NODE,
4446 .node_id = PM_NODE_IDENTIFY(parser),
4455 .opening_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4456 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4460 PM_NODE_LIST_FOREACH(elements, index, element) {
4461 pm_node_list_append(&node->elements, element);
4470static pm_constant_id_t
4471pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4472 switch (PM_NODE_TYPE(target)) {
4473 case PM_GLOBAL_VARIABLE_READ_NODE:
4474 return ((pm_global_variable_read_node_t *) target)->name;
4475 case PM_BACK_REFERENCE_READ_NODE:
4476 return ((pm_back_reference_read_node_t *) target)->name;
4477 case PM_NUMBERED_REFERENCE_READ_NODE:
4478 // This will only ever happen in the event of a syntax error, but we
4479 // still need to provide something for the node.
4480 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4482 assert(false && "unreachable");
4483 return (pm_constant_id_t) -1;
4490static pm_global_variable_and_write_node_t *
4491pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4492 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4493 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4495 *node = (pm_global_variable_and_write_node_t) {
4497 .type = PM_GLOBAL_VARIABLE_AND_WRITE_NODE,
4498 .node_id = PM_NODE_IDENTIFY(parser),
4500 .start = target->location.start,
4501 .end = value->location.end
4504 .name = pm_global_variable_write_name(parser, target),
4505 .name_loc = target->location,
4506 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4516static pm_global_variable_operator_write_node_t *
4517pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4518 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4520 *node = (pm_global_variable_operator_write_node_t) {
4522 .type = PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE,
4523 .node_id = PM_NODE_IDENTIFY(parser),
4525 .start = target->location.start,
4526 .end = value->location.end
4529 .name = pm_global_variable_write_name(parser, target),
4530 .name_loc = target->location,
4531 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4533 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4542static pm_global_variable_or_write_node_t *
4543pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4544 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4545 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4547 *node = (pm_global_variable_or_write_node_t) {
4549 .type = PM_GLOBAL_VARIABLE_OR_WRITE_NODE,
4550 .node_id = PM_NODE_IDENTIFY(parser),
4552 .start = target->location.start,
4553 .end = value->location.end
4556 .name = pm_global_variable_write_name(parser, target),
4557 .name_loc = target->location,
4558 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4568static pm_global_variable_read_node_t *
4569pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4570 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4572 *node = (pm_global_variable_read_node_t) {
4574 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4575 .node_id = PM_NODE_IDENTIFY(parser),
4576 .location = PM_LOCATION_TOKEN_VALUE(name),
4578 .name = pm_parser_constant_id_token(parser, name)
4587static pm_global_variable_read_node_t *
4588pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4589 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4591 *node = (pm_global_variable_read_node_t) {
4593 .type = PM_GLOBAL_VARIABLE_READ_NODE,
4594 .node_id = PM_NODE_IDENTIFY(parser),
4595 .location = PM_LOCATION_NULL_VALUE(parser)
4606static pm_global_variable_write_node_t *
4607pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4608 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4610 *node = (pm_global_variable_write_node_t) {
4612 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4613 .node_id = PM_NODE_IDENTIFY(parser),
4614 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4616 .start = target->location.start,
4617 .end = value->location.end
4620 .name = pm_global_variable_write_name(parser, target),
4621 .name_loc = PM_LOCATION_NODE_VALUE(target),
4622 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4632static pm_global_variable_write_node_t *
4633pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4634 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4636 *node = (pm_global_variable_write_node_t) {
4638 .type = PM_GLOBAL_VARIABLE_WRITE_NODE,
4639 .node_id = PM_NODE_IDENTIFY(parser),
4640 .location = PM_LOCATION_NULL_VALUE(parser)
4643 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4644 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4654static pm_hash_node_t *
4655pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4656 assert(opening != NULL);
4657 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4659 *node = (pm_hash_node_t) {
4661 .type = PM_HASH_NODE,
4662 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4663 .node_id = PM_NODE_IDENTIFY(parser),
4664 .location = PM_LOCATION_TOKEN_VALUE(opening)
4666 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4667 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4678pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4679 pm_node_list_append(&hash->elements, element);
4681 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4682 if (static_literal) {
4683 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4684 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);
4685 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4686 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4689 if (!static_literal) {
4690 pm_node_flag_unset((pm_node_t *)hash, PM_NODE_FLAG_STATIC_LITERAL);
4695pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4696 hash->base.location.end = token->end;
4697 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4703static pm_if_node_t *
4704pm_if_node_create(pm_parser_t *parser,
4705 const pm_token_t *if_keyword,
4706 pm_node_t *predicate,
4707 const pm_token_t *then_keyword,
4708 pm_statements_node_t *statements,
4709 pm_node_t *subsequent,
4710 const pm_token_t *end_keyword
4712 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4713 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4716 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4717 end = end_keyword->end;
4718 } else if (subsequent != NULL) {
4719 end = subsequent->location.end;
4720 } else if (pm_statements_node_body_length(statements) != 0) {
4721 end = statements->base.location.end;
4723 end = predicate->location.end;
4726 *node = (pm_if_node_t) {
4729 .flags = PM_NODE_FLAG_NEWLINE,
4730 .node_id = PM_NODE_IDENTIFY(parser),
4732 .start = if_keyword->start,
4736 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4737 .predicate = predicate,
4738 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4739 .statements = statements,
4740 .subsequent = subsequent,
4741 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4750static pm_if_node_t *
4751pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4752 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4753 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4755 pm_statements_node_t *statements = pm_statements_node_create(parser);
4756 pm_statements_node_body_append(parser, statements, statement, true);
4758 *node = (pm_if_node_t) {
4761 .flags = PM_NODE_FLAG_NEWLINE,
4762 .node_id = PM_NODE_IDENTIFY(parser),
4764 .start = statement->location.start,
4765 .end = predicate->location.end
4768 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4769 .predicate = predicate,
4770 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4771 .statements = statements,
4773 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4782static pm_if_node_t *
4783pm_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) {
4784 pm_assert_value_expression(parser, predicate);
4785 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4787 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4788 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4790 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4791 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4793 pm_token_t end_keyword = not_provided(parser);
4794 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4796 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4798 *node = (pm_if_node_t) {
4801 .flags = PM_NODE_FLAG_NEWLINE,
4802 .node_id = PM_NODE_IDENTIFY(parser),
4804 .start = predicate->location.start,
4805 .end = false_expression->location.end,
4808 .if_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
4809 .predicate = predicate,
4810 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4811 .statements = if_statements,
4812 .subsequent = (pm_node_t *) else_node,
4813 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
4821pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4822 node->base.location.end = keyword->end;
4823 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4827pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4828 node->base.location.end = keyword->end;
4829 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4835static pm_implicit_node_t *
4836pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4837 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4839 *node = (pm_implicit_node_t) {
4841 .type = PM_IMPLICIT_NODE,
4842 .node_id = PM_NODE_IDENTIFY(parser),
4843 .location = value->location
4854static pm_implicit_rest_node_t *
4855pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4856 assert(token->type == PM_TOKEN_COMMA);
4858 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4860 *node = (pm_implicit_rest_node_t) {
4862 .type = PM_IMPLICIT_REST_NODE,
4863 .node_id = PM_NODE_IDENTIFY(parser),
4864 .location = PM_LOCATION_TOKEN_VALUE(token)
4874static pm_integer_node_t *
4875pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4876 assert(token->type == PM_TOKEN_INTEGER);
4877 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4879 *node = (pm_integer_node_t) {
4881 .type = PM_INTEGER_NODE,
4882 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4883 .node_id = PM_NODE_IDENTIFY(parser),
4884 .location = PM_LOCATION_TOKEN_VALUE(token)
4889 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4891 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4892 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4893 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4894 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4895 default: assert(false && "unreachable"); break;
4898 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4906static pm_imaginary_node_t *
4907pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4908 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4910 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4911 *node = (pm_imaginary_node_t) {
4913 .type = PM_IMAGINARY_NODE,
4914 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4915 .node_id = PM_NODE_IDENTIFY(parser),
4916 .location = PM_LOCATION_TOKEN_VALUE(token)
4918 .numeric = (pm_node_t *) pm_integer_node_create(parser, base, &((pm_token_t) {
4919 .type = PM_TOKEN_INTEGER,
4920 .start = token->start,
4921 .end = token->end - 1
4932static pm_rational_node_t *
4933pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4934 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4936 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4937 *node = (pm_rational_node_t) {
4939 .type = PM_RATIONAL_NODE,
4940 .flags = base | PM_NODE_FLAG_STATIC_LITERAL,
4941 .node_id = PM_NODE_IDENTIFY(parser),
4942 .location = PM_LOCATION_TOKEN_VALUE(token)
4945 .denominator = { .value = 1, 0 }
4948 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4950 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4951 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4952 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4953 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4954 default: assert(false && "unreachable"); break;
4957 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4966static pm_imaginary_node_t *
4967pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4968 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4970 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4971 *node = (pm_imaginary_node_t) {
4973 .type = PM_IMAGINARY_NODE,
4974 .flags = PM_NODE_FLAG_STATIC_LITERAL,
4975 .node_id = PM_NODE_IDENTIFY(parser),
4976 .location = PM_LOCATION_TOKEN_VALUE(token)
4978 .numeric = (pm_node_t *) pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4979 .type = PM_TOKEN_INTEGER_RATIONAL,
4980 .start = token->start,
4981 .end = token->end - 1
4991static pm_in_node_t *
4992pm_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) {
4993 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4996 if (statements != NULL) {
4997 end = statements->base.location.end;
4998 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4999 end = then_keyword->end;
5001 end = pattern->location.end;
5004 *node = (pm_in_node_t) {
5007 .node_id = PM_NODE_IDENTIFY(parser),
5009 .start = in_keyword->start,
5014 .statements = statements,
5015 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
5016 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
5025static pm_instance_variable_and_write_node_t *
5026pm_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) {
5027 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5028 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
5030 *node = (pm_instance_variable_and_write_node_t) {
5032 .type = PM_INSTANCE_VARIABLE_AND_WRITE_NODE,
5033 .node_id = PM_NODE_IDENTIFY(parser),
5035 .start = target->base.location.start,
5036 .end = value->location.end
5039 .name = target->name,
5040 .name_loc = target->base.location,
5041 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5051static pm_instance_variable_operator_write_node_t *
5052pm_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) {
5053 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
5055 *node = (pm_instance_variable_operator_write_node_t) {
5057 .type = PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE,
5058 .node_id = PM_NODE_IDENTIFY(parser),
5060 .start = target->base.location.start,
5061 .end = value->location.end
5064 .name = target->name,
5065 .name_loc = target->base.location,
5066 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5068 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
5077static pm_instance_variable_or_write_node_t *
5078pm_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) {
5079 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5080 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
5082 *node = (pm_instance_variable_or_write_node_t) {
5084 .type = PM_INSTANCE_VARIABLE_OR_WRITE_NODE,
5085 .node_id = PM_NODE_IDENTIFY(parser),
5087 .start = target->base.location.start,
5088 .end = value->location.end
5091 .name = target->name,
5092 .name_loc = target->base.location,
5093 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5103static pm_instance_variable_read_node_t *
5104pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
5105 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
5106 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
5108 *node = (pm_instance_variable_read_node_t) {
5110 .type = PM_INSTANCE_VARIABLE_READ_NODE,
5111 .node_id = PM_NODE_IDENTIFY(parser),
5112 .location = PM_LOCATION_TOKEN_VALUE(token)
5114 .name = pm_parser_constant_id_token(parser, token)
5124static pm_instance_variable_write_node_t *
5125pm_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) {
5126 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
5127 *node = (pm_instance_variable_write_node_t) {
5129 .type = PM_INSTANCE_VARIABLE_WRITE_NODE,
5130 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5131 .node_id = PM_NODE_IDENTIFY(parser),
5133 .start = read_node->base.location.start,
5134 .end = value->location.end
5137 .name = read_node->name,
5138 .name_loc = PM_LOCATION_NODE_BASE_VALUE(read_node),
5139 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
5152pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5153 switch (PM_NODE_TYPE(part)) {
5154 case PM_STRING_NODE:
5155 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5157 case PM_EMBEDDED_STATEMENTS_NODE: {
5158 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5159 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5161 if (embedded == NULL) {
5162 // If there are no statements or more than one statement, then
5163 // we lose the static literal flag.
5164 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5165 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5166 // If the embedded statement is a string, then we can keep the
5167 // static literal flag and mark the string as frozen.
5168 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5169 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5170 // If the embedded statement is an interpolated string and it's
5171 // a static literal, then we can keep the static literal flag.
5173 // Otherwise we lose the static literal flag.
5174 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5179 case PM_EMBEDDED_VARIABLE_NODE:
5180 pm_node_flag_unset((pm_node_t *) node, PM_NODE_FLAG_STATIC_LITERAL);
5183 assert(false && "unexpected node type");
5187 pm_node_list_append(parts, part);
5193static pm_interpolated_regular_expression_node_t *
5194pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5195 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
5197 *node = (pm_interpolated_regular_expression_node_t) {
5199 .type = PM_INTERPOLATED_REGULAR_EXPRESSION_NODE,
5200 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5201 .node_id = PM_NODE_IDENTIFY(parser),
5203 .start = opening->start,
5207 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5208 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
5216pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5217 if (node->base.location.start > part->location.start) {
5218 node->base.location.start = part->location.start;
5220 if (node->base.location.end < part->location.end) {
5221 node->base.location.end = part->location.end;
5224 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5228pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5229 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
5230 node->base.location.end = closing->end;
5231 pm_node_flag_set((pm_node_t *) node, pm_regular_expression_flags_create(parser, closing));
5258pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
5259#define CLEAR_FLAGS(node) \
5260 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))
5262#define MUTABLE_FLAGS(node) \
5263 node->base.flags = (pm_node_flags_t) ((node->base.flags | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5265 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5266 node->base.location.start = part->location.start;
5269 node->base.location.end = MAX(node->base.location.end, part->location.end);
5271 switch (PM_NODE_TYPE(part)) {
5272 case PM_STRING_NODE:
5273 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5275 case PM_INTERPOLATED_STRING_NODE:
5276 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5277 // If the string that we're concatenating is a static literal,
5278 // then we can keep the static literal flag for this string.
5280 // Otherwise, we lose the static literal flag here and we should
5281 // also clear the mutability flags.
5285 case PM_EMBEDDED_STATEMENTS_NODE: {
5286 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5287 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5289 if (embedded == NULL) {
5290 // If we're embedding multiple statements or no statements, then
5291 // the string is not longer a static literal.
5293 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5294 // If the embedded statement is a string, then we can make that
5295 // string as frozen and static literal, and not touch the static
5296 // literal status of this string.
5297 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5299 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5300 MUTABLE_FLAGS(node);
5302 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5303 // If the embedded statement is an interpolated string, but that
5304 // string is marked as static literal, then we can keep our
5305 // static literal status for this string.
5306 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5307 MUTABLE_FLAGS(node);
5310 // In all other cases, we lose the static literal flag here and
5317 case PM_EMBEDDED_VARIABLE_NODE:
5318 // Embedded variables clear static literal, which means we also
5319 // should clear the mutability flags.
5323 assert(false && "unexpected node type");
5327 pm_node_list_append(&node->parts, part);
5336static pm_interpolated_string_node_t *
5337pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5338 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
5339 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5341 switch (parser->frozen_string_literal) {
5342 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5343 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5345 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5346 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5350 *node = (pm_interpolated_string_node_t) {
5352 .type = PM_INTERPOLATED_STRING_NODE,
5354 .node_id = PM_NODE_IDENTIFY(parser),
5356 .start = opening->start,
5357 .end = closing->end,
5360 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5361 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5365 if (parts != NULL) {
5367 PM_NODE_LIST_FOREACH(parts, index, part) {
5368 pm_interpolated_string_node_append(node, part);
5379pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5380 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5381 node->base.location.end = closing->end;
5385pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5386 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
5387 node->base.location.start = part->location.start;
5390 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5391 node->base.location.end = MAX(node->base.location.end, part->location.end);
5395pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5396 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5397 node->base.location.end = closing->end;
5403static pm_interpolated_symbol_node_t *
5404pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5405 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
5407 *node = (pm_interpolated_symbol_node_t) {
5409 .type = PM_INTERPOLATED_SYMBOL_NODE,
5410 .flags = PM_NODE_FLAG_STATIC_LITERAL,
5411 .node_id = PM_NODE_IDENTIFY(parser),
5413 .start = opening->start,
5414 .end = closing->end,
5417 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5418 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5422 if (parts != NULL) {
5424 PM_NODE_LIST_FOREACH(parts, index, part) {
5425 pm_interpolated_symbol_node_append(node, part);
5435static pm_interpolated_x_string_node_t *
5436pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5437 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
5439 *node = (pm_interpolated_x_string_node_t) {
5441 .type = PM_INTERPOLATED_X_STRING_NODE,
5442 .node_id = PM_NODE_IDENTIFY(parser),
5444 .start = opening->start,
5448 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
5449 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
5457pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5458 pm_interpolated_node_append((pm_node_t *) node, &node->parts, part);
5459 node->base.location.end = part->location.end;
5463pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5464 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
5465 node->base.location.end = closing->end;
5471static pm_it_local_variable_read_node_t *
5472pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5473 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
5475 *node = (pm_it_local_variable_read_node_t) {
5477 .type = PM_IT_LOCAL_VARIABLE_READ_NODE,
5478 .node_id = PM_NODE_IDENTIFY(parser),
5479 .location = PM_LOCATION_TOKEN_VALUE(name)
5489static pm_it_parameters_node_t *
5490pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5491 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5493 *node = (pm_it_parameters_node_t) {
5495 .type = PM_IT_PARAMETERS_NODE,
5496 .node_id = PM_NODE_IDENTIFY(parser),
5498 .start = opening->start,
5510static pm_keyword_hash_node_t *
5511pm_keyword_hash_node_create(pm_parser_t *parser) {
5512 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5514 *node = (pm_keyword_hash_node_t) {
5516 .type = PM_KEYWORD_HASH_NODE,
5517 .flags = PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5518 .node_id = PM_NODE_IDENTIFY(parser),
5519 .location = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5531pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5532 // If the element being added is not an AssocNode or does not have a symbol
5533 // key, then we want to turn the SYMBOL_KEYS flag off.
5534 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5535 pm_node_flag_unset((pm_node_t *)hash, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5538 pm_node_list_append(&hash->elements, element);
5539 if (hash->base.location.start == NULL) {
5540 hash->base.location.start = element->location.start;
5542 hash->base.location.end = element->location.end;
5548static pm_required_keyword_parameter_node_t *
5549pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5550 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5552 *node = (pm_required_keyword_parameter_node_t) {
5554 .type = PM_REQUIRED_KEYWORD_PARAMETER_NODE,
5555 .node_id = PM_NODE_IDENTIFY(parser),
5557 .start = name->start,
5561 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5562 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5571static pm_optional_keyword_parameter_node_t *
5572pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5573 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5575 *node = (pm_optional_keyword_parameter_node_t) {
5577 .type = PM_OPTIONAL_KEYWORD_PARAMETER_NODE,
5578 .node_id = PM_NODE_IDENTIFY(parser),
5580 .start = name->start,
5581 .end = value->location.end
5584 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5585 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5595static pm_keyword_rest_parameter_node_t *
5596pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5597 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5599 *node = (pm_keyword_rest_parameter_node_t) {
5601 .type = PM_KEYWORD_REST_PARAMETER_NODE,
5602 .node_id = PM_NODE_IDENTIFY(parser),
5604 .start = operator->start,
5605 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
5608 .name = pm_parser_optional_constant_id_token(parser, name),
5609 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5610 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5619static pm_lambda_node_t *
5620pm_lambda_node_create(
5621 pm_parser_t *parser,
5622 pm_constant_id_list_t *locals,
5623 const pm_token_t *operator,
5624 const pm_token_t *opening,
5625 const pm_token_t *closing,
5626 pm_node_t *parameters,
5629 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5631 *node = (pm_lambda_node_t) {
5633 .type = PM_LAMBDA_NODE,
5634 .node_id = PM_NODE_IDENTIFY(parser),
5636 .start = operator->start,
5641 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5642 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5643 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5644 .parameters = parameters,
5654static pm_local_variable_and_write_node_t *
5655pm_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) {
5656 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)); assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5657 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5659 *node = (pm_local_variable_and_write_node_t) {
5661 .type = PM_LOCAL_VARIABLE_AND_WRITE_NODE,
5662 .node_id = PM_NODE_IDENTIFY(parser),
5664 .start = target->location.start,
5665 .end = value->location.end
5668 .name_loc = target->location,
5669 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5681static pm_local_variable_operator_write_node_t *
5682pm_local_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
5683 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5685 *node = (pm_local_variable_operator_write_node_t) {
5687 .type = PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE,
5688 .node_id = PM_NODE_IDENTIFY(parser),
5690 .start = target->location.start,
5691 .end = value->location.end
5694 .name_loc = target->location,
5695 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5698 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5708static pm_local_variable_or_write_node_t *
5709pm_local_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value, pm_constant_id_t name, uint32_t depth) {
5710 assert(PM_NODE_TYPE_P(target, PM_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_IT_LOCAL_VARIABLE_READ_NODE) || PM_NODE_TYPE_P(target, PM_CALL_NODE));
5711 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5712 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5714 *node = (pm_local_variable_or_write_node_t) {
5716 .type = PM_LOCAL_VARIABLE_OR_WRITE_NODE,
5717 .node_id = PM_NODE_IDENTIFY(parser),
5719 .start = target->location.start,
5720 .end = value->location.end
5723 .name_loc = target->location,
5724 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5736static pm_local_variable_read_node_t *
5737pm_local_variable_read_node_create_constant_id(pm_parser_t *parser, const pm_token_t *name, pm_constant_id_t name_id, uint32_t depth, bool missing) {
5738 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5740 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5742 *node = (pm_local_variable_read_node_t) {
5744 .type = PM_LOCAL_VARIABLE_READ_NODE,
5745 .node_id = PM_NODE_IDENTIFY(parser),
5746 .location = PM_LOCATION_TOKEN_VALUE(name)
5758static pm_local_variable_read_node_t *
5759pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5760 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5761 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5768static pm_local_variable_read_node_t *
5769pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5770 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5771 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5777static pm_local_variable_write_node_t *
5778pm_local_variable_write_node_create(pm_parser_t *parser, pm_constant_id_t name, uint32_t depth, pm_node_t *value, const pm_location_t *name_loc, const pm_token_t *operator) {
5779 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5781 *node = (pm_local_variable_write_node_t) {
5783 .type = PM_LOCAL_VARIABLE_WRITE_NODE,
5784 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5785 .node_id = PM_NODE_IDENTIFY(parser),
5787 .start = name_loc->start,
5788 .end = value->location.end
5794 .name_loc = *name_loc,
5795 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5805pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5806 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5814pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5815 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5823pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5824 if (pm_token_is_numbered_parameter(start, end)) {
5825 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5833static pm_local_variable_target_node_t *
5834pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5835 pm_refute_numbered_parameter(parser, location->start, location->end);
5836 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5838 *node = (pm_local_variable_target_node_t) {
5840 .type = PM_LOCAL_VARIABLE_TARGET_NODE,
5841 .node_id = PM_NODE_IDENTIFY(parser),
5842 .location = *location
5854static pm_match_predicate_node_t *
5855pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5856 pm_assert_value_expression(parser, value);
5858 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5860 *node = (pm_match_predicate_node_t) {
5862 .type = PM_MATCH_PREDICATE_NODE,
5863 .node_id = PM_NODE_IDENTIFY(parser),
5865 .start = value->location.start,
5866 .end = pattern->location.end
5871 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5880static pm_match_required_node_t *
5881pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5882 pm_assert_value_expression(parser, value);
5884 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5886 *node = (pm_match_required_node_t) {
5888 .type = PM_MATCH_REQUIRED_NODE,
5889 .node_id = PM_NODE_IDENTIFY(parser),
5891 .start = value->location.start,
5892 .end = pattern->location.end
5897 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5906static pm_match_write_node_t *
5907pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5908 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5910 *node = (pm_match_write_node_t) {
5912 .type = PM_MATCH_WRITE_NODE,
5913 .node_id = PM_NODE_IDENTIFY(parser),
5914 .location = call->base.location
5926static pm_module_node_t *
5927pm_module_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *module_keyword, pm_node_t *constant_path, const pm_token_t *name, pm_node_t *body, const pm_token_t *end_keyword) {
5928 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5930 *node = (pm_module_node_t) {
5932 .type = PM_MODULE_NODE,
5933 .node_id = PM_NODE_IDENTIFY(parser),
5935 .start = module_keyword->start,
5936 .end = end_keyword->end
5939 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5940 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5941 .constant_path = constant_path,
5943 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5944 .name = pm_parser_constant_id_token(parser, name)
5953static pm_multi_target_node_t *
5954pm_multi_target_node_create(pm_parser_t *parser) {
5955 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5957 *node = (pm_multi_target_node_t) {
5959 .type = PM_MULTI_TARGET_NODE,
5960 .node_id = PM_NODE_IDENTIFY(parser),
5961 .location = { .start = NULL, .end = NULL }
5966 .lparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
5967 .rparen_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
5977pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5978 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5979 if (node->rest == NULL) {
5980 node->rest = target;
5982 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5983 pm_node_list_append(&node->rights, target);
5985 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5986 if (node->rest == NULL) {
5987 node->rest = target;
5989 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5990 pm_node_list_append(&node->rights, target);
5992 } else if (node->rest == NULL) {
5993 pm_node_list_append(&node->lefts, target);
5995 pm_node_list_append(&node->rights, target);
5998 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
5999 node->base.location.start = target->location.start;
6002 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
6003 node->base.location.end = target->location.end;
6011pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
6012 node->base.location.start = lparen->start;
6013 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
6020pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
6021 node->base.location.end = rparen->end;
6022 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
6028static pm_multi_write_node_t *
6029pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
6030 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
6032 *node = (pm_multi_write_node_t) {
6034 .type = PM_MULTI_WRITE_NODE,
6035 .flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
6036 .node_id = PM_NODE_IDENTIFY(parser),
6038 .start = target->base.location.start,
6039 .end = value->location.end
6042 .lefts = target->lefts,
6043 .rest = target->rest,
6044 .rights = target->rights,
6045 .lparen_loc = target->lparen_loc,
6046 .rparen_loc = target->rparen_loc,
6047 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6051 // Explicitly do not call pm_node_destroy here because we want to keep
6052 // around all of the information within the MultiWriteNode node.
6061static pm_next_node_t *
6062pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6063 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
6064 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
6066 *node = (pm_next_node_t) {
6068 .type = PM_NEXT_NODE,
6069 .node_id = PM_NODE_IDENTIFY(parser),
6071 .start = keyword->start,
6072 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6075 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6076 .arguments = arguments
6085static pm_nil_node_t *
6086pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
6087 assert(token->type == PM_TOKEN_KEYWORD_NIL);
6088 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
6090 *node = (pm_nil_node_t) {{
6091 .type = PM_NIL_NODE,
6092 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6093 .node_id = PM_NODE_IDENTIFY(parser),
6094 .location = PM_LOCATION_TOKEN_VALUE(token)
6103static pm_no_keywords_parameter_node_t *
6104pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
6105 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
6106 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
6107 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
6109 *node = (pm_no_keywords_parameter_node_t) {
6111 .type = PM_NO_KEYWORDS_PARAMETER_NODE,
6112 .node_id = PM_NODE_IDENTIFY(parser),
6114 .start = operator->start,
6118 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6119 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
6128static pm_numbered_parameters_node_t *
6129pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
6130 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
6132 *node = (pm_numbered_parameters_node_t) {
6134 .type = PM_NUMBERED_PARAMETERS_NODE,
6135 .node_id = PM_NODE_IDENTIFY(parser),
6136 .location = *location
6148#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
6157pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
6158 const uint8_t *start = token->start + 1;
6159 const uint8_t *end = token->end;
6161 ptrdiff_t diff = end - start;
6162 assert(diff > 0 && ((unsigned long) diff < SIZE_MAX));
6163 size_t length = (size_t) diff;
6165 char *digits = xcalloc(length + 1, sizeof(char));
6166 memcpy(digits, start, length);
6167 digits[length] = '\0';
6171 unsigned long value = strtoul(digits, &endptr, 10);
6173 if ((digits == endptr) || (*endptr != '\0')) {
6174 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
6180 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
6181 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
6185 return (uint32_t) value;
6193static pm_numbered_reference_read_node_t *
6194pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
6195 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
6196 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
6198 *node = (pm_numbered_reference_read_node_t) {
6200 .type = PM_NUMBERED_REFERENCE_READ_NODE,
6201 .node_id = PM_NODE_IDENTIFY(parser),
6202 .location = PM_LOCATION_TOKEN_VALUE(name),
6204 .number = pm_numbered_reference_read_node_number(parser, name)
6213static pm_optional_parameter_node_t *
6214pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
6215 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
6217 *node = (pm_optional_parameter_node_t) {
6219 .type = PM_OPTIONAL_PARAMETER_NODE,
6220 .node_id = PM_NODE_IDENTIFY(parser),
6222 .start = name->start,
6223 .end = value->location.end
6226 .name = pm_parser_constant_id_token(parser, name),
6227 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
6228 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6238static pm_or_node_t *
6239pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6240 pm_assert_value_expression(parser, left);
6242 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
6244 *node = (pm_or_node_t) {
6247 .node_id = PM_NODE_IDENTIFY(parser),
6249 .start = left->location.start,
6250 .end = right->location.end
6255 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6264static pm_parameters_node_t *
6265pm_parameters_node_create(pm_parser_t *parser) {
6266 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
6268 *node = (pm_parameters_node_t) {
6270 .type = PM_PARAMETERS_NODE,
6271 .node_id = PM_NODE_IDENTIFY(parser),
6272 .location = PM_LOCATION_TOKEN_VALUE(&parser->current)
6275 .keyword_rest = NULL,
6290pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6291 if (params->base.location.start == NULL) {
6292 params->base.location.start = param->location.start;
6294 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
6297 if (params->base.location.end == NULL) {
6298 params->base.location.end = param->location.end;
6300 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
6308pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
6309 pm_parameters_node_location_set(params, param);
6310 pm_node_list_append(¶ms->requireds, param);
6317pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6318 pm_parameters_node_location_set(params, (pm_node_t *) param);
6319 pm_node_list_append(¶ms->optionals, (pm_node_t *) param);
6326pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
6327 pm_parameters_node_location_set(params, param);
6328 pm_node_list_append(¶ms->posts, param);
6335pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6336 pm_parameters_node_location_set(params, param);
6337 params->rest = param;
6344pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
6345 pm_parameters_node_location_set(params, param);
6346 pm_node_list_append(¶ms->keywords, param);
6353pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6354 assert(params->keyword_rest == NULL);
6355 pm_parameters_node_location_set(params, param);
6356 params->keyword_rest = param;
6363pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
6364 assert(params->block == NULL);
6365 pm_parameters_node_location_set(params, (pm_node_t *) param);
6366 params->block = param;
6372static pm_program_node_t *
6373pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6374 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
6376 *node = (pm_program_node_t) {
6378 .type = PM_PROGRAM_NODE,
6379 .node_id = PM_NODE_IDENTIFY(parser),
6381 .start = statements == NULL ? parser->start : statements->base.location.start,
6382 .end = statements == NULL ? parser->end : statements->base.location.end
6386 .statements = statements
6395static pm_parentheses_node_t *
6396pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing) {
6397 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
6399 *node = (pm_parentheses_node_t) {
6401 .type = PM_PARENTHESES_NODE,
6402 .node_id = PM_NODE_IDENTIFY(parser),
6404 .start = opening->start,
6409 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6410 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6419static pm_pinned_expression_node_t *
6420pm_pinned_expression_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *operator, const pm_token_t *lparen, const pm_token_t *rparen) {
6421 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
6423 *node = (pm_pinned_expression_node_t) {
6425 .type = PM_PINNED_EXPRESSION_NODE,
6426 .node_id = PM_NODE_IDENTIFY(parser),
6428 .start = operator->start,
6432 .expression = expression,
6433 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6434 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
6435 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
6444static pm_pinned_variable_node_t *
6445pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6446 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
6448 *node = (pm_pinned_variable_node_t) {
6450 .type = PM_PINNED_VARIABLE_NODE,
6451 .node_id = PM_NODE_IDENTIFY(parser),
6453 .start = operator->start,
6454 .end = variable->location.end
6457 .variable = variable,
6458 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6467static pm_post_execution_node_t *
6468pm_post_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
6469 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
6471 *node = (pm_post_execution_node_t) {
6473 .type = PM_POST_EXECUTION_NODE,
6474 .node_id = PM_NODE_IDENTIFY(parser),
6476 .start = keyword->start,
6480 .statements = statements,
6481 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6482 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6483 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6492static pm_pre_execution_node_t *
6493pm_pre_execution_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
6494 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
6496 *node = (pm_pre_execution_node_t) {
6498 .type = PM_PRE_EXECUTION_NODE,
6499 .node_id = PM_NODE_IDENTIFY(parser),
6501 .start = keyword->start,
6505 .statements = statements,
6506 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6507 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6508 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
6517static pm_range_node_t *
6518pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6519 pm_assert_value_expression(parser, left);
6520 pm_assert_value_expression(parser, right);
6522 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
6523 pm_node_flags_t flags = 0;
6525 // Indicate that this node is an exclusive range if the operator is `...`.
6526 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6527 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6530 // Indicate that this node is a static literal (i.e., can be compiled with
6531 // a putobject in CRuby) if the left and right are implicit nil, explicit
6532 // nil, or integers.
6534 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6535 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6537 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6540 *node = (pm_range_node_t) {
6542 .type = PM_RANGE_NODE,
6544 .node_id = PM_NODE_IDENTIFY(parser),
6546 .start = (left == NULL ? operator->start : left->location.start),
6547 .end = (right == NULL ? operator->end : right->location.end)
6552 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6561static pm_redo_node_t *
6562pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6563 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6564 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
6566 *node = (pm_redo_node_t) {{
6567 .type = PM_REDO_NODE,
6568 .node_id = PM_NODE_IDENTIFY(parser),
6569 .location = PM_LOCATION_TOKEN_VALUE(token)
6579static pm_regular_expression_node_t *
6580pm_regular_expression_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
6581 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
6583 *node = (pm_regular_expression_node_t) {
6585 .type = PM_REGULAR_EXPRESSION_NODE,
6586 .flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6587 .node_id = PM_NODE_IDENTIFY(parser),
6589 .start = MIN(opening->start, closing->start),
6590 .end = MAX(opening->end, closing->end)
6593 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
6594 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6595 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
6596 .unescaped = *unescaped
6605static inline pm_regular_expression_node_t *
6606pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6607 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6613static pm_required_parameter_node_t *
6614pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6615 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
6617 *node = (pm_required_parameter_node_t) {
6619 .type = PM_REQUIRED_PARAMETER_NODE,
6620 .node_id = PM_NODE_IDENTIFY(parser),
6621 .location = PM_LOCATION_TOKEN_VALUE(token)
6623 .name = pm_parser_constant_id_token(parser, token)
6632static pm_rescue_modifier_node_t *
6633pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6634 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
6636 *node = (pm_rescue_modifier_node_t) {
6638 .type = PM_RESCUE_MODIFIER_NODE,
6639 .node_id = PM_NODE_IDENTIFY(parser),
6641 .start = expression->location.start,
6642 .end = rescue_expression->location.end
6645 .expression = expression,
6646 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6647 .rescue_expression = rescue_expression
6656static pm_rescue_node_t *
6657pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6658 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
6660 *node = (pm_rescue_node_t) {
6662 .type = PM_RESCUE_NODE,
6663 .node_id = PM_NODE_IDENTIFY(parser),
6664 .location = PM_LOCATION_TOKEN_VALUE(keyword)
6666 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6667 .operator_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
6678pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
6679 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
6686pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6687 node->reference = reference;
6688 node->base.location.end = reference->location.end;
6695pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6696 node->statements = statements;
6697 if (pm_statements_node_body_length(statements) > 0) {
6698 node->base.location.end = statements->base.location.end;
6706pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6707 node->subsequent = subsequent;
6708 node->base.location.end = subsequent->base.location.end;
6715pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6716 pm_node_list_append(&node->exceptions, exception);
6717 node->base.location.end = exception->location.end;
6723static pm_rest_parameter_node_t *
6724pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6725 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6727 *node = (pm_rest_parameter_node_t) {
6729 .type = PM_REST_PARAMETER_NODE,
6730 .node_id = PM_NODE_IDENTIFY(parser),
6732 .start = operator->start,
6733 .end = (name->type == PM_TOKEN_NOT_PROVIDED ? operator->end : name->end)
6736 .name = pm_parser_optional_constant_id_token(parser, name),
6737 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6738 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6747static pm_retry_node_t *
6748pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6749 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6750 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6752 *node = (pm_retry_node_t) {{
6753 .type = PM_RETRY_NODE,
6754 .node_id = PM_NODE_IDENTIFY(parser),
6755 .location = PM_LOCATION_TOKEN_VALUE(token)
6764static pm_return_node_t *
6765pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6766 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6768 *node = (pm_return_node_t) {
6770 .type = PM_RETURN_NODE,
6771 .node_id = PM_NODE_IDENTIFY(parser),
6773 .start = keyword->start,
6774 .end = (arguments == NULL ? keyword->end : arguments->base.location.end)
6777 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6778 .arguments = arguments
6787static pm_self_node_t *
6788pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6789 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6790 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6792 *node = (pm_self_node_t) {{
6793 .type = PM_SELF_NODE,
6794 .node_id = PM_NODE_IDENTIFY(parser),
6795 .location = PM_LOCATION_TOKEN_VALUE(token)
6804static pm_shareable_constant_node_t *
6805pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6806 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6808 *node = (pm_shareable_constant_node_t) {
6810 .type = PM_SHAREABLE_CONSTANT_NODE,
6811 .flags = (pm_node_flags_t) value,
6812 .node_id = PM_NODE_IDENTIFY(parser),
6813 .location = PM_LOCATION_NODE_VALUE(write)
6824static pm_singleton_class_node_t *
6825pm_singleton_class_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, const pm_token_t *class_keyword, const pm_token_t *operator, pm_node_t *expression, pm_node_t *body, const pm_token_t *end_keyword) {
6826 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6828 *node = (pm_singleton_class_node_t) {
6830 .type = PM_SINGLETON_CLASS_NODE,
6831 .node_id = PM_NODE_IDENTIFY(parser),
6833 .start = class_keyword->start,
6834 .end = end_keyword->end
6838 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6839 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6840 .expression = expression,
6842 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6851static pm_source_encoding_node_t *
6852pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6853 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6854 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6856 *node = (pm_source_encoding_node_t) {{
6857 .type = PM_SOURCE_ENCODING_NODE,
6858 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6859 .node_id = PM_NODE_IDENTIFY(parser),
6860 .location = PM_LOCATION_TOKEN_VALUE(token)
6869static pm_source_file_node_t*
6870pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6871 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6872 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6874 pm_node_flags_t flags = 0;
6876 switch (parser->frozen_string_literal) {
6877 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6878 flags |= PM_STRING_FLAGS_MUTABLE;
6880 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6881 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6885 *node = (pm_source_file_node_t) {
6887 .type = PM_SOURCE_FILE_NODE,
6889 .node_id = PM_NODE_IDENTIFY(parser),
6890 .location = PM_LOCATION_TOKEN_VALUE(file_keyword),
6892 .filepath = parser->filepath
6901static pm_source_line_node_t *
6902pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6903 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6904 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6906 *node = (pm_source_line_node_t) {{
6907 .type = PM_SOURCE_LINE_NODE,
6908 .flags = PM_NODE_FLAG_STATIC_LITERAL,
6909 .node_id = PM_NODE_IDENTIFY(parser),
6910 .location = PM_LOCATION_TOKEN_VALUE(token)
6919static pm_splat_node_t *
6920pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6921 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6923 *node = (pm_splat_node_t) {
6925 .type = PM_SPLAT_NODE,
6926 .node_id = PM_NODE_IDENTIFY(parser),
6928 .start = operator->start,
6929 .end = (expression == NULL ? operator->end : expression->location.end)
6932 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6933 .expression = expression
6942static pm_statements_node_t *
6943pm_statements_node_create(pm_parser_t *parser) {
6944 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6946 *node = (pm_statements_node_t) {
6948 .type = PM_STATEMENTS_NODE,
6949 .node_id = PM_NODE_IDENTIFY(parser),
6950 .location = PM_LOCATION_NULL_VALUE(parser)
6962pm_statements_node_body_length(pm_statements_node_t *node) {
6963 return node && node->body.size;
6970pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6971 node->base.location = (pm_location_t) { .start = start, .end = end };
6979pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6980 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6981 node->base.location.start = statement->location.start;
6984 if (statement->location.end > node->base.location.end) {
6985 node->base.location.end = statement->location.end;
6993pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6994 pm_statements_node_body_update(node, statement);
6996 if (node->body.size > 0) {
6997 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6999 switch (PM_NODE_TYPE(previous)) {
7004 case PM_RETURN_NODE:
7005 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
7012 pm_node_list_append(&node->body, statement);
7013 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7020pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
7021 pm_statements_node_body_update(node, statement);
7022 pm_node_list_prepend(&node->body, statement);
7023 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
7029static inline pm_string_node_t *
7030pm_string_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *string) {
7031 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
7032 pm_node_flags_t flags = 0;
7034 switch (parser->frozen_string_literal) {
7035 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7036 flags = PM_STRING_FLAGS_MUTABLE;
7038 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7039 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7043 *node = (pm_string_node_t) {
7045 .type = PM_STRING_NODE,
7047 .node_id = PM_NODE_IDENTIFY(parser),
7049 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start),
7050 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end)
7053 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7054 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7055 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7056 .unescaped = *string
7065static pm_string_node_t *
7066pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7067 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7074static pm_string_node_t *
7075pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7076 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
7077 parser->current_string = PM_STRING_EMPTY;
7084static pm_super_node_t *
7085pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
7086 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
7087 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
7089 const uint8_t *end = pm_arguments_end(arguments);
7091 assert(false && "unreachable");
7094 *node = (pm_super_node_t) {
7096 .type = PM_SUPER_NODE,
7097 .node_id = PM_NODE_IDENTIFY(parser),
7099 .start = keyword->start,
7103 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7104 .lparen_loc = arguments->opening_loc,
7105 .arguments = arguments->arguments,
7106 .rparen_loc = arguments->closing_loc,
7107 .block = arguments->block
7118pm_ascii_only_p(const pm_string_t *contents) {
7119 const size_t length = pm_string_length(contents);
7120 const uint8_t *source = pm_string_source(contents);
7122 for (size_t index = 0; index < length; index++) {
7123 if (source[index] & 0x80) return false;
7133parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7134 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7135 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
7138 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7151parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
7152 const pm_encoding_t *encoding = parser->encoding;
7154 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
7155 size_t width = encoding->char_width(cursor, end - cursor);
7158 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
7175static inline pm_node_flags_t
7176parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
7177 if (parser->explicit_encoding != NULL) {
7178 // A Symbol may optionally have its encoding explicitly set. This will
7179 // happen if an escape sequence results in a non-ASCII code point.
7180 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7181 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
7182 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
7183 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7184 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
7185 } else if (validate) {
7186 parse_symbol_encoding_validate_other(parser, location, contents);
7188 } else if (pm_ascii_only_p(contents)) {
7189 // Ruby stipulates that all source files must use an ASCII-compatible
7190 // encoding. Thus, all symbols appearing in source are eligible for
7191 // "downgrading" to US-ASCII.
7192 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
7193 } else if (validate) {
7194 parse_symbol_encoding_validate_other(parser, location, contents);
7200static pm_node_flags_t
7201parse_and_validate_regular_expression_encoding_modifier(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags, char modifier, const pm_encoding_t *modifier_encoding) {
7202 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
7203 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
7204 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
7205 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
7207 // There's special validation logic used if a string does not contain any character escape sequences.
7208 if (parser->explicit_encoding == NULL) {
7209 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
7210 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
7211 // the US-ASCII encoding.
7213 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
7216 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7218 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7220 } else if (parser->encoding != modifier_encoding) {
7221 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
7223 if (modifier == 'n' && !ascii_only) {
7224 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) pm_string_length(source), (const char *) pm_string_source(source));
7231 // TODO (nirvdrum 21-Feb-2024): To validate regexp sources with character escape sequences we need to know whether hex or Unicode escape sequences were used and Prism doesn't currently provide that data. We handle a subset of unambiguous cases in the meanwhile.
7232 bool mixed_encoding = false;
7234 if (mixed_encoding) {
7235 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7236 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
7237 // TODO (nirvdrum 21-Feb-2024): Validate the content is valid in the modifier encoding. Do this on-demand so we don't pay the cost of computation unnecessarily.
7238 bool valid_string_in_modifier_encoding = true;
7240 if (!valid_string_in_modifier_encoding) {
7241 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7243 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7244 // TODO (nirvdrum 21-Feb-2024): There's currently no way to tell if the source used hex or Unicode character escapes from `explicit_encoding` alone. If the source encoding was already UTF-8, both character escape types would set `explicit_encoding` to UTF-8, but need to be processed differently. Skip for now.
7245 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
7246 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, (int) pm_string_length(source), (const char *) pm_string_source(source));
7250 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
7260static pm_node_flags_t
7261parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
7262 // TODO (nirvdrum 22-Feb-2024): CRuby reports a special Regexp-specific error for invalid Unicode ranges. We either need to scan again or modify the "invalid Unicode escape sequence" message we already report.
7263 bool valid_unicode_range = true;
7264 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
7265 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INVALID_UNICODE_RANGE, (int) pm_string_length(source), (const char *) pm_string_source(source));
7269 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
7270 // to multi-byte characters are allowed.
7271 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
7272 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
7273 // following error message appearing twice. We do the same for compatibility.
7274 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
7285 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
7286 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
7289 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
7290 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
7293 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
7294 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
7297 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
7298 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
7301 // At this point no encoding modifiers will be present on the regular expression as they would have already
7302 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
7303 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
7305 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
7308 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
7309 // or by specifying a modifier.
7311 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
7312 if (parser->explicit_encoding != NULL) {
7313 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
7314 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
7315 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
7316 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
7327static pm_symbol_node_t *
7328pm_symbol_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing, const pm_string_t *unescaped, pm_node_flags_t flags) {
7329 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7331 *node = (pm_symbol_node_t) {
7333 .type = PM_SYMBOL_NODE,
7334 .flags = PM_NODE_FLAG_STATIC_LITERAL | flags,
7335 .node_id = PM_NODE_IDENTIFY(parser),
7337 .start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start),
7338 .end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end)
7341 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7342 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
7343 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7344 .unescaped = *unescaped
7353static inline pm_symbol_node_t *
7354pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7355 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
7361static pm_symbol_node_t *
7362pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
7363 pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, value, &parser->current_string, false));
7364 parser->current_string = PM_STRING_EMPTY;
7371static pm_symbol_node_t *
7372pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
7373 pm_symbol_node_t *node;
7375 switch (token->type) {
7376 case PM_TOKEN_LABEL: {
7377 pm_token_t opening = not_provided(parser);
7378 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
7380 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
7381 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7383 assert((label.end - label.start) >= 0);
7384 pm_string_shared_init(&node->unescaped, label.start, label.end);
7385 pm_node_flag_set((pm_node_t *) node, parse_symbol_encoding(parser, &label, &node->unescaped, false));
7389 case PM_TOKEN_MISSING: {
7390 pm_token_t opening = not_provided(parser);
7391 pm_token_t closing = not_provided(parser);
7393 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
7394 node = pm_symbol_node_create(parser, &opening, &label, &closing);
7398 assert(false && "unreachable");
7409static pm_symbol_node_t *
7410pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
7411 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7413 *node = (pm_symbol_node_t) {
7415 .type = PM_SYMBOL_NODE,
7416 .flags = PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
7417 .node_id = PM_NODE_IDENTIFY(parser),
7418 .location = PM_LOCATION_NULL_VALUE(parser)
7420 .value_loc = PM_LOCATION_NULL_VALUE(parser),
7424 pm_string_constant_init(&node->unescaped, content, strlen(content));
7432pm_symbol_node_label_p(pm_node_t *node) {
7433 const uint8_t *end = NULL;
7435 switch (PM_NODE_TYPE(node)) {
7436 case PM_SYMBOL_NODE:
7437 end = ((pm_symbol_node_t *) node)->closing_loc.end;
7439 case PM_INTERPOLATED_SYMBOL_NODE:
7440 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
7446 return (end != NULL) && (end[-1] == ':');
7452static pm_symbol_node_t *
7453pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
7454 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
7456 *new_node = (pm_symbol_node_t) {
7458 .type = PM_SYMBOL_NODE,
7459 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7460 .node_id = PM_NODE_IDENTIFY(parser),
7462 .start = opening->start,
7466 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
7467 .value_loc = node->content_loc,
7468 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7469 .unescaped = node->unescaped
7472 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
7473 pm_node_flag_set((pm_node_t *) new_node, parse_symbol_encoding(parser, &content, &node->unescaped, true));
7475 // We are explicitly _not_ using pm_node_destroy here because we don't want
7476 // to trash the unescaped string. We could instead copy the string if we
7477 // know that it is owned, but we're taking the fast path for now.
7486static pm_string_node_t *
7487pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
7488 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
7489 pm_node_flags_t flags = 0;
7491 switch (parser->frozen_string_literal) {
7492 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
7493 flags = PM_STRING_FLAGS_MUTABLE;
7495 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
7496 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
7500 *new_node = (pm_string_node_t) {
7502 .type = PM_STRING_NODE,
7504 .node_id = PM_NODE_IDENTIFY(parser),
7505 .location = node->base.location
7507 .opening_loc = node->opening_loc,
7508 .content_loc = node->value_loc,
7509 .closing_loc = node->closing_loc,
7510 .unescaped = node->unescaped
7513 // We are explicitly _not_ using pm_node_destroy here because we don't want
7514 // to trash the unescaped string. We could instead copy the string if we
7515 // know that it is owned, but we're taking the fast path for now.
7524static pm_true_node_t *
7525pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
7526 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
7527 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7529 *node = (pm_true_node_t) {{
7530 .type = PM_TRUE_NODE,
7531 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7532 .node_id = PM_NODE_IDENTIFY(parser),
7533 .location = PM_LOCATION_TOKEN_VALUE(token)
7542static pm_true_node_t *
7543pm_true_node_synthesized_create(pm_parser_t *parser) {
7544 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
7546 *node = (pm_true_node_t) {{
7547 .type = PM_TRUE_NODE,
7548 .flags = PM_NODE_FLAG_STATIC_LITERAL,
7549 .node_id = PM_NODE_IDENTIFY(parser),
7550 .location = { .start = parser->start, .end = parser->end }
7559static pm_undef_node_t *
7560pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
7561 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
7562 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
7564 *node = (pm_undef_node_t) {
7566 .type = PM_UNDEF_NODE,
7567 .node_id = PM_NODE_IDENTIFY(parser),
7568 .location = PM_LOCATION_TOKEN_VALUE(token),
7570 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
7581pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
7582 node->base.location.end = name->location.end;
7583 pm_node_list_append(&node->names, name);
7589static pm_unless_node_t *
7590pm_unless_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, const pm_token_t *then_keyword, pm_statements_node_t *statements) {
7591 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7592 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7595 if (statements != NULL) {
7596 end = statements->base.location.end;
7598 end = predicate->location.end;
7601 *node = (pm_unless_node_t) {
7603 .type = PM_UNLESS_NODE,
7604 .flags = PM_NODE_FLAG_NEWLINE,
7605 .node_id = PM_NODE_IDENTIFY(parser),
7607 .start = keyword->start,
7611 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7612 .predicate = predicate,
7613 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
7614 .statements = statements,
7615 .else_clause = NULL,
7616 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7625static pm_unless_node_t *
7626pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
7627 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7628 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
7630 pm_statements_node_t *statements = pm_statements_node_create(parser);
7631 pm_statements_node_body_append(parser, statements, statement, true);
7633 *node = (pm_unless_node_t) {
7635 .type = PM_UNLESS_NODE,
7636 .flags = PM_NODE_FLAG_NEWLINE,
7637 .node_id = PM_NODE_IDENTIFY(parser),
7639 .start = statement->location.start,
7640 .end = predicate->location.end
7643 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
7644 .predicate = predicate,
7645 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7646 .statements = statements,
7647 .else_clause = NULL,
7648 .end_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE
7655pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
7656 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
7657 node->base.location.end = end_keyword->end;
7666pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7667 assert(parser->current_block_exits != NULL);
7669 // All of the block exits that we want to remove should be within the
7670 // statements, and since we are modifying the statements, we shouldn't have
7671 // to check the end location.
7672 const uint8_t *start = statements->base.location.start;
7674 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7675 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7676 if (block_exit->location.start < start) break;
7678 // Implicitly remove from the list by lowering the size.
7679 parser->current_block_exits->size--;
7686static pm_until_node_t *
7687pm_until_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
7688 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7689 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7691 *node = (pm_until_node_t) {
7693 .type = PM_UNTIL_NODE,
7695 .node_id = PM_NODE_IDENTIFY(parser),
7697 .start = keyword->start,
7698 .end = closing->end,
7701 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7702 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7703 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7704 .predicate = predicate,
7705 .statements = statements
7714static pm_until_node_t *
7715pm_until_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
7716 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
7717 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7718 pm_loop_modifier_block_exits(parser, statements);
7720 *node = (pm_until_node_t) {
7722 .type = PM_UNTIL_NODE,
7724 .node_id = PM_NODE_IDENTIFY(parser),
7726 .start = statements->base.location.start,
7727 .end = predicate->location.end,
7730 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7731 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7732 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7733 .predicate = predicate,
7734 .statements = statements
7743static pm_when_node_t *
7744pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7745 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
7747 *node = (pm_when_node_t) {
7749 .type = PM_WHEN_NODE,
7750 .node_id = PM_NODE_IDENTIFY(parser),
7752 .start = keyword->start,
7756 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7758 .then_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7769pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
7770 node->base.location.end = condition->location.end;
7771 pm_node_list_append(&node->conditions, condition);
7778pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
7779 node->base.location.end = then_keyword->end;
7780 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
7787pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7788 if (statements->base.location.end > node->base.location.end) {
7789 node->base.location.end = statements->base.location.end;
7792 node->statements = statements;
7798static pm_while_node_t *
7799pm_while_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_token_t *do_keyword, const pm_token_t *closing, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
7800 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7801 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7803 *node = (pm_while_node_t) {
7805 .type = PM_WHILE_NODE,
7807 .node_id = PM_NODE_IDENTIFY(parser),
7809 .start = keyword->start,
7813 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7814 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
7815 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
7816 .predicate = predicate,
7817 .statements = statements
7826static pm_while_node_t *
7827pm_while_node_modifier_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *predicate, pm_statements_node_t *statements, pm_node_flags_t flags) {
7828 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7829 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7830 pm_loop_modifier_block_exits(parser, statements);
7832 *node = (pm_while_node_t) {
7834 .type = PM_WHILE_NODE,
7836 .node_id = PM_NODE_IDENTIFY(parser),
7838 .start = statements->base.location.start,
7839 .end = predicate->location.end
7842 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7843 .do_keyword_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7844 .closing_loc = PM_OPTIONAL_LOCATION_NOT_PROVIDED_VALUE,
7845 .predicate = predicate,
7846 .statements = statements
7855static pm_while_node_t *
7856pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7857 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7859 *node = (pm_while_node_t) {
7861 .type = PM_WHILE_NODE,
7862 .node_id = PM_NODE_IDENTIFY(parser),
7863 .location = PM_LOCATION_NULL_VALUE(parser)
7865 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7866 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7867 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7868 .predicate = predicate,
7869 .statements = statements
7879static pm_x_string_node_t *
7880pm_xstring_node_create_unescaped(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing, const pm_string_t *unescaped) {
7881 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7883 *node = (pm_x_string_node_t) {
7885 .type = PM_X_STRING_NODE,
7886 .flags = PM_STRING_FLAGS_FROZEN,
7887 .node_id = PM_NODE_IDENTIFY(parser),
7889 .start = opening->start,
7893 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7894 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7895 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7896 .unescaped = *unescaped
7905static inline pm_x_string_node_t *
7906pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7907 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7913static pm_yield_node_t *
7914pm_yield_node_create(pm_parser_t *parser, const pm_token_t *keyword, const pm_location_t *lparen_loc, pm_arguments_node_t *arguments, const pm_location_t *rparen_loc) {
7915 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7918 if (rparen_loc->start != NULL) {
7919 end = rparen_loc->end;
7920 } else if (arguments != NULL) {
7921 end = arguments->base.location.end;
7922 } else if (lparen_loc->start != NULL) {
7923 end = lparen_loc->end;
7928 *node = (pm_yield_node_t) {
7930 .type = PM_YIELD_NODE,
7931 .node_id = PM_NODE_IDENTIFY(parser),
7933 .start = keyword->start,
7937 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7938 .lparen_loc = *lparen_loc,
7939 .arguments = arguments,
7940 .rparen_loc = *rparen_loc
7947#undef PM_NODE_IDENTIFY
7954pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7955 pm_scope_t *scope = parser->current_scope;
7958 while (scope != NULL) {
7959 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7960 if (scope->closed) break;
7962 scope = scope->previous;
7975pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7976 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7983pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7984 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7990static pm_constant_id_t
7991pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7992 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7993 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
8000static inline pm_constant_id_t
8001pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
8002 return pm_parser_local_add_location(parser, token->start, token->end, reads);
8008static pm_constant_id_t
8009pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
8010 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
8011 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8018static pm_constant_id_t
8019pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
8020 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
8021 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
8033pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
8034 // We want to check whether the parameter name is a numbered parameter or
8036 pm_refute_numbered_parameter(parser, name->start, name->end);
8038 // Otherwise we'll fetch the constant id for the parameter name and check
8039 // whether it's already in the current scope.
8040 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
8042 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
8043 // Add an error if the parameter doesn't start with _ and has been seen before
8044 if ((name->start < name->end) && (*name->start != '_')) {
8045 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
8056pm_parser_scope_pop(pm_parser_t *parser) {
8057 pm_scope_t *scope = parser->current_scope;
8058 parser->current_scope = scope->previous;
8059 pm_locals_free(&scope->locals);
8060 pm_node_list_free(&scope->implicit_parameters);
8064/******************************************************************************/
8066/******************************************************************************/
8072pm_state_stack_push(pm_state_stack_t *stack, bool value) {
8073 *stack = (*stack << 1) | (value & 1);
8080pm_state_stack_pop(pm_state_stack_t *stack) {
8088pm_state_stack_p(const pm_state_stack_t *stack) {
8093pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
8094 // Use the negation of the value to prevent stack overflow.
8095 pm_state_stack_push(&parser->accepts_block_stack, !value);
8099pm_accepts_block_stack_pop(pm_parser_t *parser) {
8100 pm_state_stack_pop(&parser->accepts_block_stack);
8104pm_accepts_block_stack_p(pm_parser_t *parser) {
8105 return !pm_state_stack_p(&parser->accepts_block_stack);
8109pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
8110 pm_state_stack_push(&parser->do_loop_stack, value);
8114pm_do_loop_stack_pop(pm_parser_t *parser) {
8115 pm_state_stack_pop(&parser->do_loop_stack);
8119pm_do_loop_stack_p(pm_parser_t *parser) {
8120 return pm_state_stack_p(&parser->do_loop_stack);
8123/******************************************************************************/
8124/* Lexer check helpers */
8125/******************************************************************************/
8131static inline uint8_t
8132peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
8133 if (cursor < parser->end) {
8145static inline uint8_t
8146peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
8147 return peek_at(parser, parser->current.end + offset);
8154static inline uint8_t
8155peek(const pm_parser_t *parser) {
8156 return peek_at(parser, parser->current.end);
8164match(pm_parser_t *parser, uint8_t value) {
8165 if (peek(parser) == value) {
8166 parser->current.end++;
8177match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
8178 if (peek_at(parser, cursor) == '\n') {
8181 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
8193match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
8194 return match_eol_at(parser, parser->current.end + offset);
8203match_eol(pm_parser_t *parser) {
8204 return match_eol_at(parser, parser->current.end);
8210static inline const uint8_t *
8211next_newline(const uint8_t *cursor, ptrdiff_t length) {
8212 assert(length >= 0);
8214 // Note that it's okay for us to use memchr here to look for \n because none
8215 // of the encodings that we support have \n as a component of a multi-byte
8217 return memchr(cursor, '\n', (size_t) length);
8224ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
8225 return !lex_state_p(parser, PM_LEX_STATE_CLASS | PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME | PM_LEX_STATE_ENDFN) && space_seen && !pm_char_is_whitespace(peek(parser));
8233parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
8234 const pm_encoding_t *encoding = pm_encoding_find(start, end);
8236 if (encoding != NULL) {
8237 if (parser->encoding != encoding) {
8238 parser->encoding = encoding;
8239 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
8242 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
8254parser_lex_magic_comment_encoding(pm_parser_t *parser) {
8255 const uint8_t *cursor = parser->current.start + 1;
8256 const uint8_t *end = parser->current.end;
8258 bool separator = false;
8260 if (end - cursor <= 6) return;
8261 switch (cursor[6]) {
8262 case 'C': case 'c': cursor += 6; continue;
8263 case 'O': case 'o': cursor += 5; continue;
8264 case 'D': case 'd': cursor += 4; continue;
8265 case 'I': case 'i': cursor += 3; continue;
8266 case 'N': case 'n': cursor += 2; continue;
8267 case 'G': case 'g': cursor += 1; continue;
8274 if (pm_char_is_whitespace(*cursor)) break;
8277 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
8283 if (++cursor >= end) return;
8284 } while (pm_char_is_whitespace(*cursor));
8286 if (separator) break;
8287 if (*cursor != '=' && *cursor != ':') return;
8293 const uint8_t *value_start = cursor;
8294 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
8296 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
8297 // If we were unable to parse the encoding value, then we've got an
8298 // issue because we didn't understand the encoding that the user was
8299 // trying to use. In this case we'll keep using the default encoding but
8300 // add an error to the parser to indicate an unsuccessful parse.
8301 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
8306 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
8307 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
8308 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
8309} pm_magic_comment_boolean_value_t;
8315static pm_magic_comment_boolean_value_t
8316parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
8317 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
8318 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
8319 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
8320 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
8322 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
8327pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
8328 return b == '\'' || b == '"' || b == ':' || b == ';';
8336static inline const uint8_t *
8337parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
8338 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
8339 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
8358parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
8361 const uint8_t *start = parser->
current.start + 1;
8362 const uint8_t *end = parser->
current.end;
8363 if (end - start <= 7)
return false;
8365 const uint8_t *cursor;
8366 bool indicator =
false;
8368 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8371 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
8382 while (cursor < end) {
8383 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
8385 const uint8_t *key_start = cursor;
8386 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
8388 const uint8_t *key_end = cursor;
8389 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8390 if (cursor == end)
break;
8392 if (*cursor ==
':') {
8395 if (!indicator)
return false;
8399 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8400 if (cursor == end)
break;
8402 const uint8_t *value_start;
8403 const uint8_t *value_end;
8405 if (*cursor ==
'"') {
8406 value_start = ++cursor;
8407 for (; cursor < end && *cursor !=
'"'; cursor++) {
8408 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
8411 if (*cursor ==
'"') cursor++;
8413 value_start = cursor;
8414 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
8419 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
8421 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
8422 if (cursor != end)
return false;
8428 const size_t key_length = (size_t) (key_end - key_start);
8432 pm_string_shared_init(&key, key_start, key_end);
8434 uint8_t *buffer =
xmalloc(key_length);
8435 if (buffer == NULL)
break;
8437 memcpy(buffer, key_start, key_length);
8438 buffer[dash - key_start] =
'_';
8440 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
8441 buffer[dash - key_start] =
'_';
8444 pm_string_owned_init(&key, buffer, key_length);
8449 const uint8_t *key_source = pm_string_source(&key);
8450 uint32_t value_length = (uint32_t) (value_end - value_start);
8456 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
8457 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
8459 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
8463 if (key_length == 11) {
8464 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
8465 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8466 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8467 PM_PARSER_WARN_TOKEN_FORMAT(
8470 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8472 (
const char *) key_source,
8474 (
const char *) value_start
8477 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8480 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8485 }
else if (key_length == 21) {
8486 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
8489 if (semantic_token_seen) {
8490 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
8492 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
8493 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
8494 PM_PARSER_WARN_TOKEN_FORMAT(
8497 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8499 (
const char *) key_source,
8501 (
const char *) value_start
8504 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
8507 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
8513 }
else if (key_length == 24) {
8514 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
8515 const uint8_t *cursor = parser->
current.start;
8516 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
8518 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
8519 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
8520 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
8521 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
8522 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
8523 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
8524 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
8525 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
8526 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
8527 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
8529 PM_PARSER_WARN_TOKEN_FORMAT(
8532 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
8534 (
const char *) key_source,
8536 (
const char *) value_start
8544 pm_string_free(&key);
8653 while (context_node != NULL) {
8654 if (context_terminator(context_node->
context, token))
return context_node->
context;
8655 context_node = context_node->
prev;
8664 if (context_node == NULL)
return false;
8689 while (context_node != NULL) {
8690 if (context_node->
context == context)
return true;
8691 context_node = context_node->
prev;
8701 while (context_node != NULL) {
8702 switch (context_node->
context) {
8723 context_node = context_node->
prev;
8738 assert(
false &&
"unreachable");
8795 assert(
false &&
"unreachable");
8804pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8805 if (invalid != NULL) {
8806 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8807 pm_parser_err(parser, invalid, invalid + 1, diag_id);
8812pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8813 const uint8_t *invalid = NULL;
8814 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
8815 pm_strspn_number_validate(parser,
string, length, invalid);
8820pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8821 const uint8_t *invalid = NULL;
8822 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
8823 pm_strspn_number_validate(parser,
string, length, invalid);
8828pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8829 const uint8_t *invalid = NULL;
8830 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
8831 pm_strspn_number_validate(parser,
string, length, invalid);
8836pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8837 const uint8_t *invalid = NULL;
8838 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
8839 pm_strspn_number_validate(parser,
string, length, invalid);
8844lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8849 if (peek(parser) ==
'.') {
8850 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8852 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8863 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8864 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8867 if (pm_char_is_decimal_digit(peek(parser))) {
8869 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8871 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8873 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8875 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8888lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8892 if (peek_offset(parser, -1) ==
'0') {
8893 switch (*parser->
current.end) {
8898 if (pm_char_is_decimal_digit(peek(parser))) {
8899 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8902 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8911 if (pm_char_is_binary_digit(peek(parser))) {
8912 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8915 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8925 if (pm_char_is_octal_digit(peek(parser))) {
8926 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8929 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8945 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8953 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8954 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8957 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8965 type = lex_optional_float_suffix(parser, seen_e);
8972 type = lex_optional_float_suffix(parser, seen_e);
8979 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8982 type = lex_optional_float_suffix(parser, seen_e);
8988 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8989 const uint8_t *fraction_start = parser->
current.end;
8990 const uint8_t *fraction_end = parser->
current.end + 2;
8991 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8992 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
9004 bool seen_e =
false;
9005 type = lex_numeric_prefix(parser, &seen_e);
9007 const uint8_t *end = parser->
current.end;
9011 if (match(parser,
'r')) {
9014 if (match(parser,
'i')) {
9017 }
else if (match(parser,
'i')) {
9021 if (!seen_e && match(parser,
'r')) {
9024 if (match(parser,
'i')) {
9027 }
else if (match(parser,
'i')) {
9032 const uint8_t b = peek(parser);
9033 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
9046 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9052 bool allow_multiple =
true;
9054 switch (*parser->
current.end) {
9085 if (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0) {
9088 }
while (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0);
9092 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
9112 allow_multiple =
false;
9117 if ((width = char_is_identifier(parser, parser->
current.end)) > 0) {
9120 }
while (allow_multiple && parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0);
9121 }
else if (pm_char_is_whitespace(peek(parser))) {
9124 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
9130 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
9152 if (memcmp(current_start, value, vlen) == 0) {
9155 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
9156 lex_state_set(parser, PM_LEX_STATE_ENDFN);
9158 lex_state_set(parser, state);
9159 if (state == PM_LEX_STATE_BEG) {
9163 if ((modifier_type !=
PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
9164 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
9165 return modifier_type;
9176lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
9179 const uint8_t *end = parser->
end;
9180 const uint8_t *current_start = parser->
current.start;
9181 const uint8_t *current_end = parser->
current.end;
9184 if (encoding_changed) {
9185 while (current_end < end && (width = char_is_identifier(parser, current_end)) > 0) {
9186 current_end += width;
9189 while (current_end < end && (width = char_is_identifier_utf8(current_end, end)) > 0) {
9190 current_end += width;
9193 parser->
current.end = current_end;
9197 width = (size_t) (current_end - current_start);
9199 if (current_end < end) {
9200 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
9206 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9207 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
9211 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9212 (void) match(parser,
':');
9216 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9225 if (lex_state_p(parser, PM_LEX_STATE_FNAME) && peek_offset(parser, 1) !=
'~' && peek_offset(parser, 1) !=
'>' && (peek_offset(parser, 1) !=
'=' || peek_offset(parser, 2) ==
'>') && match(parser,
'=')) {
9232 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
9233 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
9237 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
9238 (void) match(parser,
':');
9243 if (parser->
lex_state != PM_LEX_STATE_DOT) {
9248 if (pm_do_loop_stack_p(parser)) {
9309 if (encoding_changed) {
9339lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
9342 if (pound + 1 >= parser->
end) {
9343 parser->
current.end = pound + 1;
9353 if (pound + 2 >= parser->
end) {
9354 parser->
current.end = pound + 1;
9360 const uint8_t *variable = pound + 2;
9361 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
9363 if (char_is_identifier_start(parser, variable)) {
9367 if (pound > parser->
current.start) {
9374 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9375 parser->
current.end = pound + 1;
9382 parser->
current.end = pound + 1;
9388 if (pound + 2 >= parser->
end) {
9389 parser->
current.end = pound + 1;
9396 const uint8_t *check = pound + 2;
9398 if (pound[2] ==
'-') {
9399 if (pound + 3 >= parser->
end) {
9400 parser->
current.end = pound + 2;
9412 char_is_identifier_start(parser, check) ||
9413 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
9418 if (pound > parser->
current.start) {
9425 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
9426 parser->
current.end = pound + 1;
9432 parser->
current.end = pound + 1;
9438 if (pound > parser->
current.start) {
9447 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
9448 parser->
current.end = pound + 2;
9450 pm_do_loop_stack_push(parser,
false);
9456 parser->
current.end = pound + 1;
9461static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
9462static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
9463static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
9464static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
9465static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
9470static const bool ascii_printable_chars[] = {
9471 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
9472 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
9473 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9474 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9475 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9476 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
9477 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
9482char_is_ascii_printable(
const uint8_t b) {
9483 return (b < 0x80) && ascii_printable_chars[b];
9490static inline uint8_t
9491escape_hexadecimal_digit(
const uint8_t value) {
9492 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9500static inline uint32_t
9501escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length) {
9503 for (
size_t index = 0; index < length; index++) {
9504 if (index != 0) value <<= 4;
9505 value |= escape_hexadecimal_digit(
string[index]);
9510 if (value >= 0xD800 && value <= 0xDFFF) {
9511 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
9521static inline uint8_t
9522escape_byte(uint8_t value,
const uint8_t flags) {
9523 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9524 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9532escape_write_unicode(
pm_parser_t *parser,
pm_buffer_t *buffer,
const uint8_t flags,
const uint8_t *start,
const uint8_t *end, uint32_t value) {
9536 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9544 if (value <= 0x7F) {
9545 pm_buffer_append_byte(buffer, (uint8_t) value);
9546 }
else if (value <= 0x7FF) {
9547 pm_buffer_append_byte(buffer, (uint8_t) (0xC0 | (value >> 6)));
9548 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
9549 }
else if (value <= 0xFFFF) {
9550 pm_buffer_append_byte(buffer, (uint8_t) (0xE0 | (value >> 12)));
9551 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 6) & 0x3F)));
9552 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
9553 }
else if (value <= 0x10FFFF) {
9554 pm_buffer_append_byte(buffer, (uint8_t) (0xF0 | (value >> 18)));
9555 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 12) & 0x3F)));
9556 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | ((value >> 6) & 0x3F)));
9557 pm_buffer_append_byte(buffer, (uint8_t) (0x80 | (value & 0x3F)));
9559 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
9560 pm_buffer_append_byte(buffer, 0xEF);
9561 pm_buffer_append_byte(buffer, 0xBF);
9562 pm_buffer_append_byte(buffer, 0xBD);
9574 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
9580 pm_buffer_append_byte(buffer,
byte);
9592 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9597 width = (width == 0) ? 1 : width;
9599 for (
size_t index = 0; index < width; index++) {
9600 escape_write_byte_encoded(parser, buffer, *parser->
current.end);
9622 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9623 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9626 escape_write_byte_encoded(parser, buffer,
byte);
9635escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9636#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9638 PM_PARSER_WARN_TOKEN_FORMAT(
9641 PM_WARN_INVALID_CHARACTER,
9655 switch (peek(parser)) {
9658 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9663 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9668 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9673 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9678 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9683 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9688 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9693 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9698 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9703 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9708 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9711 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9712 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
9715 if (pm_char_is_octal_digit(peek(parser))) {
9716 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9719 if (pm_char_is_octal_digit(peek(parser))) {
9720 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.end -
'0'));
9725 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9729 const uint8_t *start = parser->
current.end - 1;
9732 uint8_t
byte = peek(parser);
9734 if (pm_char_is_hexadecimal_digit(
byte)) {
9735 uint8_t value = escape_hexadecimal_digit(
byte);
9738 byte = peek(parser);
9739 if (pm_char_is_hexadecimal_digit(
byte)) {
9740 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9744 value = escape_byte(value, flags);
9745 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9746 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9747 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9749 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9753 escape_write_byte_encoded(parser, buffer, value);
9755 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9761 const uint8_t *start = parser->
current.end - 1;
9765 const uint8_t *start = parser->
current.end - 2;
9766 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9767 }
else if (peek(parser) ==
'{') {
9768 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
9773 if ((whitespace = pm_strspn_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
9774 parser->
current.end += whitespace;
9775 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9786 const uint8_t *extra_codepoints_start = NULL;
9787 int codepoints_count = 0;
9790 const uint8_t *unicode_start = parser->
current.end;
9791 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
9793 if (hexadecimal_length > 6) {
9795 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9796 }
else if (hexadecimal_length == 0) {
9799 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9803 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9805 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
9806 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9812 parser->
current.end += hexadecimal_length;
9814 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9815 extra_codepoints_start = unicode_start;
9818 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length);
9819 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
9826 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9827 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9831 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
9832 }
else if (peek(parser) ==
'}') {
9835 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9839 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9841 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9845 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9846 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
9849 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
9852 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9853 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9855 const uint8_t *start = parser->
current.end - 2;
9856 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9858 }
else if (length == 4) {
9859 uint32_t value = escape_unicode(parser, parser->
current.end, 4);
9861 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9862 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
9865 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
9868 parser->
current.end += length;
9870 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9874 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
9876 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9885 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9886 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9890 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9894 uint8_t peeked = peek(parser);
9898 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9904 if (match(parser,
'u') || match(parser,
'U')) {
9905 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9909 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9913 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9914 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9918 escape_read_warn(parser, flags, 0,
"\\t");
9919 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9922 if (!char_is_ascii_printable(peeked)) {
9923 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9928 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9935 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9936 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9939 if (peek(parser) !=
'-') {
9941 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9947 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9951 uint8_t peeked = peek(parser);
9955 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9961 if (match(parser,
'u') || match(parser,
'U')) {
9962 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9966 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9970 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9971 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9975 escape_read_warn(parser, flags, 0,
"\\t");
9976 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9979 if (!char_is_ascii_printable(peeked)) {
9981 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9986 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9993 if (flags & PM_ESCAPE_FLAG_META) {
9994 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9997 if (peek(parser) !=
'-') {
9999 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10005 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
10009 uint8_t peeked = peek(parser);
10014 if (match(parser,
'u') || match(parser,
'U')) {
10015 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
10019 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
10023 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
10024 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10028 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
10029 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10032 if (!char_is_ascii_printable(peeked)) {
10034 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
10039 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
10044 if (peek_offset(parser, 1) ==
'\n') {
10046 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
10053 escape_write_escape_encoded(parser, buffer);
10055 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
10089 if (lex_state_end_p(parser)) {
10090 lex_state_set(parser, PM_LEX_STATE_BEG);
10095 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
10100 if (pm_char_is_whitespace(*parser->
current.end)) {
10101 lex_state_set(parser, PM_LEX_STATE_BEG);
10105 lex_state_set(parser, PM_LEX_STATE_BEG);
10107 if (match(parser,
'\\')) {
10108 lex_state_set(parser, PM_LEX_STATE_END);
10111 pm_buffer_init_capacity(&buffer, 3);
10113 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
10125 (parser->
current.end + encoding_width >= parser->
end) ||
10126 !char_is_identifier(parser, parser->
current.end + encoding_width)
10129 lex_state_set(parser, PM_LEX_STATE_END);
10130 parser->
current.end += encoding_width;
10148 if (parser->
current.end < parser->
end && (width = char_is_identifier_start(parser, parser->
current.end)) > 0) {
10149 parser->
current.end += width;
10151 while (parser->
current.end < parser->
end && (width = char_is_identifier(parser, parser->
current.end)) > 0) {
10152 parser->
current.end += width;
10154 }
else if (parser->
current.end < parser->
end && pm_char_is_decimal_digit(*parser->
current.end)) {
10161 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
10164 pm_parser_err_token(parser, &parser->
current, diag_id);
10170 lex_mode_pop(parser);
10192 if (comment == NULL)
return NULL;
10210 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10212 if (newline == NULL) {
10215 pm_newline_list_append(&parser->
newline_list, newline);
10216 parser->
current.end = newline + 1;
10220 parser_lex_callback(parser);
10223 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
10228 while (parser->
current.end + 4 <= parser->
end) {
10234 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
10237 pm_char_is_whitespace(parser->
current.end[4]) ||
10238 (parser->
current.end[4] ==
'\0') ||
10239 (parser->
current.end[4] ==
'\004') ||
10240 (parser->
current.end[4] ==
'\032')
10243 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10245 if (newline == NULL) {
10248 pm_newline_list_append(&parser->
newline_list, newline);
10249 parser->
current.end = newline + 1;
10253 parser_lex_callback(parser);
10263 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10265 if (newline == NULL) {
10268 pm_newline_list_append(&parser->
newline_list, newline);
10269 parser->
current.end = newline + 1;
10273 parser_lex_callback(parser);
10276 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
10292 parser_lex_callback(parser);
10316 const uint8_t *cursor = parser->
current.end;
10318 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
10319 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
10382 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
10393static inline size_t
10399 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
10404 return (width == 0 ? 1 : width);
10412 size_t width = parser_char_width(parser);
10413 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
10414 parser->
current.end += width;
10419 size_t width = parser_char_width(parser);
10420 pm_buffer_append_bytes(&token_buffer->
base.
buffer, parser->
current.end, width);
10422 parser->
current.end += width;
10426pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
10427 for (
size_t index = 0; index < length; index++) {
10428 if (value[index] & 0x80)
return false;
10442 pm_string_owned_init(&parser->
current_string, (uint8_t *) pm_buffer_value(&token_buffer->
buffer), pm_buffer_length(&token_buffer->
buffer));
10463 if (token_buffer->
cursor == NULL) {
10466 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
10467 pm_token_buffer_copy(parser, token_buffer);
10479 pm_regexp_token_buffer_copy(parser, token_buffer);
10483#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10495 const uint8_t *start;
10496 if (token_buffer->
cursor == NULL) {
10497 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10498 start = parser->
current.start;
10500 start = token_buffer->
cursor;
10503 const uint8_t *end = parser->
current.end - 1;
10504 assert(end >= start);
10505 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10507 token_buffer->
cursor = end;
10512 const uint8_t *start;
10514 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10515 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10516 start = parser->
current.start;
10521 const uint8_t *end = parser->
current.end - 1;
10522 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10523 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10528#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10534static inline size_t
10536 size_t whitespace = 0;
10539 case PM_HEREDOC_INDENT_NONE:
10544 case PM_HEREDOC_INDENT_DASH:
10546 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
10548 case PM_HEREDOC_INDENT_TILDE:
10551 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10552 if (**cursor ==
'\t') {
10553 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10572 size_t eol_length = match_eol(parser);
10579 parser_flush_heredoc_end(parser);
10585 uint8_t delimiter = *parser->
current.end;
10589 if (eol_length == 2) {
10590 delimiter = *(parser->
current.end + 1);
10593 parser->
current.end += eol_length;
10597 return *parser->
current.end++;
10604#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10623 bool lexed_comment =
false;
10631 case PM_LEX_DEFAULT:
10632 case PM_LEX_EMBEXPR:
10633 case PM_LEX_EMBVAR:
10649 bool space_seen =
false;
10653 bool chomping =
true;
10654 while (parser->
current.end < parser->
end && chomping) {
10655 switch (*parser->
current.end) {
10664 if (match_eol_offset(parser, 1)) {
10667 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10673 size_t eol_length = match_eol_offset(parser, 1);
10679 parser->
current.end += eol_length + 1;
10683 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
10716 switch (*parser->
current.end++) {
10724 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10725 parser->
current.end = ending == NULL ? parser->
end : ending;
10730 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10733 if (ending) parser->
current.end++;
10735 parser_lex_callback(parser);
10747 parser_lex_magic_comment_encoding(parser);
10751 lexed_comment =
true;
10757 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
10769 if (!lexed_comment) {
10770 parser->
current.end += eol_length - 1;
10779 parser_flush_heredoc_end(parser);
10784 switch (lex_state_ignored_p(parser)) {
10785 case PM_IGNORED_NEWLINE_NONE:
10787 case PM_IGNORED_NEWLINE_PATTERN:
10789 if (!lexed_comment) parser_lex_ignored_newline(parser);
10790 lex_state_set(parser, PM_LEX_STATE_BEG);
10796 case PM_IGNORED_NEWLINE_ALL:
10797 if (!lexed_comment) parser_lex_ignored_newline(parser);
10798 lexed_comment =
false;
10799 goto lex_next_token;
10807 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
10809 if (next_content < parser->end) {
10815 if (next_content[0] ==
'#') {
10817 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
10819 while (following && (following + 1 < parser->
end)) {
10821 following += pm_strspn_inline_whitespace(following, parser->
end - following);
10825 if (peek_at(parser, following) !=
'#')
break;
10829 following = next_newline(following, parser->
end - following);
10835 lex_state_ignored_p(parser) ||
10837 (peek_at(parser, following) ==
'.') ||
10838 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10841 if (!lexed_comment) parser_lex_ignored_newline(parser);
10842 lexed_comment =
false;
10843 goto lex_next_token;
10849 if (next_content[0] ==
'.') {
10853 if (peek_at(parser, next_content + 1) ==
'.') {
10854 if (!lexed_comment) parser_lex_ignored_newline(parser);
10855 lex_state_set(parser, PM_LEX_STATE_BEG);
10861 if (!lexed_comment) parser_lex_ignored_newline(parser);
10862 lex_state_set(parser, PM_LEX_STATE_DOT);
10863 parser->
current.start = next_content;
10864 parser->
current.end = next_content + 1;
10871 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10872 if (!lexed_comment) parser_lex_ignored_newline(parser);
10873 lex_state_set(parser, PM_LEX_STATE_DOT);
10874 parser->
current.start = next_content;
10875 parser->
current.end = next_content + 2;
10883 lex_state_set(parser, PM_LEX_STATE_BEG);
10886 if (!lexed_comment) parser_lex_callback(parser);
10896 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10903 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10908 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10909 pm_do_loop_stack_push(parser,
false);
10916 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10917 pm_do_loop_stack_pop(parser);
10922 lex_state_set(parser, PM_LEX_STATE_BEG);
10931 if (lex_state_operator_p(parser)) {
10932 if (match(parser,
']')) {
10934 lex_state_set(parser, PM_LEX_STATE_ARG);
10938 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10942 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10946 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10947 pm_do_loop_stack_push(parser,
false);
10953 lex_state_set(parser, PM_LEX_STATE_END);
10954 pm_do_loop_stack_pop(parser);
10964 lex_state_set(parser, PM_LEX_STATE_BEG);
10966 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10968 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10969 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10972 lex_state_set(parser, PM_LEX_STATE_BEG);
10973 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10976 lex_state_set(parser, PM_LEX_STATE_BEG);
10979 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10984 pm_do_loop_stack_push(parser,
false);
10992 pm_do_loop_stack_pop(parser);
10995 lex_mode_pop(parser);
11000 lex_state_set(parser, PM_LEX_STATE_END);
11005 if (match(parser,
'*')) {
11006 if (match(parser,
'=')) {
11007 lex_state_set(parser, PM_LEX_STATE_BEG);
11013 if (lex_state_spcarg_p(parser, space_seen)) {
11014 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
11016 }
else if (lex_state_beg_p(parser)) {
11018 }
else if (ambiguous_operator_p(parser, space_seen)) {
11019 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
11022 if (lex_state_operator_p(parser)) {
11023 lex_state_set(parser, PM_LEX_STATE_ARG);
11025 lex_state_set(parser, PM_LEX_STATE_BEG);
11031 if (match(parser,
'=')) {
11032 lex_state_set(parser, PM_LEX_STATE_BEG);
11038 if (lex_state_spcarg_p(parser, space_seen)) {
11039 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
11041 }
else if (lex_state_beg_p(parser)) {
11043 }
else if (ambiguous_operator_p(parser, space_seen)) {
11044 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
11047 if (lex_state_operator_p(parser)) {
11048 lex_state_set(parser, PM_LEX_STATE_ARG);
11050 lex_state_set(parser, PM_LEX_STATE_BEG);
11058 if (lex_state_operator_p(parser)) {
11059 lex_state_set(parser, PM_LEX_STATE_ARG);
11060 if (match(parser,
'@')) {
11064 lex_state_set(parser, PM_LEX_STATE_BEG);
11067 if (match(parser,
'=')) {
11071 if (match(parser,
'~')) {
11080 current_token_starts_line(parser) &&
11082 memcmp(parser->
current.end,
"begin", 5) == 0 &&
11083 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
11090 goto lex_next_token;
11093 if (lex_state_operator_p(parser)) {
11094 lex_state_set(parser, PM_LEX_STATE_ARG);
11096 lex_state_set(parser, PM_LEX_STATE_BEG);
11099 if (match(parser,
'>')) {
11103 if (match(parser,
'~')) {
11107 if (match(parser,
'=')) {
11115 if (match(parser,
'<')) {
11117 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
11118 !lex_state_end_p(parser) &&
11119 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
11121 const uint8_t *end = parser->
current.end;
11126 if (match(parser,
'-')) {
11127 indent = PM_HEREDOC_INDENT_DASH;
11129 else if (match(parser,
'~')) {
11130 indent = PM_HEREDOC_INDENT_TILDE;
11133 if (match(parser,
'`')) {
11134 quote = PM_HEREDOC_QUOTE_BACKTICK;
11136 else if (match(parser,
'"')) {
11137 quote = PM_HEREDOC_QUOTE_DOUBLE;
11139 else if (match(parser,
'\'')) {
11140 quote = PM_HEREDOC_QUOTE_SINGLE;
11143 const uint8_t *ident_start = parser->
current.end;
11148 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end)) == 0) {
11151 if (quote == PM_HEREDOC_QUOTE_NONE) {
11152 parser->
current.end += width;
11154 while ((parser->
current.end < parser->
end) && (width = char_is_identifier(parser, parser->
current.end))) {
11155 parser->
current.end += width;
11161 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
11166 size_t ident_length = (size_t) (parser->
current.end - ident_start);
11167 bool ident_error =
false;
11169 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
11170 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
11171 ident_error =
true;
11176 .mode = PM_LEX_HEREDOC,
11179 .ident_start = ident_start,
11180 .ident_length = ident_length,
11184 .next_start = parser->
current.end,
11186 .line_continuation =
false
11191 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
11193 if (body_start == NULL) {
11198 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
11199 body_start = parser->
end;
11203 pm_newline_list_append(&parser->
newline_list, body_start);
11216 if (match(parser,
'=')) {
11217 lex_state_set(parser, PM_LEX_STATE_BEG);
11221 if (ambiguous_operator_p(parser, space_seen)) {
11222 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
11225 if (lex_state_operator_p(parser)) {
11226 lex_state_set(parser, PM_LEX_STATE_ARG);
11228 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11229 lex_state_set(parser, PM_LEX_STATE_BEG);
11235 if (lex_state_operator_p(parser)) {
11236 lex_state_set(parser, PM_LEX_STATE_ARG);
11238 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
11239 lex_state_set(parser, PM_LEX_STATE_BEG);
11242 if (match(parser,
'=')) {
11243 if (match(parser,
'>')) {
11254 if (match(parser,
'>')) {
11255 if (lex_state_operator_p(parser)) {
11256 lex_state_set(parser, PM_LEX_STATE_ARG);
11258 lex_state_set(parser, PM_LEX_STATE_BEG);
11263 if (lex_state_operator_p(parser)) {
11264 lex_state_set(parser, PM_LEX_STATE_ARG);
11266 lex_state_set(parser, PM_LEX_STATE_BEG);
11273 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11274 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
11280 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
11281 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11285 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
11286 if (previous_command_start) {
11287 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11289 lex_state_set(parser, PM_LEX_STATE_ARG);
11295 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
11301 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
11302 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
11308 LEX(lex_question_mark(parser));
11312 if (match(parser,
'&')) {
11313 lex_state_set(parser, PM_LEX_STATE_BEG);
11315 if (match(parser,
'=')) {
11322 if (match(parser,
'=')) {
11323 lex_state_set(parser, PM_LEX_STATE_BEG);
11327 if (match(parser,
'.')) {
11328 lex_state_set(parser, PM_LEX_STATE_DOT);
11333 if (lex_state_spcarg_p(parser, space_seen)) {
11334 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11335 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11337 const uint8_t delim = peek_offset(parser, 1);
11339 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1)) {
11340 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11345 }
else if (lex_state_beg_p(parser)) {
11347 }
else if (ambiguous_operator_p(parser, space_seen)) {
11348 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11351 if (lex_state_operator_p(parser)) {
11352 lex_state_set(parser, PM_LEX_STATE_ARG);
11354 lex_state_set(parser, PM_LEX_STATE_BEG);
11362 if (match(parser,
'|')) {
11363 if (match(parser,
'=')) {
11364 lex_state_set(parser, PM_LEX_STATE_BEG);
11368 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11373 lex_state_set(parser, PM_LEX_STATE_BEG);
11377 if (match(parser,
'=')) {
11378 lex_state_set(parser, PM_LEX_STATE_BEG);
11382 if (lex_state_operator_p(parser)) {
11383 lex_state_set(parser, PM_LEX_STATE_ARG);
11385 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11392 if (lex_state_operator_p(parser)) {
11393 lex_state_set(parser, PM_LEX_STATE_ARG);
11395 if (match(parser,
'@')) {
11402 if (match(parser,
'=')) {
11403 lex_state_set(parser, PM_LEX_STATE_BEG);
11408 lex_state_beg_p(parser) ||
11409 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) :
false)
11411 lex_state_set(parser, PM_LEX_STATE_BEG);
11413 if (pm_char_is_decimal_digit(peek(parser))) {
11416 lex_state_set(parser, PM_LEX_STATE_END);
11423 if (ambiguous_operator_p(parser, space_seen)) {
11424 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11427 lex_state_set(parser, PM_LEX_STATE_BEG);
11433 if (lex_state_operator_p(parser)) {
11434 lex_state_set(parser, PM_LEX_STATE_ARG);
11436 if (match(parser,
'@')) {
11443 if (match(parser,
'=')) {
11444 lex_state_set(parser, PM_LEX_STATE_BEG);
11448 if (match(parser,
'>')) {
11449 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11453 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11454 bool is_beg = lex_state_beg_p(parser);
11455 if (!is_beg && spcarg) {
11456 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11459 if (is_beg || spcarg) {
11460 lex_state_set(parser, PM_LEX_STATE_BEG);
11464 if (ambiguous_operator_p(parser, space_seen)) {
11465 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11468 lex_state_set(parser, PM_LEX_STATE_BEG);
11474 bool beg_p = lex_state_beg_p(parser);
11476 if (match(parser,
'.')) {
11477 if (match(parser,
'.')) {
11480 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11481 lex_state_set(parser, PM_LEX_STATE_BEG);
11483 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11489 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
11492 lex_state_set(parser, PM_LEX_STATE_BEG);
11496 lex_state_set(parser, PM_LEX_STATE_BEG);
11500 lex_state_set(parser, PM_LEX_STATE_DOT);
11516 lex_state_set(parser, PM_LEX_STATE_END);
11522 if (match(parser,
':')) {
11523 if (lex_state_beg_p(parser) || lex_state_p(parser, PM_LEX_STATE_CLASS) || (lex_state_p(parser, PM_LEX_STATE_ARG_ANY) && space_seen)) {
11524 lex_state_set(parser, PM_LEX_STATE_BEG);
11528 lex_state_set(parser, PM_LEX_STATE_DOT);
11532 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11533 lex_state_set(parser, PM_LEX_STATE_BEG);
11537 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11538 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
11542 lex_state_set(parser, PM_LEX_STATE_FNAME);
11547 if (lex_state_beg_p(parser)) {
11548 lex_mode_push_regexp(parser,
'\0',
'/');
11552 if (match(parser,
'=')) {
11553 lex_state_set(parser, PM_LEX_STATE_BEG);
11557 if (lex_state_spcarg_p(parser, space_seen)) {
11558 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
11559 lex_mode_push_regexp(parser,
'\0',
'/');
11563 if (ambiguous_operator_p(parser, space_seen)) {
11564 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11567 if (lex_state_operator_p(parser)) {
11568 lex_state_set(parser, PM_LEX_STATE_ARG);
11570 lex_state_set(parser, PM_LEX_STATE_BEG);
11577 if (lex_state_operator_p(parser)) {
11578 lex_state_set(parser, PM_LEX_STATE_ARG);
11580 lex_state_set(parser, PM_LEX_STATE_BEG);
11586 if (lex_state_operator_p(parser)) {
11587 (void) match(parser,
'@');
11588 lex_state_set(parser, PM_LEX_STATE_ARG);
11590 lex_state_set(parser, PM_LEX_STATE_BEG);
11601 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
11602 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11606 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11607 lex_state_set(parser, PM_LEX_STATE_BEG);
11610 lex_state_beg_p(parser) ||
11611 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11612 lex_state_spcarg_p(parser, space_seen)
11615 if (*parser->
current.end >= 0x80) {
11616 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11619 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11620 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11626 uint8_t delimiter = peek_offset(parser, 1);
11628 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11629 goto lex_next_token;
11632 switch (peek(parser)) {
11637 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11639 lex_mode_push_list_eof(parser);
11648 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11650 lex_mode_push_list_eof(parser);
11659 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11660 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11662 lex_mode_push_regexp(parser,
'\0',
'\0');
11671 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11672 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11674 lex_mode_push_string_eof(parser);
11683 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11684 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11686 lex_mode_push_string_eof(parser);
11695 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11696 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11697 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11699 lex_mode_push_string_eof(parser);
11708 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11710 lex_mode_push_list_eof(parser);
11719 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11721 lex_mode_push_list_eof(parser);
11730 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11731 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11733 lex_mode_push_string_eof(parser);
11743 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11744 goto lex_next_token;
11748 if (ambiguous_operator_p(parser, space_seen)) {
11749 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11752 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11763 lex_mode_pop(parser);
11766 lex_state_set(parser, PM_LEX_STATE_END);
11772 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11773 LEX(lex_at_variable(parser));
11776 if (*parser->
current.start !=
'_') {
11777 size_t width = char_is_identifier_start(parser, parser->
current.start);
11784 if (*parser->
current.start >= 0x80) {
11785 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
11786 }
else if (*parser->
current.start ==
'\\') {
11787 switch (peek_at(parser, parser->
current.start + 1)) {
11790 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11794 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11798 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11802 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11805 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11807 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11812 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11815 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11816 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11818 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11821 goto lex_next_token;
11835 current_token_starts_line(parser) &&
11836 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11837 (parser->
current.end == parser->
end || match_eol(parser))
11842 const uint8_t *cursor = parser->
current.end;
11843 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11844 pm_newline_list_append(&parser->
newline_list, cursor++);
11849 parser_lex_callback(parser);
11860 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11861 if (previous_command_start) {
11862 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11864 lex_state_set(parser, PM_LEX_STATE_ARG);
11866 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11867 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11869 lex_state_set(parser, PM_LEX_STATE_END);
11874 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11876 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11877 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11879 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11886 case PM_LEX_LIST: {
11900 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11901 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11908 if (whitespace > 0) {
11909 parser->
current.end += whitespace;
11910 if (peek_offset(parser, -1) ==
'\n') {
11912 parser_flush_heredoc_end(parser);
11926 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11927 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11933 while (breakpoint != NULL) {
11936 if (pm_char_is_whitespace(*breakpoint)) {
11937 parser->
current.end = breakpoint;
11938 pm_token_buffer_flush(parser, &token_buffer);
11948 parser->
current.end = breakpoint + 1;
11949 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11956 if (breakpoint > parser->
current.start) {
11957 parser->
current.end = breakpoint;
11958 pm_token_buffer_flush(parser, &token_buffer);
11964 parser->
current.end = breakpoint + 1;
11965 lex_mode_pop(parser);
11966 lex_state_set(parser, PM_LEX_STATE_END);
11971 if (*breakpoint ==
'\0') {
11972 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11979 if (*breakpoint ==
'\\') {
11980 parser->
current.end = breakpoint + 1;
11989 pm_token_buffer_escape(parser, &token_buffer);
11990 uint8_t peeked = peek(parser);
11998 pm_token_buffer_push_byte(&token_buffer, peeked);
12003 if (peek(parser) !=
'\n') {
12004 pm_token_buffer_push_byte(&token_buffer,
'\r');
12009 pm_token_buffer_push_byte(&token_buffer,
'\n');
12015 parser_flush_heredoc_end(parser);
12016 pm_token_buffer_copy(parser, &token_buffer);
12027 pm_token_buffer_push_byte(&token_buffer, peeked);
12030 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12032 pm_token_buffer_push_byte(&token_buffer,
'\\');
12033 pm_token_buffer_push_escaped(&token_buffer, parser);
12040 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12045 if (*breakpoint ==
'#') {
12053 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12058 pm_token_buffer_flush(parser, &token_buffer);
12067 parser->
current.end = breakpoint + 1;
12068 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12074 pm_token_buffer_flush(parser, &token_buffer);
12081 pm_token_buffer_flush(parser, &token_buffer);
12084 case PM_LEX_REGEXP: {
12106 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
12107 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12110 while (breakpoint != NULL) {
12112 bool is_terminator = (*breakpoint == term);
12117 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12118 if (term ==
'\n') {
12119 is_terminator =
true;
12125 if (term ==
'\r') {
12126 is_terminator =
false;
12132 if (is_terminator) {
12134 parser->
current.end = breakpoint + 1;
12135 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12143 if (breakpoint > parser->
current.start) {
12144 parser->
current.end = breakpoint;
12145 pm_regexp_token_buffer_flush(parser, &token_buffer);
12150 size_t eol_length = match_eol_at(parser, breakpoint);
12152 parser->
current.end = breakpoint + eol_length;
12155 parser->
current.end = breakpoint + 1;
12162 lex_mode_pop(parser);
12163 lex_state_set(parser, PM_LEX_STATE_END);
12169 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
12170 parser->
current.end = breakpoint + 1;
12171 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12176 switch (*breakpoint) {
12179 parser->
current.end = breakpoint + 1;
12180 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12183 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12184 parser->
current.end = breakpoint + 1;
12185 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12190 parser->
current.end = breakpoint;
12191 pm_regexp_token_buffer_escape(parser, &token_buffer);
12199 pm_newline_list_append(&parser->
newline_list, breakpoint);
12200 parser->
current.end = breakpoint + 1;
12201 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12205 parser->
current.end = breakpoint + 1;
12206 parser_flush_heredoc_end(parser);
12207 pm_regexp_token_buffer_flush(parser, &token_buffer);
12213 parser->
current.end = breakpoint + 1;
12222 pm_regexp_token_buffer_escape(parser, &token_buffer);
12223 uint8_t peeked = peek(parser);
12228 if (peek(parser) !=
'\n') {
12230 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12232 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
12233 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
12242 parser_flush_heredoc_end(parser);
12243 pm_regexp_token_buffer_copy(parser, &token_buffer);
12265 case '$':
case ')':
case '*':
case '+':
12266 case '.':
case '>':
case '?':
case ']':
12267 case '^':
case '|':
case '}':
12268 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12274 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12275 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12280 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12281 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12286 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12299 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
12304 pm_regexp_token_buffer_flush(parser, &token_buffer);
12310 assert(
false &&
"unreachable");
12316 pm_regexp_token_buffer_flush(parser, &token_buffer);
12323 pm_regexp_token_buffer_flush(parser, &token_buffer);
12326 case PM_LEX_STRING: {
12345 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
12346 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12352 while (breakpoint != NULL) {
12357 parser->
current.end = breakpoint + 1;
12358 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12363 bool is_terminator = (*breakpoint == term);
12368 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12369 if (term ==
'\n') {
12370 is_terminator =
true;
12376 if (term ==
'\r') {
12377 is_terminator =
false;
12384 if (is_terminator) {
12388 parser->
current.end = breakpoint + 1;
12389 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12396 if (breakpoint > parser->
current.start) {
12397 parser->
current.end = breakpoint;
12398 pm_token_buffer_flush(parser, &token_buffer);
12404 size_t eol_length = match_eol_at(parser, breakpoint);
12406 parser->
current.end = breakpoint + eol_length;
12409 parser->
current.end = breakpoint + 1;
12412 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12414 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12415 lex_mode_pop(parser);
12419 lex_state_set(parser, PM_LEX_STATE_END);
12420 lex_mode_pop(parser);
12424 switch (*breakpoint) {
12427 parser->
current.end = breakpoint + 1;
12428 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12431 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12432 parser->
current.end = breakpoint + 1;
12433 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12440 parser->
current.end = breakpoint;
12441 pm_token_buffer_escape(parser, &token_buffer);
12442 token_buffer.
cursor = breakpoint;
12451 pm_newline_list_append(&parser->
newline_list, breakpoint);
12452 parser->
current.end = breakpoint + 1;
12453 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12457 parser->
current.end = breakpoint + 1;
12458 parser_flush_heredoc_end(parser);
12459 pm_token_buffer_flush(parser, &token_buffer);
12463 parser->
current.end = breakpoint + 1;
12472 pm_token_buffer_escape(parser, &token_buffer);
12473 uint8_t peeked = peek(parser);
12477 pm_token_buffer_push_byte(&token_buffer,
'\\');
12482 if (peek(parser) !=
'\n') {
12484 pm_token_buffer_push_byte(&token_buffer,
'\\');
12486 pm_token_buffer_push_byte(&token_buffer,
'\r');
12492 pm_token_buffer_push_byte(&token_buffer,
'\\');
12493 pm_token_buffer_push_byte(&token_buffer,
'\n');
12500 parser_flush_heredoc_end(parser);
12501 pm_token_buffer_copy(parser, &token_buffer);
12512 pm_token_buffer_push_byte(&token_buffer, peeked);
12515 pm_token_buffer_push_byte(&token_buffer, peeked);
12518 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12520 pm_token_buffer_push_byte(&token_buffer,
'\\');
12521 pm_token_buffer_push_escaped(&token_buffer, parser);
12528 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12539 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12544 pm_token_buffer_flush(parser, &token_buffer);
12550 assert(
false &&
"unreachable");
12555 pm_token_buffer_flush(parser, &token_buffer);
12562 pm_token_buffer_flush(parser, &token_buffer);
12565 case PM_LEX_HEREDOC: {
12592 lex_state_set(parser, PM_LEX_STATE_END);
12593 lex_mode_pop(parser);
12597 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
12602 if (current_token_starts_line(parser)) {
12603 const uint8_t *start = parser->
current.start;
12605 if (!line_continuation && (start + ident_length <= parser->end)) {
12606 const uint8_t *newline = next_newline(start, parser->
end - start);
12607 const uint8_t *ident_end = newline;
12608 const uint8_t *terminator_end = newline;
12610 if (newline == NULL) {
12611 terminator_end = parser->
end;
12612 ident_end = parser->
end;
12615 if (newline[-1] ==
'\r') {
12620 const uint8_t *terminator_start = ident_end - ident_length;
12621 const uint8_t *cursor = start;
12623 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12624 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12630 (cursor == terminator_start) &&
12631 (memcmp(terminator_start, ident_start, ident_length) == 0)
12633 if (newline != NULL) {
12634 pm_newline_list_append(&parser->
newline_list, newline);
12637 parser->
current.end = terminator_end;
12645 lex_state_set(parser, PM_LEX_STATE_END);
12646 lex_mode_pop(parser);
12651 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
12653 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
12656 peek_at(parser, start) !=
'\n'
12665 uint8_t breakpoints[] =
"\r\n\\#";
12668 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12669 breakpoints[3] =
'\0';
12672 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12674 bool was_line_continuation =
false;
12676 while (breakpoint != NULL) {
12677 switch (*breakpoint) {
12680 parser->
current.end = breakpoint + 1;
12681 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12684 parser->
current.end = breakpoint + 1;
12686 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12687 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12694 pm_token_buffer_escape(parser, &token_buffer);
12695 token_buffer.
cursor = breakpoint;
12700 parser_flush_heredoc_end(parser);
12701 parser->
current.end = breakpoint + 1;
12702 pm_token_buffer_flush(parser, &token_buffer);
12706 pm_newline_list_append(&parser->
newline_list, breakpoint);
12710 const uint8_t *start = breakpoint + 1;
12712 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12715 const uint8_t *newline = next_newline(start, parser->
end - start);
12717 if (newline == NULL) {
12718 newline = parser->
end;
12719 }
else if (newline[-1] ==
'\r') {
12724 const uint8_t *terminator_start = newline - ident_length;
12728 const uint8_t *cursor = start;
12730 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12731 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12737 cursor == terminator_start &&
12738 (memcmp(terminator_start, ident_start, ident_length) == 0)
12740 parser->
current.end = breakpoint + 1;
12741 pm_token_buffer_flush(parser, &token_buffer);
12746 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
12753 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
12758 parser->
current.end = breakpoint + 1;
12759 pm_token_buffer_flush(parser, &token_buffer);
12765 parser->
current.end = breakpoint + 1;
12766 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12776 parser->
current.end = breakpoint + 1;
12785 pm_token_buffer_escape(parser, &token_buffer);
12786 uint8_t peeked = peek(parser);
12788 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12792 if (peek(parser) !=
'\n') {
12793 pm_token_buffer_push_byte(&token_buffer,
'\\');
12794 pm_token_buffer_push_byte(&token_buffer,
'\r');
12799 pm_token_buffer_push_byte(&token_buffer,
'\\');
12800 pm_token_buffer_push_byte(&token_buffer,
'\n');
12802 breakpoint = parser->
current.end;
12805 pm_token_buffer_push_byte(&token_buffer,
'\\');
12806 pm_token_buffer_push_escaped(&token_buffer, parser);
12813 if (peek(parser) !=
'\n') {
12814 pm_token_buffer_push_byte(&token_buffer,
'\r');
12822 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12823 const uint8_t *end = parser->
current.end;
12828 parser->
current.end = breakpoint;
12829 pm_token_buffer_flush(parser, &token_buffer);
12833 parser->
current.end = end + 1;
12838 was_line_continuation =
true;
12840 breakpoint = parser->
current.end;
12843 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12849 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12861 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12866 pm_token_buffer_flush(parser, &token_buffer);
12872 assert(
false &&
"unreachable");
12875 was_line_continuation =
false;
12880 pm_token_buffer_flush(parser, &token_buffer);
12887 pm_token_buffer_flush(parser, &token_buffer);
12892 assert(
false &&
"unreachable");
12910 PM_BINDING_POWER_UNSET = 0,
12911 PM_BINDING_POWER_STATEMENT = 2,
12912 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12913 PM_BINDING_POWER_MODIFIER = 6,
12914 PM_BINDING_POWER_COMPOSITION = 8,
12915 PM_BINDING_POWER_NOT = 10,
12916 PM_BINDING_POWER_MATCH = 12,
12917 PM_BINDING_POWER_DEFINED = 14,
12918 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12919 PM_BINDING_POWER_ASSIGNMENT = 18,
12920 PM_BINDING_POWER_TERNARY = 20,
12921 PM_BINDING_POWER_RANGE = 22,
12922 PM_BINDING_POWER_LOGICAL_OR = 24,
12923 PM_BINDING_POWER_LOGICAL_AND = 26,
12924 PM_BINDING_POWER_EQUALITY = 28,
12925 PM_BINDING_POWER_COMPARISON = 30,
12926 PM_BINDING_POWER_BITWISE_OR = 32,
12927 PM_BINDING_POWER_BITWISE_AND = 34,
12928 PM_BINDING_POWER_SHIFT = 36,
12929 PM_BINDING_POWER_TERM = 38,
12930 PM_BINDING_POWER_FACTOR = 40,
12931 PM_BINDING_POWER_UMINUS = 42,
12932 PM_BINDING_POWER_EXPONENT = 44,
12933 PM_BINDING_POWER_UNARY = 46,
12934 PM_BINDING_POWER_INDEX = 48,
12935 PM_BINDING_POWER_CALL = 50,
12936 PM_BINDING_POWER_MAX = 52
12937} pm_binding_power_t;
12960#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12961#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12962#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12963#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12964#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
13026 [
PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
13030 [
PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13031 [
PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
13047 [
PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
13048 [
PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
13051 [
PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
13059 [
PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13060 [
PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13061 [
PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
13068 [
PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
13072#undef BINDING_POWER_ASSIGNMENT
13073#undef LEFT_ASSOCIATIVE
13074#undef RIGHT_ASSOCIATIVE
13075#undef RIGHT_ASSOCIATIVE_UNARY
13090 return match1(parser, type1) || match1(parser, type2);
13098 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
13106 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
13114 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
13122 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8);
13130 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7) || match1(parser, type8) || match1(parser, type9);
13141 if (match1(parser,
type)) {
13142 parser_lex(parser);
13154 if (match2(parser, type1, type2)) {
13155 parser_lex(parser);
13174 if (accept1(parser,
type))
return;
13177 pm_parser_err(parser, location, location, diag_id);
13189 if (accept2(parser, type1, type2))
return;
13192 pm_parser_err(parser, location, location, diag_id);
13203expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
13205 parser_lex(parser);
13207 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
13214parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth);
13221parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth) {
13222 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
13223 pm_assert_value_expression(parser, node);
13277 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13297 return pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET;
13306parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
pm_diagnostic_id_t diag_id, uint16_t depth) {
13309 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13310 return (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
13313 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
13327 size_t length = constant->
length;
13328 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
13329 if (name == NULL)
return;
13331 memcpy(name, constant->
start, length);
13332 name[length] =
'=';
13337 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
13349 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13350 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13351 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13352 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13353 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13354 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13355 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13362 pm_node_destroy(parser, target);
13375 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13376 if (implicit_parameters->
nodes[index] == node) {
13380 if (index != implicit_parameters->
size - 1) {
13381 memcpy(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13384 implicit_parameters->
size--;
13412 return parse_unwriteable_target(parser, target);
13419 if (context_def_p(parser)) {
13420 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13428 if (context_def_p(parser)) {
13429 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13438 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13447 parse_target_implicit_parameter(parser, target);
13451 uint32_t name = cast->
name;
13452 uint32_t depth = cast->
depth;
13453 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13464 parse_target_implicit_parameter(parser, target);
13465 pm_node_destroy(parser, target);
13474 if (splat_parent) {
13477 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13502 (call->
block == NULL)
13517 pm_node_destroy(parser, target);
13519 return (
pm_node_t *) pm_local_variable_target_node_create(parser, &message_loc, name, 0);
13524 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13527 parse_write_name(parser, &call->
name);
13528 return (
pm_node_t *) pm_call_target_node_create(parser, call);
13536 return (
pm_node_t *) pm_index_target_node_create(parser, call);
13544 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13555 pm_node_t *result = parse_target(parser, target, multiple,
false);
13564 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13578 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13579 return (
pm_node_t *) pm_shareable_constant_node_create(parser, write, shareable_constant);
13592 pm_node_destroy(parser, value);
13596 pm_node_destroy(parser, target);
13602 if (context_def_p(parser)) {
13603 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13606 return parse_shareable_constant_write(parser, node);
13611 if (context_def_p(parser)) {
13612 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13615 pm_node_destroy(parser, target);
13616 return parse_shareable_constant_write(parser, node);
13620 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13624 pm_node_destroy(parser, target);
13633 uint32_t depth = local_read->
depth;
13634 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13637 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13639 parse_target_implicit_parameter(parser, target);
13642 pm_locals_unread(&scope->
locals, name);
13643 pm_node_destroy(parser, target);
13645 return (
pm_node_t *) pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator);
13651 parse_target_implicit_parameter(parser, target);
13652 pm_node_destroy(parser, target);
13658 pm_node_destroy(parser, target);
13671 pm_multi_target_node_targets_append(parser, multi_target, (
pm_node_t *) splat);
13673 return (
pm_node_t *) pm_multi_write_node_create(parser, multi_target,
operator, value);
13687 (call->
block == NULL)
13701 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13702 pm_node_destroy(parser, target);
13705 target = (
pm_node_t *) pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator);
13707 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13725 pm_arguments_node_arguments_append(arguments, value);
13728 parse_write_name(parser, &call->
name);
13740 call->
arguments = pm_arguments_node_create(parser);
13743 pm_arguments_node_arguments_append(call->
arguments, value);
13747 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13761 pm_node_destroy(parser, value);
13768 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13782 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13783 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13784 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13785 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13786 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13787 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13788 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13795 pm_node_destroy(parser, target);
13810parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13814 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13822 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13828 if (token_begins_expression_p(parser->
current.type)) {
13829 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13830 name = parse_target(parser, name,
true,
true);
13833 pm_node_t *splat = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
13834 pm_multi_target_node_targets_append(parser, result, splat);
13838 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13839 target = parse_target(parser, target,
true,
false);
13841 pm_multi_target_node_targets_append(parser, result, target);
13842 context_pop(parser);
13843 }
else if (token_begins_expression_p(parser->
current.type)) {
13844 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13845 target = parse_target(parser, target,
true,
false);
13847 pm_multi_target_node_targets_append(parser, result, target);
13852 pm_multi_target_node_targets_append(parser, result, rest);
13865parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13866 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13871 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13887 if (context_terminator(context, &parser->
current))
return NULL;
13893 context_push(parser, context);
13896 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13897 pm_statements_node_body_append(parser, statements, node,
true);
13914 if (context_terminator(context, &parser->
current))
break;
13924 if (context_terminator(context, &parser->
current))
break;
13937 parser_lex(parser);
13949 if (context_terminator(context, &parser->
current))
break;
13960 context_pop(parser);
13961 bool last_value =
true;
13965 last_value =
false;
13970 pm_void_statements_check(parser, statements, last_value);
13983 if (duplicated != NULL) {
13987 pm_diagnostic_list_append_format(
13991 PM_WARN_DUPLICATED_HASH_KEY,
13992 (
int) pm_buffer_length(&buffer),
13993 pm_buffer_value(&buffer),
13997 pm_buffer_free(&buffer);
14009 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
14010 pm_diagnostic_list_append_format(
14014 PM_WARN_DUPLICATED_WHEN_CLAUSE,
14027 bool contains_keyword_splat =
false;
14032 switch (parser->
current.type) {
14034 parser_lex(parser);
14044 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14045 }
else if (token_begins_expression_p(parser->
current.type)) {
14046 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
14048 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14051 element = (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
14052 contains_keyword_splat =
true;
14057 parser_lex(parser);
14060 pm_hash_key_static_literals_add(parser, literals, key);
14065 if (token_begins_expression_p(parser->
current.type)) {
14066 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14070 value = (
pm_node_t *) pm_constant_read_node_create(parser, &constant);
14075 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14076 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14078 depth = pm_parser_local_depth(parser, &identifier);
14082 value = (
pm_node_t *) pm_call_node_variable_call_create(parser, &identifier);
14084 value = (
pm_node_t *) pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth);
14089 value = (
pm_node_t *) pm_implicit_node_create(parser, value);
14092 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14096 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
14104 pm_hash_key_static_literals_add(parser, literals, key);
14107 if (pm_symbol_node_label_p(key)) {
14108 operator = not_provided(parser);
14114 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14115 element = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
14135 if (token_begins_expression_p(parser->
current.type))
continue;
14141 return contains_keyword_splat;
14150 arguments->
arguments = pm_arguments_node_create(parser);
14153 pm_arguments_node_arguments_append(arguments->
arguments, argument);
14161 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].left;
14167 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14173 bool parsed_first_argument =
false;
14174 bool parsed_bare_hash =
false;
14175 bool parsed_block_argument =
false;
14176 bool parsed_forwarding_arguments =
false;
14179 if (parsed_forwarding_arguments) {
14180 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14185 switch (parser->
current.type) {
14188 if (parsed_bare_hash) {
14189 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14196 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) hash, (uint16_t) (depth + 1));
14198 parse_arguments_append(parser, arguments, argument);
14204 pm_static_literals_free(&hash_keys);
14205 parsed_bare_hash =
true;
14210 parser_lex(parser);
14214 if (token_begins_expression_p(parser->
current.type)) {
14215 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14217 pm_parser_scope_forwarding_block_check(parser, &
operator);
14220 argument = (
pm_node_t *) pm_block_argument_node_create(parser, &
operator, expression);
14221 if (parsed_block_argument) {
14222 parse_arguments_append(parser, arguments, argument);
14224 arguments->
block = argument;
14228 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14231 parsed_block_argument =
true;
14235 parser_lex(parser);
14239 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14240 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, NULL);
14241 if (parsed_bare_hash) {
14242 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14245 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
14247 if (parsed_bare_hash) {
14248 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14251 argument = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
14254 parse_arguments_append(parser, arguments, argument);
14258 if (accepts_forwarding) {
14259 parser_lex(parser);
14261 if (token_begins_expression_p(parser->
current.type)) {
14266 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
14273 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14276 argument = (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
14278 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
14279 if (parsed_first_argument && terminator ==
PM_TOKEN_EOF) {
14280 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14283 argument = (
pm_node_t *) pm_forwarding_arguments_node_create(parser, &parser->
previous);
14284 parse_arguments_append(parser, arguments, argument);
14287 parsed_forwarding_arguments =
true;
14294 if (argument == NULL) {
14295 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14298 bool contains_keywords =
false;
14299 bool contains_keyword_splat =
false;
14302 if (parsed_bare_hash) {
14303 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14310 operator = not_provided(parser);
14314 contains_keywords =
true;
14318 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14321 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
14322 argument = (
pm_node_t *) pm_assoc_node_create(parser, argument, &
operator, value);
14324 pm_keyword_hash_node_elements_append(bare_hash, argument);
14329 token_begins_expression_p(parser->
current.type) ||
14332 contains_keyword_splat = parse_assocs(parser, &hash_keys, (
pm_node_t *) bare_hash, (uint16_t) (depth + 1));
14335 pm_static_literals_free(&hash_keys);
14336 parsed_bare_hash =
true;
14339 parse_arguments_append(parser, arguments, argument);
14350 parsed_first_argument =
true;
14358 bool accepted_newline =
false;
14370 if (accepted_newline) {
14371 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14381 if (match1(parser, terminator))
break;
14396parse_required_destructured_parameter(
pm_parser_t *parser) {
14400 pm_multi_target_node_opening_set(node, &parser->
previous);
14411 pm_multi_target_node_targets_append(parser, node, param);
14412 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14417 param = (
pm_node_t *) parse_required_destructured_parameter(parser);
14424 value = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14425 if (pm_parser_parameter_name_check(parser, &name)) {
14426 pm_node_flag_set_repeated_parameter(value);
14428 pm_parser_local_add_token(parser, &name, 1);
14431 param = (
pm_node_t *) pm_splat_node_create(parser, &star, value);
14436 param = (
pm_node_t *) pm_required_parameter_node_create(parser, &name);
14437 if (pm_parser_parameter_name_check(parser, &name)) {
14438 pm_node_flag_set_repeated_parameter(param);
14440 pm_parser_local_add_token(parser, &name, 1);
14443 pm_multi_target_node_targets_append(parser, node, param);
14448 pm_multi_target_node_closing_set(node, &parser->
previous);
14458 PM_PARAMETERS_NO_CHANGE = 0,
14459 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14460 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14461 PM_PARAMETERS_ORDER_KEYWORDS,
14462 PM_PARAMETERS_ORDER_REST,
14463 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14464 PM_PARAMETERS_ORDER_OPTIONAL,
14465 PM_PARAMETERS_ORDER_NAMED,
14466 PM_PARAMETERS_ORDER_NONE,
14467} pm_parameters_order_t;
14473 [0] = PM_PARAMETERS_NO_CHANGE,
14496 pm_parameters_order_t state = parameters_ordering[token->type];
14497 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14501 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14502 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14504 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14508 if (token->type ==
PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14509 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14511 }
else if (token->type ==
PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14512 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14514 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14516 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14520 if (state < *current) *current = state;
14530 pm_binding_power_t binding_power,
14531 bool uses_parentheses,
14532 bool allows_trailing_comma,
14533 bool allows_forwarding_parameters,
14534 bool accepts_blocks_in_defaults,
14538 pm_do_loop_stack_push(parser,
false);
14541 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14544 bool parsing =
true;
14546 switch (parser->
current.type) {
14548 update_parameter_state(parser, &parser->
current, &order);
14551 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14552 pm_parameters_node_requireds_append(params, param);
14554 pm_parameters_node_posts_append(params, param);
14560 update_parameter_state(parser, &parser->
current, &order);
14561 parser_lex(parser);
14566 bool repeated =
false;
14569 repeated = pm_parser_parameter_name_check(parser, &name);
14570 pm_parser_local_add_token(parser, &name, 1);
14572 name = not_provided(parser);
14578 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14580 if (params->
block == NULL) {
14581 pm_parameters_node_block_set(params, param);
14583 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_BLOCK_MULTI);
14584 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14590 if (!allows_forwarding_parameters) {
14591 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
14594 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
14595 parser_lex(parser);
14604 pm_parameters_node_posts_append(params, keyword_rest);
14605 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14609 pm_parameters_node_keyword_rest_set(params, (
pm_node_t *) param);
14618 parser_lex(parser);
14621 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14624 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14627 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14630 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14633 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14639 update_parameter_state(parser, &parser->
current, &order);
14641 update_parameter_state(parser, &parser->
previous, &order);
14645 bool repeated = pm_parser_parameter_name_check(parser, &name);
14646 pm_parser_local_add_token(parser, &name, 1);
14651 parser_lex(parser);
14656 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14657 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14658 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14663 pm_node_flag_set_repeated_parameter((
pm_node_t *) param);
14665 pm_parameters_node_optionals_append(params, param);
14671 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14674 context_pop(parser);
14683 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14686 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14688 pm_parameters_node_requireds_append(params, (
pm_node_t *) param);
14692 pm_node_flag_set_repeated_parameter((
pm_node_t *)param);
14694 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14700 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14701 update_parameter_state(parser, &parser->
current, &order);
14704 parser_lex(parser);
14711 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14712 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14713 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14716 bool repeated = pm_parser_parameter_name_check(parser, &local);
14717 pm_parser_local_add_token(parser, &local, 1);
14719 switch (parser->
current.type) {
14723 context_pop(parser);
14725 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14727 pm_node_flag_set_repeated_parameter(param);
14730 pm_parameters_node_keywords_append(params, param);
14735 context_pop(parser);
14737 if (uses_parentheses) {
14742 pm_node_t *param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14744 pm_node_flag_set_repeated_parameter(param);
14747 pm_parameters_node_keywords_append(params, param);
14753 if (token_begins_expression_p(parser->
current.type)) {
14757 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14758 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14759 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14762 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14765 param = (
pm_node_t *) pm_optional_keyword_parameter_node_create(parser, &name, value);
14768 param = (
pm_node_t *) pm_required_keyword_parameter_node_create(parser, &name);
14772 pm_node_flag_set_repeated_parameter(param);
14775 context_pop(parser);
14776 pm_parameters_node_keywords_append(params, param);
14793 update_parameter_state(parser, &parser->
current, &order);
14794 parser_lex(parser);
14798 bool repeated =
false;
14802 repeated = pm_parser_parameter_name_check(parser, &name);
14803 pm_parser_local_add_token(parser, &name, 1);
14805 name = not_provided(parser);
14809 pm_node_t *param = (
pm_node_t *) pm_rest_parameter_node_create(parser, &
operator, &name);
14811 pm_node_flag_set_repeated_parameter(param);
14814 if (params->
rest == NULL) {
14815 pm_parameters_node_rest_set(params, param);
14817 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14818 pm_parameters_node_posts_append(params, param);
14825 pm_parameters_order_t previous_order = order;
14826 update_parameter_state(parser, &parser->
current, &order);
14827 parser_lex(parser);
14833 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14834 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14837 param = (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
14841 bool repeated =
false;
14844 repeated = pm_parser_parameter_name_check(parser, &name);
14845 pm_parser_local_add_token(parser, &name, 1);
14847 name = not_provided(parser);
14851 param = (
pm_node_t *) pm_keyword_rest_parameter_node_create(parser, &
operator, &name);
14853 pm_node_flag_set_repeated_parameter(param);
14858 pm_parameters_node_keyword_rest_set(params, param);
14860 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14861 pm_parameters_node_posts_append(params, param);
14868 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14873 if (params->
rest == NULL) {
14874 pm_parameters_node_rest_set(params, param);
14876 pm_parser_err_node(parser, (
pm_node_t *) param, PM_ERR_PARAMETER_SPLAT_MULTI);
14877 pm_parameters_node_posts_append(params, (
pm_node_t *) param);
14880 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14891 if (!parsing)
break;
14893 bool accepted_newline =
false;
14894 if (uses_parentheses) {
14901 if (accepted_newline) {
14902 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14910 pm_do_loop_stack_pop(parser);
14914 pm_node_destroy(parser, (
pm_node_t *) params);
14946token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14948 const uint8_t *end = token->start;
14952 newline_index == 0 &&
14953 parser->
start[0] == 0xef &&
14954 parser->
start[1] == 0xbb &&
14955 parser->
start[2] == 0xbf
14958 int64_t column = 0;
14959 for (; cursor < end; cursor++) {
14962 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14969 if (break_on_non_space)
return -1;
14982parser_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) {
14987 size_t closing_newline_index = token_newline_index(parser);
14988 if (opening_newline_index == closing_newline_index)
return;
14993 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14994 if (!if_after_else && (opening_column == -1))
return;
15001 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15002 if ((closing_column == -1) || (opening_column == closing_column))
return;
15006 if (allow_indent && (closing_column > opening_column))
return;
15009 PM_PARSER_WARN_FORMAT(
15011 closing_token->
start,
15012 closing_token->
end,
15013 PM_WARN_INDENTATION_MISMATCH,
15014 (
int) (closing_token->
end - closing_token->
start),
15015 (
const char *) closing_token->
start,
15016 (
int) (opening_token->
end - opening_token->
start),
15017 (
const char *) opening_token->
start,
15018 ((int32_t) opening_newline_index) + parser->
start_line
15023 PM_RESCUES_BEGIN = 1,
15030} pm_rescues_type_t;
15041 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15042 parser_lex(parser);
15046 switch (parser->
current.type) {
15051 parser_lex(parser);
15052 pm_rescue_node_operator_set(rescue, &parser->
previous);
15054 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15055 reference = parse_target(parser, reference,
false,
false);
15057 pm_rescue_node_reference_set(rescue, reference);
15072 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15073 pm_rescue_node_exceptions_append(rescue, expression);
15082 pm_rescue_node_operator_set(rescue, &parser->
previous);
15084 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15085 reference = parse_target(parser, reference,
false,
false);
15087 pm_rescue_node_reference_set(rescue, reference);
15102 pm_accepts_block_stack_push(parser,
true);
15117 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15119 pm_accepts_block_stack_pop(parser);
15123 if (current == NULL) {
15124 pm_begin_node_rescue_clause_set(parent_node, rescue);
15126 pm_rescue_node_subsequent_set(current, rescue);
15135 if (current != NULL) {
15139 while (clause != NULL) {
15147 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15148 opening_newline_index = token_newline_index(parser);
15150 else_keyword = parser->
current;
15151 opening = &else_keyword;
15153 parser_lex(parser);
15158 pm_accepts_block_stack_push(parser,
true);
15172 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15173 pm_accepts_block_stack_pop(parser);
15178 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
15179 pm_begin_node_else_clause_set(parent_node, else_clause);
15183 if (current == NULL) pm_parser_err_node(parser, (
pm_node_t *) else_clause, PM_ERR_BEGIN_LONELY_ELSE);
15187 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15190 parser_lex(parser);
15195 pm_accepts_block_stack_push(parser,
true);
15209 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15210 pm_accepts_block_stack_pop(parser);
15215 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
15216 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15220 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15221 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
15224 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
15234 pm_token_t begin_keyword = not_provided(parser);
15235 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
15237 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15247parse_block_parameters(
15249 bool allows_trailing_comma,
15251 bool is_lambda_literal,
15252 bool accepts_blocks_in_defaults,
15257 parameters = parse_parameters(
15259 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15261 allows_trailing_comma,
15263 accepts_blocks_in_defaults,
15265 (uint16_t) (depth + 1)
15275 switch (parser->
current.type) {
15277 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15278 parser_lex(parser);
15281 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15282 parser_lex(parser);
15285 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15286 parser_lex(parser);
15289 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15290 parser_lex(parser);
15297 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
15298 pm_parser_local_add_token(parser, &parser->
previous, 1);
15301 if (repeated) pm_node_flag_set_repeated_parameter((
pm_node_t *) local);
15303 pm_block_parameters_node_append_local(block_parameters, local);
15308 return block_parameters;
15316outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15318 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15329static const char *
const pm_numbered_parameter_names[] = {
15330 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15344 if (parameters != NULL) {
15346 if (implicit_parameters->
size > 0) {
15350 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15352 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15354 assert(
false &&
"unreachable");
15363 if (implicit_parameters->
size == 0) {
15370 uint8_t numbered_parameter = 0;
15371 bool it_parameter =
false;
15373 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15377 if (it_parameter) {
15378 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15379 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15380 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15382 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15384 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
15386 assert(
false &&
"unreachable");
15389 if (numbered_parameter > 0) {
15390 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15392 it_parameter =
true;
15397 if (numbered_parameter > 0) {
15401 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15405 return (
pm_node_t *) pm_numbered_parameters_node_create(parser, &location, numbered_parameter);
15408 if (it_parameter) {
15409 return (
pm_node_t *) pm_it_parameters_node_create(parser, opening, closing);
15419parse_block(
pm_parser_t *parser, uint16_t depth) {
15423 pm_accepts_block_stack_push(parser,
true);
15424 pm_parser_scope_push(parser,
false);
15431 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15433 parser_lex(parser);
15435 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15438 expect1(parser,
PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15441 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
15456 pm_accepts_block_stack_push(parser,
true);
15458 pm_accepts_block_stack_pop(parser);
15463 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));
15471 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
15474 pm_parser_scope_pop(parser);
15475 pm_accepts_block_stack_pop(parser);
15477 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
15486parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
15487 bool found =
false;
15496 pm_accepts_block_stack_push(parser,
true);
15505 pm_accepts_block_stack_pop(parser);
15510 pm_accepts_block_stack_push(parser,
false);
15515 parse_arguments(parser, arguments, accepts_block,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
15524 pm_accepts_block_stack_pop(parser);
15530 if (accepts_block) {
15535 block = parse_block(parser, (uint16_t) (depth + 1));
15536 pm_arguments_validate_block(parser, arguments, block);
15539 block = parse_block(parser, (uint16_t) (depth + 1));
15542 if (block != NULL) {
15546 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_BLOCK_MULTI);
15548 if (arguments->
block != NULL) {
15550 arguments->
arguments = pm_arguments_node_create(parser);
15552 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
15568 bool in_sclass =
false;
15570 switch (context_node->
context) {
15615 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15637 assert(
false &&
"unreachable");
15642 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15653 switch (context_node->
context) {
15727 assert(
false &&
"unreachable");
15741 return previous_block_exits;
15759 default: assert(
false &&
"unreachable");
type =
"";
break;
15762 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15779 }
else if (previous_block_exits != NULL) {
15791 flush_block_exits(parser, previous_block_exits);
15799 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15805 predicate_closed =
true;
15809 if (!predicate_closed) {
15810 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15813 context_pop(parser);
15818parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15820 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15823 pm_token_t then_keyword = not_provided(parser);
15825 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15829 pm_accepts_block_stack_push(parser,
true);
15830 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15831 pm_accepts_block_stack_pop(parser);
15835 pm_token_t end_keyword = not_provided(parser);
15840 parent = (
pm_node_t *) pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15843 parent = (
pm_node_t *) pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements);
15846 assert(
false &&
"unreachable");
15856 if (parser_end_of_line_p(parser)) {
15857 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15860 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15862 parser_lex(parser);
15864 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15865 pm_accepts_block_stack_push(parser,
true);
15868 pm_accepts_block_stack_pop(parser);
15871 pm_node_t *elsif = (
pm_node_t *) pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword);
15878 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15879 opening_newline_index = token_newline_index(parser);
15881 parser_lex(parser);
15884 pm_accepts_block_stack_push(parser,
true);
15886 pm_accepts_block_stack_pop(parser);
15889 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15892 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15902 assert(
false &&
"unreachable");
15906 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15914 bool recursing =
true;
15916 while (recursing) {
15921 recursing = current != NULL;
15939 assert(
false &&
"unreachable");
15943 pop_block_exits(parser, previous_block_exits);
15944 pm_node_list_free(¤t_block_exits);
15953#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15954 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15955 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15956 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15957 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15958 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15959 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15960 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15961 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15962 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15963 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15969#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15970 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15971 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15972 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15973 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15974 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15975 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15976 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15983#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15984 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15985 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15986 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15987 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15988 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15989 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15990 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15991 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15997#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15998 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15999 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16000 case PM_TOKEN_CLASS_VARIABLE
16006#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16007 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16008 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16009 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16020parse_unescaped_encoding(
const pm_parser_t *parser) {
16042parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16043 switch (parser->
current.type) {
16055 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16057 parser_lex(parser);
16075 lex_state_set(parser, PM_LEX_STATE_BEG);
16076 parser_lex(parser);
16082 pm_accepts_block_stack_push(parser,
true);
16084 pm_accepts_block_stack_pop(parser);
16088 lex_state_set(parser, state);
16096 if (statements != NULL && statements->
body.
size == 1) {
16100 return (
pm_node_t *) pm_embedded_statements_node_create(parser, &opening, statements, &closing);
16114 lex_state_set(parser, PM_LEX_STATE_BEG);
16115 parser_lex(parser);
16120 switch (parser->
current.type) {
16124 parser_lex(parser);
16125 variable = (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16130 parser_lex(parser);
16131 variable = (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16136 parser_lex(parser);
16137 variable = (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16142 parser_lex(parser);
16143 variable = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &parser->
previous);
16148 parser_lex(parser);
16149 variable = (
pm_node_t *) pm_class_variable_read_node_create(parser, &parser->
previous);
16160 return (
pm_node_t *) pm_embedded_variable_node_create(parser, &
operator, variable);
16163 parser_lex(parser);
16164 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16174static const uint8_t *
16175parse_operator_symbol_name(
const pm_token_t *name) {
16176 switch (name->type) {
16179 if (name->end[-1] ==
'@')
return name->end - 1;
16191 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
16193 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16194 parser_lex(parser);
16211 if (lex_mode->
mode != PM_LEX_STRING) {
16212 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16214 switch (parser->
current.type) {
16215 case PM_CASE_OPERATOR:
16216 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16225 case PM_CASE_KEYWORD:
16226 parser_lex(parser);
16237 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16245 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16246 parser_lex(parser);
16250 return (
pm_node_t *) pm_symbol_node_create(parser, &opening, &content, &closing);
16254 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16259 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16266 if (part) pm_interpolated_symbol_node_append(symbol, part);
16269 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16270 pm_interpolated_symbol_node_append(symbol, part);
16274 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16276 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16281 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16291 parser_lex(parser);
16306 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped);
16307 pm_interpolated_symbol_node_append(symbol, part);
16310 pm_interpolated_symbol_node_append(symbol, part);
16312 if (next_state != PM_LEX_STATE_NONE) {
16313 lex_state_set(parser, next_state);
16316 parser_lex(parser);
16319 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
16324 pm_string_shared_init(&unescaped, content.
start, content.
end);
16327 if (next_state != PM_LEX_STATE_NONE) {
16328 lex_state_set(parser, next_state);
16332 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16337 return (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false));
16345parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16346 switch (parser->
current.type) {
16347 case PM_CASE_OPERATOR: {
16348 const pm_token_t opening = not_provided(parser);
16349 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
16351 case PM_CASE_KEYWORD:
16355 parser_lex(parser);
16362 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16368 parser_lex(parser);
16370 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16373 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16385parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16386 switch (parser->
current.type) {
16387 case PM_CASE_OPERATOR: {
16388 const pm_token_t opening = not_provided(parser);
16389 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16391 case PM_CASE_KEYWORD:
16395 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16396 parser_lex(parser);
16403 pm_node_flag_set((
pm_node_t *) symbol, parse_symbol_encoding(parser, &parser->
previous, &symbol->unescaped,
false));
16409 parser_lex(parser);
16411 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16414 parser_lex(parser);
16415 return (
pm_node_t *) pm_back_reference_read_node_create(parser, &parser->
previous);
16417 parser_lex(parser);
16418 return (
pm_node_t *) pm_numbered_reference_read_node_create(parser, &parser->
previous);
16420 parser_lex(parser);
16421 return (
pm_node_t *) pm_global_variable_read_node_create(parser, &parser->
previous);
16423 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16438 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16439 return (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false);
16443 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16444 if (is_numbered_param) {
16449 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
16450 for (uint8_t number = 1; number <= maximum; number++) {
16451 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16458 pm_node_t *node = (
pm_node_t *) pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false);
16481 pm_node_t *node = parse_variable(parser);
16482 if (node != NULL)
return node;
16487 pm_node_flag_set((
pm_node_t *)node, flags);
16498parse_method_definition_name(
pm_parser_t *parser) {
16499 switch (parser->
current.type) {
16500 case PM_CASE_KEYWORD:
16503 parser_lex(parser);
16506 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
16507 parser_lex(parser);
16509 case PM_CASE_OPERATOR:
16510 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16511 parser_lex(parser);
16520parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
16523 pm_string_ensure_owned(
string);
16528 size_t dest_length = pm_string_length(
string);
16529 const uint8_t *source_cursor = (uint8_t *) string->
source;
16530 const uint8_t *source_end = source_cursor + dest_length;
16535 size_t trimmed_whitespace = 0;
16541 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16542 if (*source_cursor ==
'\t') {
16543 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16544 if (trimmed_whitespace > common_whitespace)
break;
16546 trimmed_whitespace++;
16553 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
16554 string->length = dest_length;
16564 bool dedent_next =
true;
16569 size_t write_index = 0;
16577 nodes->
nodes[write_index++] = node;
16578 dedent_next =
false;
16584 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
16588 pm_node_destroy(parser, node);
16590 nodes->
nodes[write_index++] = node;
16594 dedent_next =
true;
16597 nodes->
size = write_index;
16604parse_strings_empty_content(
const uint8_t *location) {
16614 bool concating =
false;
16622 assert(lex_mode->
mode == PM_LEX_STRING);
16624 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
16627 parser_lex(parser);
16649 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16650 }
else if (!lex_interpolation) {
16658 content = not_provided(parser);
16679 pm_token_t delimiters = not_provided(parser);
16680 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped);
16681 pm_node_list_append(&parts, part);
16684 part = (
pm_node_t *) pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters);
16685 pm_node_list_append(&parts, part);
16686 parser_lex(parser);
16690 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16692 pm_node_list_free(&parts);
16694 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16695 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16697 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16698 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16700 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16705 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
16714 parser_lex(parser);
16717 node = (
pm_node_t *) pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
16718 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16726 if (location > parser->
start && location[-1] ==
'\n') location--;
16727 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16733 node = (
pm_node_t *) pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true));
16734 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16739 pm_token_t string_opening = not_provided(parser);
16740 pm_token_t string_closing = not_provided(parser);
16742 pm_node_t *part = (
pm_node_t *) pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped);
16743 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16744 pm_node_list_append(&parts, part);
16747 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16748 pm_node_list_append(&parts, part);
16753 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16754 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16756 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16757 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16760 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16763 pm_node_list_free(&parts);
16773 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16774 pm_node_list_append(&parts, part);
16779 node = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous);
16780 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16782 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16783 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current);
16786 node = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous);
16789 pm_node_list_free(&parts);
16792 if (current == NULL) {
16808 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16818 pm_interpolated_string_node_append(container, current);
16829#define PM_PARSE_PATTERN_SINGLE 0
16830#define PM_PARSE_PATTERN_TOP 1
16831#define PM_PARSE_PATTERN_MULTI 2
16844 if (*location->
start ==
'_')
return;
16846 if (pm_constant_id_list_includes(captures, capture)) {
16847 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16849 pm_constant_id_list_append(captures, capture);
16863 node = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
16882 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16889 parser_lex(parser);
16894 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16905 return (
pm_node_t *) pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16921 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16922 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16937 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16938 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16953 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16954 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16968 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16969 pm_array_pattern_node_requireds_append(pattern_node, inner);
16987 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16990 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16991 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16994 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16995 name = (
pm_node_t *) pm_local_variable_target_node_create(
16997 &PM_LOCATION_TOKEN_VALUE(&identifier),
16999 (uint32_t) (depth == -1 ? 0 : depth)
17004 return pm_splat_node_create(parser, &
operator, name);
17013 parser_lex(parser);
17019 return (
pm_node_t *) pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous);
17026 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17030 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17031 value = (
pm_node_t *) pm_local_variable_target_node_create(
17033 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17035 (uint32_t) (depth == -1 ? 0 : depth)
17039 return (
pm_node_t *) pm_assoc_splat_node_create(parser, value, &
operator);
17047pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17048 ptrdiff_t length = end - start;
17049 if (length == 0)
return false;
17052 size_t width = char_is_identifier_start(parser, start);
17053 if (width == 0)
return false;
17059 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17064 const uint8_t *cursor = start + width;
17065 while ((cursor < end) && (width = char_is_identifier(parser, cursor))) cursor += width;
17066 return cursor == end;
17080 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
17081 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17083 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
17085 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
17086 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);
17091 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
17094 parse_pattern_capture(parser, captures, constant_id, value_loc);
17099 (uint32_t) (depth == -1 ? 0 : depth)
17112 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17131 if (pm_symbol_node_label_p(first_node)) {
17132 parse_pattern_hash_key(parser, &keys, first_node);
17138 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17142 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17146 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17148 pm_node_list_append(&assocs, assoc);
17158 pm_parser_err_node(parser, first_node, diag_id);
17162 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, first_node, &
operator, value);
17164 pm_node_list_append(&assocs, assoc);
17174 if (rest != NULL) {
17175 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17182 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17184 if (rest == NULL) {
17187 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17188 pm_node_list_append(&assocs, assoc);
17194 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17197 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17198 }
else if (!pm_symbol_node_label_p(key)) {
17199 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17202 expect1(parser,
PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17206 parse_pattern_hash_key(parser, &keys, key);
17210 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17212 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17216 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, key, &
operator, value);
17218 if (rest != NULL) {
17219 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17222 pm_node_list_append(&assocs, assoc);
17229 pm_static_literals_free(&keys);
17238 switch (parser->
current.type) {
17241 parser_lex(parser);
17245 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17249 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17250 return (
pm_node_t *) pm_local_variable_target_node_create(
17252 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17254 (uint32_t) (depth == -1 ? 0 : depth)
17259 parser_lex(parser);
17264 return (
pm_node_t *) pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous);
17269 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17282 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17283 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17296 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17297 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17309 pm_array_pattern_node_requireds_append(node, inner);
17318 parser_lex(parser);
17323 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
17327 switch (parser->
current.type) {
17329 parser_lex(parser);
17330 first_node = (
pm_node_t *) pm_symbol_node_label_create(parser, &parser->
previous);
17333 first_node = parse_pattern_keyword_rest(parser, captures);
17336 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17340 parser_lex(parser);
17347 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17356 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17357 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
17366 parser_lex(parser);
17370 switch (parser->
current.type) {
17371 case PM_CASE_PRIMITIVE: {
17372 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17373 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17376 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17377 pm_node_t *right = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17378 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
17382 case PM_CASE_PRIMITIVE: {
17383 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
17386 if (pm_symbol_node_label_p(node))
return node;
17395 switch (parser->
current.type) {
17396 case PM_CASE_PRIMITIVE: {
17397 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17398 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, right);
17401 return (
pm_node_t *) pm_range_node_create(parser, node, &
operator, NULL);
17408 parser_lex(parser);
17413 switch (parser->
current.type) {
17415 parser_lex(parser);
17418 if (variable == NULL) {
17419 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
17420 variable = (
pm_node_t *) pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0);
17423 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17426 parser_lex(parser);
17429 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17432 parser_lex(parser);
17435 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17438 parser_lex(parser);
17441 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17444 parser_lex(parser);
17447 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17450 parser_lex(parser);
17453 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17460 parser_lex(parser);
17462 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17467 return (
pm_node_t *) pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous);
17472 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17473 pm_node_t *variable = (
pm_node_t *) pm_missing_node_create(parser,
operator.start,
operator.end);
17474 return (
pm_node_t *) pm_pinned_variable_node_create(parser, &
operator, variable);
17480 parser_lex(parser);
17485 return parse_pattern_constant_path(parser, captures, (
pm_node_t *) node, (uint16_t) (depth + 1));
17489 parser_lex(parser);
17492 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17495 pm_parser_err_current(parser, diag_id);
17511 switch (parser->
current.type) {
17520 case PM_CASE_PRIMITIVE: {
17521 if (node == NULL) {
17522 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17524 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17525 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17533 parser_lex(parser);
17535 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17540 if (node == NULL) {
17543 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17549 pm_parser_err_current(parser, diag_id);
17552 if (node == NULL) {
17555 node = (
pm_node_t *) pm_alternation_pattern_node_create(parser, node, right, &
operator);
17572 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17576 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
17579 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
17581 (uint32_t) (depth == -1 ? 0 : depth)
17584 node = (
pm_node_t *) pm_capture_pattern_node_create(parser, node, target, &
operator);
17597 bool leading_rest =
false;
17598 bool trailing_rest =
false;
17600 switch (parser->
current.type) {
17602 parser_lex(parser);
17604 node = (
pm_node_t *) parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1));
17606 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17607 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17613 node = parse_pattern_keyword_rest(parser, captures);
17614 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17616 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17617 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17625 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17627 if (pm_symbol_node_label_p(node)) {
17628 node = (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17630 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17631 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17637 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17641 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17642 parser_lex(parser);
17643 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17644 leading_rest =
true;
17650 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17656 if (pm_symbol_node_label_p(node)) {
17657 return (
pm_node_t *) parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1));
17660 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser,
PM_TOKEN_COMMA)) {
17665 pm_node_list_append(&nodes, node);
17672 pm_node_list_append(&nodes, node);
17673 trailing_rest =
true;
17678 node = (
pm_node_t *) parse_pattern_rest(parser, captures);
17683 if (trailing_rest) {
17684 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17687 trailing_rest =
true;
17689 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17692 pm_node_list_append(&nodes, node);
17700 node = (
pm_node_t *) pm_find_pattern_node_create(parser, &nodes);
17702 if (nodes.
size == 2) {
17703 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17706 node = (
pm_node_t *) pm_array_pattern_node_node_list_create(parser, &nodes);
17708 if (leading_rest && trailing_rest) {
17709 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17714 }
else if (leading_rest) {
17717 node = (
pm_node_t *) pm_array_pattern_node_rest_create(parser, node);
17729parse_negative_numeric(
pm_node_t *node) {
17754 assert(
false &&
"unreachable");
17767 case PM_ERR_HASH_KEY: {
17771 case PM_ERR_HASH_VALUE:
17772 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17776 case PM_ERR_UNARY_RECEIVER: {
17781 case PM_ERR_UNARY_DISALLOWED:
17782 case PM_ERR_EXPECT_ARGUMENT: {
17787 pm_parser_err_previous(parser, diag_id);
17797#define CONTEXT_NONE 0
17798#define CONTEXT_THROUGH_ENSURE 1
17799#define CONTEXT_THROUGH_ELSE 2
17802 int context = CONTEXT_NONE;
17804 while (context_node != NULL) {
17805 switch (context_node->
context) {
17826 if (context == CONTEXT_NONE) {
17827 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17828 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17829 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17830 }
else if (context == CONTEXT_THROUGH_ELSE) {
17831 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17843 context = CONTEXT_THROUGH_ELSE;
17854 context = CONTEXT_THROUGH_ENSURE;
17858 assert(
false &&
"unreachable");
17888 context_node = context_node->
prev;
17892#undef CONTEXT_ENSURE
17903 while (context_node != NULL) {
17904 switch (context_node->
context) {
17929 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17933 assert(
false &&
"unreachable");
17974 context_node = context_node->
prev;
18006parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
18010 if (callback_data->
shared) {
18016 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
18029 .shared = unescaped->
type == PM_STRING_SHARED
18039parse_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) {
18040 switch (parser->
current.type) {
18042 parser_lex(parser);
18045 pm_accepts_block_stack_push(parser,
true);
18046 bool parsed_bare_hash =
false;
18062 if (accepted_newline) {
18063 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
18088 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
18090 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18093 element = (
pm_node_t *) pm_splat_node_create(parser, &
operator, expression);
18095 if (parsed_bare_hash) {
18096 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
18099 element = (
pm_node_t *) pm_keyword_hash_node_create(parser);
18103 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18106 pm_static_literals_free(&hash_keys);
18107 parsed_bare_hash =
true;
18109 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
18112 if (parsed_bare_hash) {
18113 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
18118 pm_hash_key_static_literals_add(parser, &hash_keys, element);
18124 operator = not_provided(parser);
18127 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
18128 pm_node_t *assoc = (
pm_node_t *) pm_assoc_node_create(parser, element, &
operator, value);
18129 pm_keyword_hash_node_elements_append(hash, assoc);
18133 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
18136 pm_static_literals_free(&hash_keys);
18137 parsed_bare_hash =
true;
18141 pm_array_node_elements_append(array, element);
18153 pm_array_node_close_set(array, &parser->
previous);
18154 pm_accepts_block_stack_pop(parser);
18163 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18165 parser_lex(parser);
18173 pop_block_exits(parser, previous_block_exits);
18174 pm_node_list_free(¤t_block_exits);
18176 return (
pm_node_t *) pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous);
18181 pm_accepts_block_stack_push(parser,
true);
18183 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18184 context_pop(parser);
18190 if (terminator_found) {
18199 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18202 parser_lex(parser);
18203 pm_accepts_block_stack_pop(parser);
18205 pop_block_exits(parser, previous_block_exits);
18206 pm_node_list_free(¤t_block_exits);
18217 multi_target = pm_multi_target_node_create(parser);
18218 pm_multi_target_node_targets_append(parser, multi_target, statement);
18221 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18230 if (match1(parser,
PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18231 result = parse_targets(parser, (
pm_node_t *) multi_target, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18243 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18246 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18251 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18261 pm_statements_node_body_append(parser, statements, statement,
true);
18271 pm_statements_node_body_append(parser, statements, statement,
true);
18275 if (!terminator_found && !match1(parser,
PM_TOKEN_EOF)) {
18281 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18282 pm_statements_node_body_append(parser, statements, node,
true);
18311 context_pop(parser);
18312 pm_accepts_block_stack_pop(parser);
18324 pm_multi_target_node_targets_append(parser, multi_target, statement);
18326 statement = (
pm_node_t *) multi_target;
18338 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
18342 pop_block_exits(parser, previous_block_exits);
18343 pm_node_list_free(¤t_block_exits);
18345 pm_void_statements_check(parser, statements,
true);
18359 pm_accepts_block_stack_push(parser,
true);
18360 parser_lex(parser);
18365 if (current_hash_keys != NULL) {
18366 parse_assocs(parser, current_hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18369 parse_assocs(parser, &hash_keys, (
pm_node_t *) node, (uint16_t) (depth + 1));
18370 pm_static_literals_free(&hash_keys);
18376 pm_accepts_block_stack_pop(parser);
18378 pm_hash_node_closing_loc_set(node, &parser->
previous);
18383 parser_lex(parser);
18394 pm_node_t *node = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &content, &closing);
18395 pm_node_flag_set(node, parse_unescaped_encoding(parser));
18400 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18406 parser_lex(parser);
18409 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18410 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18416 parser_lex(parser);
18428 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18429 return (
pm_node_t *) pm_call_node_fcall_create(parser, &constant, &arguments);
18434 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18437 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18443 parser_lex(parser);
18449 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18450 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18458 parser_lex(parser);
18460 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));
18467 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
18470 return (
pm_node_t *) pm_range_node_create(parser, NULL, &
operator, right);
18473 parser_lex(parser);
18476 parser_lex(parser);
18477 return (
pm_node_t *) pm_float_node_imaginary_create(parser, &parser->
previous);
18479 parser_lex(parser);
18482 parser_lex(parser);
18483 return (
pm_node_t *) pm_float_node_rational_imaginary_create(parser, &parser->
previous);
18485 parser_lex(parser);
18488 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18489 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18495 parser_lex(parser);
18498 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18499 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18505 parser_lex(parser);
18508 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18509 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18516 parser_lex(parser);
18518 pm_node_t *node = parse_variable_call(parser);
18528 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
18538 if (arguments.
block != NULL) {
18560 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18561 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
18567 parse_target_implicit_parameter(parser, node);
18575 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18576 parse_target_implicit_parameter(parser, node);
18579 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
18583 pm_node_destroy(parser, node);
18588 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser,
PM_TOKEN_COMMA)) {
18589 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18600 size_t common_whitespace = (size_t) -1;
18603 parser_lex(parser);
18615 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18622 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18635 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18638 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18642 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18647 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18648 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18658 pm_node_list_append(&parts, part);
18661 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18662 pm_node_list_append(&parts, part);
18668 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18670 cast->
parts = parts;
18673 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18679 pm_node_list_free(&parts);
18682 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18690 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18692 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18698 parse_heredoc_dedent(parser, nodes, common_whitespace);
18703 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18709 parser_lex(parser);
18712 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
18713 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18720 parser_lex(parser);
18725 parser_lex(parser);
18726 return (
pm_node_t *) pm_integer_node_imaginary_create(parser, base, &parser->
previous);
18730 parser_lex(parser);
18731 return (
pm_node_t *) pm_integer_node_rational_create(parser, base, &parser->
previous);
18735 parser_lex(parser);
18736 return (
pm_node_t *) pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous);
18739 parser_lex(parser);
18740 return (
pm_node_t *) pm_source_encoding_node_create(parser, &parser->
previous);
18742 parser_lex(parser);
18745 parser_lex(parser);
18748 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18749 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18752 parser_lex(parser);
18755 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18756 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18764 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18767 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18770 return (
pm_node_t *) pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name);
18775 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18780 return (
pm_node_t *) pm_alias_method_node_create(parser, &keyword, new_name, old_name);
18784 size_t opening_newline_index = token_newline_index(parser);
18785 parser_lex(parser);
18791 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18798 }
else if (!token_begins_expression_p(parser->
current.type)) {
18801 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18806 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18807 parser_lex(parser);
18809 pop_block_exits(parser, previous_block_exits);
18810 pm_node_list_free(¤t_block_exits);
18812 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18813 return (
pm_node_t *) pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous);
18818 pm_token_t end_keyword = not_provided(parser);
18822 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18829 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18830 parser_lex(parser);
18833 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18838 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18840 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18841 pm_when_node_conditions_append(when_node, (
pm_node_t *) splat_node);
18845 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18846 pm_when_node_conditions_append(when_node, condition);
18857 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18860 pm_when_clause_static_literals_add(parser, &literals, condition);
18866 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18870 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18875 if (statements != NULL) {
18876 pm_when_node_statements_set(when_node, statements);
18880 pm_case_node_condition_append(case_node, (
pm_node_t *) when_node);
18886 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18889 pm_static_literals_free(&literals);
18892 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18896 if (predicate == NULL) {
18897 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18904 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18909 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18911 parser_lex(parser);
18916 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));
18919 pm_constant_id_list_free(&captures);
18926 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18927 pattern = (
pm_node_t *) pm_if_node_modifier_create(parser, pattern, &keyword, predicate);
18930 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18931 pattern = (
pm_node_t *) pm_unless_node_modifier_create(parser, pattern, &keyword, predicate);
18942 then_keyword = not_provided(parser);
18960 pm_node_t *condition = (
pm_node_t *) pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword);
18961 pm_case_match_node_condition_append(case_node, condition);
18967 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18979 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18981 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18985 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18991 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
19000 pop_block_exits(parser, previous_block_exits);
19001 pm_node_list_free(¤t_block_exits);
19006 size_t opening_newline_index = token_newline_index(parser);
19007 parser_lex(parser);
19013 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19017 pm_accepts_block_stack_push(parser,
true);
19018 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19019 pm_accepts_block_stack_pop(parser);
19023 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19024 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19028 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
19030 pop_block_exits(parser, previous_block_exits);
19031 pm_node_list_free(¤t_block_exits);
19037 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19039 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19040 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19043 parser_lex(parser);
19053 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19056 flush_block_exits(parser, previous_block_exits);
19057 pm_node_list_free(¤t_block_exits);
19059 return (
pm_node_t *) pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19064 parser_lex(parser);
19070 token_begins_expression_p(parser->
current.type) ||
19073 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].left;
19075 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19076 parse_arguments(parser, &arguments,
false,
PM_TOKEN_EOF, (uint16_t) (depth + 1));
19080 switch (keyword.
type) {
19093 parse_return(parser, node);
19097 assert(
false &&
"unreachable");
19102 parser_lex(parser);
19106 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
19113 return (
pm_node_t *) pm_forwarding_super_node_create(parser, &keyword, &arguments);
19116 return (
pm_node_t *) pm_super_node_create(parser, &keyword, &arguments);
19119 parser_lex(parser);
19123 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
19129 if (arguments.
block != NULL) {
19130 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19131 pm_node_destroy(parser, arguments.
block);
19132 arguments.
block = NULL;
19141 size_t opening_newline_index = token_newline_index(parser);
19142 parser_lex(parser);
19145 pm_do_loop_stack_push(parser,
false);
19148 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19152 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));
19154 pm_parser_scope_push(parser,
true);
19161 pm_accepts_block_stack_push(parser,
true);
19163 pm_accepts_block_stack_pop(parser);
19168 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));
19170 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19178 pm_parser_scope_pop(parser);
19179 pm_do_loop_stack_pop(parser);
19181 flush_block_exits(parser, previous_block_exits);
19182 pm_node_list_free(¤t_block_exits);
19184 return (
pm_node_t *) pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous);
19187 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
19190 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
19197 inheritance_operator = parser->
current;
19198 lex_state_set(parser, PM_LEX_STATE_BEG);
19201 parser_lex(parser);
19203 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
19205 inheritance_operator = not_provided(parser);
19209 pm_parser_scope_push(parser,
true);
19219 pm_accepts_block_stack_push(parser,
true);
19221 pm_accepts_block_stack_pop(parser);
19226 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));
19228 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
19233 if (context_def_p(parser)) {
19234 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
19240 pm_parser_scope_pop(parser);
19241 pm_do_loop_stack_pop(parser);
19244 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
19247 pop_block_exits(parser, previous_block_exits);
19248 pm_node_list_free(¤t_block_exits);
19250 return (
pm_node_t *) pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous);
19254 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19257 size_t opening_newline_index = token_newline_index(parser);
19267 parser_lex(parser);
19271 bool valid_name =
true;
19273 switch (parser->
current.type) {
19274 case PM_CASE_OPERATOR:
19275 pm_parser_scope_push(parser,
true);
19276 lex_state_set(parser, PM_LEX_STATE_ENDFN);
19277 parser_lex(parser);
19282 parser_lex(parser);
19285 receiver = parse_variable_call(parser);
19287 pm_parser_scope_push(parser,
true);
19288 lex_state_set(parser, PM_LEX_STATE_FNAME);
19289 parser_lex(parser);
19292 name = parse_method_definition_name(parser);
19295 pm_parser_scope_push(parser,
true);
19305 valid_name =
false;
19315 pm_parser_scope_push(parser,
true);
19316 parser_lex(parser);
19321 lex_state_set(parser, PM_LEX_STATE_FNAME);
19322 parser_lex(parser);
19325 switch (identifier.
type) {
19327 receiver = (
pm_node_t *) pm_constant_read_node_create(parser, &identifier);
19330 receiver = (
pm_node_t *) pm_instance_variable_read_node_create(parser, &identifier);
19333 receiver = (
pm_node_t *) pm_class_variable_read_node_create(parser, &identifier);
19336 receiver = (
pm_node_t *) pm_global_variable_read_node_create(parser, &identifier);
19339 receiver = (
pm_node_t *) pm_nil_node_create(parser, &identifier);
19342 receiver = (
pm_node_t *) pm_self_node_create(parser, &identifier);
19345 receiver = (
pm_node_t *) pm_true_node_create(parser, &identifier);
19348 receiver = (
pm_node_t *) pm_false_node_create(parser, &identifier);
19351 receiver = (
pm_node_t *) pm_source_file_node_create(parser, &identifier);
19354 receiver = (
pm_node_t *) pm_source_line_node_create(parser, &identifier);
19357 receiver = (
pm_node_t *) pm_source_encoding_node_create(parser, &identifier);
19363 name = parse_method_definition_name(parser);
19378 context_pop(parser);
19379 parser_lex(parser);
19382 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
19388 lex_state_set(parser, PM_LEX_STATE_FNAME);
19392 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, expression, &rparen);
19396 pm_parser_scope_push(parser,
true);
19398 name = parse_method_definition_name(parser);
19402 pm_parser_scope_push(parser,
true);
19403 name = parse_method_definition_name(parser);
19411 switch (parser->
current.type) {
19413 parser_lex(parser);
19419 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
19422 lex_state_set(parser, PM_LEX_STATE_BEG);
19425 context_pop(parser);
19435 case PM_CASE_PARAMETER: {
19439 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
19442 lparen = not_provided(parser);
19443 rparen = not_provided(parser);
19444 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
19446 context_pop(parser);
19450 lparen = not_provided(parser);
19451 rparen = not_provided(parser);
19454 context_pop(parser);
19464 if (token_is_setter_name(&name)) {
19465 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
19470 pm_do_loop_stack_push(parser,
false);
19471 statements = (
pm_node_t *) pm_statements_node_create(parser);
19473 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));
19480 context_pop(parser);
19482 statement = (
pm_node_t *) pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value);
19485 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19486 pm_do_loop_stack_pop(parser);
19487 context_pop(parser);
19488 end_keyword = not_provided(parser);
19490 equal = not_provided(parser);
19493 lex_state_set(parser, PM_LEX_STATE_BEG);
19500 pm_accepts_block_stack_push(parser,
true);
19501 pm_do_loop_stack_push(parser,
false);
19504 pm_accepts_block_stack_push(parser,
true);
19506 pm_accepts_block_stack_pop(parser);
19511 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));
19513 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19516 pm_accepts_block_stack_pop(parser);
19517 pm_do_loop_stack_pop(parser);
19525 pm_parser_scope_pop(parser);
19532 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.start, parse_operator_symbol_name(&name));
19534 flush_block_exits(parser, previous_block_exits);
19535 pm_node_list_free(¤t_block_exits);
19537 return (
pm_node_t *) pm_def_node_create(
19554 parser_lex(parser);
19564 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19567 rparen = not_provided(parser);
19574 lparen = not_provided(parser);
19575 rparen = not_provided(parser);
19576 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19579 context_pop(parser);
19580 return (
pm_node_t *) pm_defined_node_create(
19585 &PM_LOCATION_TOKEN_VALUE(&keyword)
19589 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19590 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19593 parser_lex(parser);
19596 if (context_def_p(parser)) {
19597 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19605 return (
pm_node_t *) pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous);
19608 parser_lex(parser);
19611 size_t opening_newline_index = token_newline_index(parser);
19612 parser_lex(parser);
19624 if (token_begins_expression_p(parser->
current.type)) {
19625 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19628 index = (
pm_node_t *) pm_splat_node_create(parser, &star_operator, name);
19629 }
else if (token_begins_expression_p(parser->
current.type)) {
19630 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19632 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19633 index = (
pm_node_t *) pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end);
19638 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19640 index = parse_target(parser, index,
false,
false);
19643 context_pop(parser);
19644 pm_do_loop_stack_push(parser,
true);
19649 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19650 pm_do_loop_stack_pop(parser);
19656 do_keyword = not_provided(parser);
19664 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19667 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19670 return (
pm_node_t *) pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous);
19673 if (parser_end_of_line_p(parser)) {
19674 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19677 size_t opening_newline_index = token_newline_index(parser);
19679 parser_lex(parser);
19681 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19683 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19684 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19687 parser_lex(parser);
19689 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19692 pm_node_destroy(parser, name);
19694 pm_undef_node_append(undef, name);
19697 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19698 parser_lex(parser);
19699 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19702 pm_node_destroy(parser, name);
19706 pm_undef_node_append(undef, name);
19713 parser_lex(parser);
19725 receiver = (
pm_node_t *) pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous);
19727 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19728 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19737 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19740 return (
pm_node_t *) pm_call_node_not_create(parser, receiver, &message, &arguments);
19743 size_t opening_newline_index = token_newline_index(parser);
19744 parser_lex(parser);
19746 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19750 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19752 size_t opening_newline_index = token_newline_index(parser);
19753 parser_lex(parser);
19756 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19762 pop_block_exits(parser, previous_block_exits);
19763 pm_node_list_free(¤t_block_exits);
19766 return (
pm_node_t *) pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing);
19773 constant_path = (
pm_node_t *) pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous);
19781 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19784 pm_parser_scope_push(parser,
true);
19789 pm_accepts_block_stack_push(parser,
true);
19791 pm_accepts_block_stack_pop(parser);
19796 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));
19798 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19804 pm_parser_scope_pop(parser);
19807 if (context_def_p(parser)) {
19808 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19811 pop_block_exits(parser, previous_block_exits);
19812 pm_node_list_free(¤t_block_exits);
19814 return (
pm_node_t *) pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous);
19817 parser_lex(parser);
19820 parser_lex(parser);
19828 parser_lex(parser);
19831 parse_retry(parser, node);
19836 parser_lex(parser);
19839 parser_lex(parser);
19842 size_t opening_newline_index = token_newline_index(parser);
19845 pm_do_loop_stack_push(parser,
true);
19847 parser_lex(parser);
19849 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19851 pm_do_loop_stack_pop(parser);
19852 context_pop(parser);
19858 do_keyword = not_provided(parser);
19864 pm_accepts_block_stack_push(parser,
true);
19865 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19866 pm_accepts_block_stack_pop(parser);
19870 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19873 return (
pm_node_t *) pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19876 size_t opening_newline_index = token_newline_index(parser);
19879 pm_do_loop_stack_push(parser,
true);
19881 parser_lex(parser);
19883 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19885 pm_do_loop_stack_pop(parser);
19886 context_pop(parser);
19892 do_keyword = not_provided(parser);
19898 pm_accepts_block_stack_push(parser,
true);
19899 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19900 pm_accepts_block_stack_pop(parser);
19904 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19907 return (
pm_node_t *) pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0);
19910 parser_lex(parser);
19921 pm_array_node_elements_append(array, (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19929 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19934 pm_array_node_close_set(array, &closing);
19939 parser_lex(parser);
19948 switch (parser->
current.type) {
19950 if (current == NULL) {
19956 pm_array_node_elements_append(array, current);
19960 parser_lex(parser);
19967 if (current == NULL) {
19971 current = (
pm_node_t *) pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing);
19972 parser_lex(parser);
19978 parser_lex(parser);
19990 pm_node_t *second_string = (
pm_node_t *) pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing);
19991 parser_lex(parser);
19994 pm_interpolated_symbol_node_append(interpolated, first_string);
19995 pm_interpolated_symbol_node_append(interpolated, second_string);
20000 assert(
false &&
"unreachable");
20006 bool start_location_set =
false;
20007 if (current == NULL) {
20013 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20023 pm_interpolated_symbol_node_append(interpolated, current);
20025 start_location_set =
true;
20032 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20034 if (!start_location_set) {
20040 bool start_location_set =
false;
20041 if (current == NULL) {
20047 current = (
pm_node_t *) pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
20058 pm_interpolated_symbol_node_append(interpolated, current);
20060 start_location_set =
true;
20066 assert(
false &&
"unreachable");
20069 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20071 if (!start_location_set) {
20078 parser_lex(parser);
20085 pm_array_node_elements_append(array, current);
20090 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20095 pm_array_node_close_set(array, &closing);
20100 parser_lex(parser);
20116 pm_array_node_elements_append(array,
string);
20124 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20130 pm_array_node_close_set(array, &closing);
20134 parser_lex(parser);
20143 switch (parser->
current.type) {
20149 if (current == NULL) {
20156 pm_array_node_elements_append(array, current);
20160 parser_lex(parser);
20168 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
20169 parser_lex(parser);
20171 if (current == NULL) {
20188 pm_interpolated_string_node_append(interpolated, current);
20189 pm_interpolated_string_node_append(interpolated,
string);
20192 assert(
false &&
"unreachable");
20198 if (current == NULL) {
20205 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20214 pm_interpolated_string_node_append(interpolated, current);
20222 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20227 if (current == NULL) {
20234 current = (
pm_node_t *) pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
20243 pm_interpolated_string_node_append(interpolated, current);
20250 assert(
false &&
"unreachable");
20253 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20259 parser_lex(parser);
20266 pm_array_node_elements_append(array, current);
20271 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20277 pm_array_node_close_set(array, &closing);
20282 parser_lex(parser);
20294 parser_lex(parser);
20312 parser_lex(parser);
20325 parse_regular_expression_errors(parser, node);
20328 pm_node_flag_set((
pm_node_t *) node, parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, node->base.
flags));
20334 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20347 pm_interpolated_regular_expression_node_append(interpolated, part);
20352 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20359 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20360 pm_interpolated_regular_expression_node_append(interpolated, part);
20366 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20372 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20377 parser_lex(parser);
20394 parser_lex(parser);
20395 return (
pm_node_t *) pm_xstring_node_create(parser, &opening, &content, &parser->
previous);
20407 parser_lex(parser);
20410 pm_node_t *node = (
pm_node_t *) pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped);
20411 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20412 parser_lex(parser);
20418 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20424 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20426 pm_interpolated_xstring_node_append(node, part);
20431 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20436 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20437 pm_interpolated_xstring_node_append(node, part);
20443 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20448 pm_interpolated_xstring_node_closing_set(node, &closing);
20453 parser_lex(parser);
20458 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20459 pm_parser_err_prefix(parser, diag_id);
20466 if (token_begins_expression_p(parser->
current.type)) {
20467 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20473 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20475 return parse_target_validate(parser, splat,
true);
20479 if (binding_power > PM_BINDING_POWER_UNARY) {
20480 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20483 parser_lex(parser);
20486 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));
20487 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20489 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20493 if (binding_power > PM_BINDING_POWER_UNARY) {
20494 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20496 parser_lex(parser);
20499 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20500 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20505 if (binding_power > PM_BINDING_POWER_UNARY) {
20506 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20508 parser_lex(parser);
20511 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20512 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20517 parser_lex(parser);
20520 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20524 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20525 node = (
pm_node_t *) pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0);
20526 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20533 parse_negative_numeric(node);
20536 node = (
pm_node_t *) pm_call_node_unary_create(parser, &
operator, node,
"-@");
20547 size_t opening_newline_index = token_newline_index(parser);
20548 pm_accepts_block_stack_push(parser,
true);
20549 parser_lex(parser);
20552 pm_parser_scope_push(parser,
false);
20556 switch (parser->
current.type) {
20559 parser_lex(parser);
20562 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20564 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20570 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20573 case PM_CASE_PARAMETER: {
20574 pm_accepts_block_stack_push(parser,
false);
20576 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20577 pm_accepts_block_stack_pop(parser);
20581 block_parameters = NULL;
20597 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20604 pm_accepts_block_stack_push(parser,
true);
20606 pm_accepts_block_stack_pop(parser);
20611 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));
20613 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20620 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20623 pm_parser_scope_pop(parser);
20624 pm_accepts_block_stack_pop(parser);
20626 return (
pm_node_t *) pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body);
20629 if (binding_power > PM_BINDING_POWER_UNARY) {
20630 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20632 parser_lex(parser);
20635 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20636 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20641 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20644 parser_lex(parser);
20646 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20657 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20658 pm_parser_err_prefix(parser, diag_id);
20664 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20665 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20671 pm_parser_err_prefix(parser, diag_id);
20689parse_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) {
20690 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));
20698 parser_lex(parser);
20701 context_pop(parser);
20703 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20723 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20728 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20736 parse_assignment_value_local(parser, statement);
20758parse_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) {
20759 bool permitted =
true;
20760 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_USTAR)) permitted =
false;
20762 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));
20763 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20765 parse_assignment_value_local(parser, value);
20766 bool single_value =
true;
20769 single_value =
false;
20774 pm_array_node_elements_append(array, value);
20778 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20780 pm_array_node_elements_append(array, element);
20783 parse_assignment_value_local(parser, element);
20793 parser_lex(parser);
20795 bool accepts_command_call_inner =
false;
20802 accepts_command_call_inner =
true;
20807 context_pop(parser);
20809 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, value, &rescue, right);
20825 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20830 if (call_node->
block != NULL) {
20831 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20833 call_node->
block = NULL;
20867parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20874 const uint8_t *source = pm_string_source(capture);
20875 size_t length = pm_string_length(capture);
20882 if (!pm_slice_is_valid_local(parser, source, source + length))
return;
20884 if (callback_data->
shared) {
20887 location = (
pm_location_t) { .start = source, .end = source + length };
20888 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20894 void *memory =
xmalloc(length);
20895 if (memory == NULL) abort();
20897 memcpy(memory, source, length);
20898 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20903 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20904 pm_constant_id_list_append(names, name);
20907 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20910 if (pm_local_is_keyword((
const char *) source, length))
return;
20914 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20919 if (callback_data->
match == NULL) {
20920 callback_data->
match = pm_match_write_node_create(parser, call);
20925 pm_node_t *target = (
pm_node_t *) pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth);
20926 pm_node_list_append(&callback_data->
match->
targets, target);
20940 .shared = content->
type == PM_STRING_SHARED
20947 .shared = content->
type == PM_STRING_SHARED
20950 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);
20951 pm_constant_id_list_free(&callback_data.
names);
20953 if (callback_data.
match != NULL) {
20961parse_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) {
20964 switch (token.type) {
20978 case PM_CASE_WRITABLE: {
20979 parser_lex(parser);
20980 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));
20983 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20986 return parse_write(parser, node, &token, value);
20990 pm_multi_target_node_targets_append(parser, multi_target, node);
20992 parser_lex(parser);
20993 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));
20994 return parse_write(parser, (
pm_node_t *) multi_target, &token, value);
21005 parser_lex(parser);
21006 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));
21007 return parse_unwriteable_write(parser, node, &token, value);
21013 parser_lex(parser);
21014 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21022 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21025 parser_lex(parser);
21027 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21028 pm_node_t *result = (
pm_node_t *) pm_global_variable_and_write_node_create(parser, node, &token, value);
21030 pm_node_destroy(parser, node);
21034 parser_lex(parser);
21036 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));
21039 pm_node_destroy(parser, node);
21043 parser_lex(parser);
21045 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));
21048 return parse_shareable_constant_write(parser, write);
21051 parser_lex(parser);
21053 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));
21056 pm_node_destroy(parser, node);
21057 return parse_shareable_constant_write(parser, write);
21060 parser_lex(parser);
21062 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21065 pm_node_destroy(parser, node);
21070 parser_lex(parser);
21072 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));
21073 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0);
21075 parse_target_implicit_parameter(parser, node);
21076 pm_node_destroy(parser, node);
21082 parse_target_implicit_parameter(parser, node);
21086 parser_lex(parser);
21088 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));
21091 pm_node_destroy(parser, node);
21102 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21105 parser_lex(parser);
21107 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21108 pm_node_t *result = (
pm_node_t *) pm_local_variable_and_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21110 pm_node_destroy(parser, (
pm_node_t *) cast);
21116 parser_lex(parser);
21122 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));
21123 return (
pm_node_t *) pm_index_and_write_node_create(parser, cast, &token, value);
21127 if (pm_call_node_writable_p(parser, cast)) {
21128 parse_write_name(parser, &cast->name);
21130 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21133 parse_call_operator_write(parser, cast, &token);
21134 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));
21135 return (
pm_node_t *) pm_call_and_write_node_create(parser, cast, &token, value);
21138 parser_lex(parser);
21139 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21143 parser_lex(parser);
21148 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21156 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21159 parser_lex(parser);
21161 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21162 pm_node_t *result = (
pm_node_t *) pm_global_variable_or_write_node_create(parser, node, &token, value);
21164 pm_node_destroy(parser, node);
21168 parser_lex(parser);
21170 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21173 pm_node_destroy(parser, node);
21177 parser_lex(parser);
21179 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));
21182 return parse_shareable_constant_write(parser, write);
21185 parser_lex(parser);
21187 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));
21190 pm_node_destroy(parser, node);
21191 return parse_shareable_constant_write(parser, write);
21194 parser_lex(parser);
21196 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));
21199 pm_node_destroy(parser, node);
21204 parser_lex(parser);
21206 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21207 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0);
21209 parse_target_implicit_parameter(parser, node);
21210 pm_node_destroy(parser, node);
21216 parse_target_implicit_parameter(parser, node);
21220 parser_lex(parser);
21222 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));
21225 pm_node_destroy(parser, node);
21236 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21239 parser_lex(parser);
21241 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21242 pm_node_t *result = (
pm_node_t *) pm_local_variable_or_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21244 pm_node_destroy(parser, (
pm_node_t *) cast);
21250 parser_lex(parser);
21256 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));
21257 return (
pm_node_t *) pm_index_or_write_node_create(parser, cast, &token, value);
21261 if (pm_call_node_writable_p(parser, cast)) {
21262 parse_write_name(parser, &cast->name);
21264 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21267 parse_call_operator_write(parser, cast, &token);
21268 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));
21269 return (
pm_node_t *) pm_call_or_write_node_create(parser, cast, &token, value);
21272 parser_lex(parser);
21273 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21277 parser_lex(parser);
21282 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21300 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21303 parser_lex(parser);
21305 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));
21306 pm_node_t *result = (
pm_node_t *) pm_global_variable_operator_write_node_create(parser, node, &token, value);
21308 pm_node_destroy(parser, node);
21312 parser_lex(parser);
21314 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21317 pm_node_destroy(parser, node);
21321 parser_lex(parser);
21323 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21326 return parse_shareable_constant_write(parser, write);
21329 parser_lex(parser);
21331 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));
21334 pm_node_destroy(parser, node);
21335 return parse_shareable_constant_write(parser, write);
21338 parser_lex(parser);
21340 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21343 pm_node_destroy(parser, node);
21348 parser_lex(parser);
21350 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));
21351 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0);
21353 parse_target_implicit_parameter(parser, node);
21354 pm_node_destroy(parser, node);
21360 parse_target_implicit_parameter(parser, node);
21364 parser_lex(parser);
21366 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));
21367 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth);
21369 pm_node_destroy(parser, node);
21373 parser_lex(parser);
21381 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21384 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));
21385 pm_node_t *result = (
pm_node_t *) pm_local_variable_operator_write_node_create(parser, (
pm_node_t *) cast, &token, value, constant_id, 0);
21387 pm_node_destroy(parser, (
pm_node_t *) cast);
21395 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));
21396 return (
pm_node_t *) pm_index_operator_write_node_create(parser, cast, &token, value);
21400 if (pm_call_node_writable_p(parser, cast)) {
21401 parse_write_name(parser, &cast->name);
21403 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21406 parse_call_operator_write(parser, cast, &token);
21407 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));
21408 return (
pm_node_t *) pm_call_operator_write_node_create(parser, cast, &token, value);
21411 parser_lex(parser);
21412 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21416 parser_lex(parser);
21427 parser_lex(parser);
21430 return (
pm_node_t *) pm_and_node_create(parser, node, &token, right);
21434 parser_lex(parser);
21437 return (
pm_node_t *) pm_or_node_create(parser, node, &token, right);
21447 parser_lex(parser);
21448 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21451 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21464 bool interpolated =
false;
21465 size_t total_length = 0;
21470 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21472 interpolated =
true;
21477 if (!interpolated && total_length > 0) {
21478 void *memory =
xmalloc(total_length);
21479 if (!memory) abort();
21481 uint8_t *cursor = memory;
21484 size_t length = pm_string_length(unescaped);
21486 memcpy(cursor, pm_string_source(unescaped), length);
21491 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21494 pm_string_free(&owned);
21526 parser_lex(parser);
21532 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21539 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21546 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21554 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21555 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, 0);
21562 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21565 parser_lex(parser);
21566 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21567 return (
pm_node_t *) pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON);
21571 parser_lex(parser);
21577 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21578 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &
operator, &arguments);
21585 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21592 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21599 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21609 switch (parser->
current.type) {
21610 case PM_CASE_OPERATOR:
21611 case PM_CASE_KEYWORD:
21615 parser_lex(parser);
21625 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21626 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21629 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21634 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21641 parser_lex(parser);
21644 if (token_begins_expression_p(parser->
current.type)) {
21645 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21648 return (
pm_node_t *) pm_range_node_create(parser, node, &token, right);
21652 parser_lex(parser);
21654 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21655 return (
pm_node_t *) pm_if_node_modifier_create(parser, node, &keyword, predicate);
21659 parser_lex(parser);
21661 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21662 return (
pm_node_t *) pm_unless_node_modifier_create(parser, node, &keyword, predicate);
21665 parser_lex(parser);
21667 pm_statements_node_body_append(parser, statements, node,
true);
21669 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21673 parser_lex(parser);
21675 pm_statements_node_body_append(parser, statements, node,
true);
21677 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21683 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21686 parser_lex(parser);
21688 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21700 context_pop(parser);
21701 pop_block_exits(parser, previous_block_exits);
21702 pm_node_list_free(¤t_block_exits);
21704 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21711 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21713 context_pop(parser);
21714 pop_block_exits(parser, previous_block_exits);
21715 pm_node_list_free(¤t_block_exits);
21717 return (
pm_node_t *) pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21720 parser_lex(parser);
21723 switch (parser->
current.type) {
21725 parser_lex(parser);
21741 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21742 path = (
pm_node_t *) pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21745 path = (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21749 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21750 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21755 case PM_CASE_OPERATOR:
21756 case PM_CASE_KEYWORD:
21759 parser_lex(parser);
21765 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21766 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21769 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21770 return parse_targets_validate(parser, (
pm_node_t *) call, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21779 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21781 return (
pm_node_t *) pm_call_node_shorthand_create(parser, node, &delimiter, &arguments);
21785 return (
pm_node_t *) pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous);
21791 parser_lex(parser);
21794 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21795 context_pop(parser);
21797 return (
pm_node_t *) pm_rescue_modifier_node_create(parser, node, &token, value);
21800 parser_lex(parser);
21806 pm_accepts_block_stack_push(parser,
true);
21808 pm_accepts_block_stack_pop(parser);
21816 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser,
PM_TOKEN_COMMA)) {
21817 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21818 return parse_targets_validate(parser, (
pm_node_t *) aref, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21826 block = parse_block(parser, (uint16_t) (depth + 1));
21827 pm_arguments_validate_block(parser, &arguments, block);
21829 block = parse_block(parser, (uint16_t) (depth + 1));
21832 if (block != NULL) {
21833 if (arguments.
block != NULL) {
21834 pm_parser_err_node(parser, (
pm_node_t *) block, PM_ERR_ARGUMENT_AFTER_BLOCK);
21836 arguments.
arguments = pm_arguments_node_create(parser);
21838 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21844 return (
pm_node_t *) pm_call_node_aref_create(parser, node, &arguments);
21852 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21853 parser_lex(parser);
21856 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));
21859 pm_constant_id_list_free(&captures);
21861 return (
pm_node_t *) pm_match_predicate_node_create(parser, node, pattern, &
operator);
21869 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21870 parser_lex(parser);
21873 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));
21876 pm_constant_id_list_free(&captures);
21878 return (
pm_node_t *) pm_match_required_node_create(parser, node, pattern, &
operator);
21881 assert(
false &&
"unreachable");
21886#undef PM_PARSE_PATTERN_SINGLE
21887#undef PM_PARSE_PATTERN_TOP
21888#undef PM_PARSE_PATTERN_MULTI
21912parse_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) {
21914 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21918 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21933 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21943 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21951 if (pm_symbol_node_label_p(node)) {
21964 current_token_type = parser->
current.type,
21965 current_binding_powers = pm_binding_powers[current_token_type],
21966 binding_power <= current_binding_powers.
left &&
21967 current_binding_powers.
binary
21969 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21975 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21987 if (
PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21995 if (
PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
22005 if (current_binding_powers.
nonassoc) {
22008 if (match1(parser, current_token_type)) {
22026 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
22029 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
22034 if (accepts_command_call) {
22043 switch (node->
type) {
22058 cast->
block == NULL &&
22071 accepts_command_call =
false;
22079 accepts_command_call =
false;
22094 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22095 if (statements == NULL) {
22096 statements = pm_statements_node_create(parser);
22100 pm_arguments_node_arguments_append(
22102 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2))
22105 pm_statements_node_body_append(parser, statements, (
pm_node_t *) pm_call_node_fcall_synthesized_create(
22108 pm_parser_constant_id_constant(parser,
"print", 5)
22112 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22113 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22114 if (statements == NULL) {
22115 statements = pm_statements_node_create(parser);
22119 pm_arguments_node_arguments_append(
22121 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2))
22124 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22125 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, (
pm_node_t *) receiver,
"split", arguments);
22129 pm_parser_constant_id_constant(parser,
"$F", 2),
22133 pm_statements_node_body_prepend(statements, (
pm_node_t *) write);
22137 pm_arguments_node_arguments_append(
22139 (
pm_node_t *) pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2))
22142 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22144 pm_keyword_hash_node_elements_append(keywords, (
pm_node_t *) pm_assoc_node_create(
22146 (
pm_node_t *) pm_symbol_node_synthesized_create(parser,
"chomp"),
22148 (
pm_node_t *) pm_true_node_synthesized_create(parser)
22151 pm_arguments_node_arguments_append(arguments, (
pm_node_t *) keywords);
22156 pm_statements_node_body_append(parser, wrapped_statements, (
pm_node_t *) pm_while_node_synthesized_create(
22158 (
pm_node_t *) pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4)),
22162 statements = wrapped_statements;
22177 pm_parser_scope_push(parser,
true);
22181 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22183 parser_lex(parser);
22190 assert(statements->
body.
size > 0);
22191 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22196 pm_parser_scope_pop(parser);
22201 statements = wrap_statements(parser, statements);
22203 flush_block_exits(parser, previous_block_exits);
22204 pm_node_list_free(¤t_block_exits);
22210 if (statements == NULL) {
22211 statements = pm_statements_node_create(parser);
22212 pm_statements_node_location_set(statements, parser->
start, parser->
start);
22215 return (
pm_node_t *) pm_program_node_create(parser, &locals, statements);
22232pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22233 size_t little_length = strlen(little);
22235 for (
const char *big_end = big + big_length; big < big_end; big++) {
22236 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22243#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22251pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22252 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22253 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
22264 const char *switches = pm_strnstr(engine,
" -", length);
22265 if (switches == NULL)
return;
22270 (
const uint8_t *) (switches + 1),
22271 length - ((
size_t) (switches - engine)) - 1,
22275 size_t encoding_length;
22276 if ((encoding_length = pm_string_length(&next_options.
encoding)) > 0) {
22277 const uint8_t *encoding_source = pm_string_source(&next_options.
encoding);
22278 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22290 assert(source != NULL);
22294 .lex_state = PM_LEX_STATE_BEG,
22295 .enclosure_nesting = 0,
22296 .lambda_enclosure_nesting = -1,
22297 .brace_nesting = 0,
22298 .do_loop_stack = 0,
22299 .accepts_block_stack = 0,
22302 .stack = {{ .mode = PM_LEX_DEFAULT }},
22306 .end = source + size,
22307 .previous = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22308 .current = { .type =
PM_TOKEN_EOF, .start = source, .end = source },
22309 .next_start = NULL,
22310 .heredoc_end = NULL,
22311 .data_loc = { .start = NULL, .end = NULL },
22312 .comment_list = { 0 },
22313 .magic_comment_list = { 0 },
22314 .warning_list = { 0 },
22315 .error_list = { 0 },
22316 .current_scope = NULL,
22317 .current_context = NULL,
22319 .encoding_changed_callback = NULL,
22320 .encoding_comment_start = source,
22321 .lex_callback = NULL,
22323 .constant_pool = { 0 },
22324 .newline_list = { 0 },
22328 .explicit_encoding = NULL,
22330 .parsing_eval =
false,
22331 .partial_script =
false,
22332 .command_start =
true,
22333 .recovering =
false,
22334 .encoding_locked =
false,
22335 .encoding_changed =
false,
22336 .pattern_matching_newlines =
false,
22337 .in_keyword_arg =
false,
22338 .current_block_exits = NULL,
22339 .semantic_token_seen =
false,
22341 .current_regular_expression_ascii_only =
false,
22342 .warn_mismatched_indentation =
true
22359 uint32_t constant_size = ((uint32_t) size) / 95;
22360 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22365 size_t newline_size = size / 22;
22366 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22369 if (options != NULL) {
22377 size_t encoding_length = pm_string_length(&options->
encoding);
22378 if (encoding_length > 0) {
22379 const uint8_t *encoding_source = pm_string_source(&options->
encoding);
22380 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22402 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22404 pm_parser_scope_push(parser, scope_index == 0);
22410 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22411 const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
22413 const uint8_t *source = pm_string_source(local);
22414 size_t length = pm_string_length(local);
22416 void *allocated =
xmalloc(length);
22417 if (allocated == NULL)
continue;
22419 memcpy(allocated, source, length);
22420 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22425 pm_accepts_block_stack_push(parser,
true);
22428 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22441 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22458 const uint8_t *newline = next_newline(parser->
start, parser->
end - parser->
start);
22459 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
start);
22461 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22462 const char *engine;
22464 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22465 if (newline != NULL) {
22469 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22474 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22477 search_shebang =
false;
22479 search_shebang =
true;
22485 if (search_shebang) {
22488 bool found_shebang =
false;
22492 const uint8_t *cursor = parser->
start;
22496 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22498 while (newline != NULL) {
22499 pm_newline_list_append(&parser->
newline_list, newline);
22501 cursor = newline + 1;
22502 newline = next_newline(cursor, parser->
end - cursor);
22504 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22505 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22506 const char *engine;
22507 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22508 found_shebang =
true;
22510 if (newline != NULL) {
22511 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22516 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22524 if (found_shebang) {
22528 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22555 for (node = list->
head; node != NULL; node = next) {
22567pm_magic_comment_list_free(
pm_list_t *list) {
22570 for (node = list->
head; node != NULL; node = next) {
22583 pm_string_free(&parser->
filepath);
22584 pm_diagnostic_list_free(&parser->
error_list);
22596 pm_parser_scope_pop(parser);
22600 lex_mode_pop(parser);
22609 return parse_program(parser);
22619#define LINE_SIZE 4096
22620 char line[LINE_SIZE];
22622 while (memset(line,
'\n', LINE_SIZE), fgets(line, LINE_SIZE, stream) != NULL) {
22623 size_t length = LINE_SIZE;
22624 while (length > 0 && line[length - 1] ==
'\n') length--;
22626 if (length == LINE_SIZE) {
22631 pm_buffer_append_string(buffer, line, length);
22637 pm_buffer_append_string(buffer, line, length);
22645 if (strncmp(line,
"__END__", 7) == 0)
return false;
22648 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22651 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22670pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22673 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22674 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22690 pm_buffer_init(buffer);
22692 bool eof = pm_parse_stream_read(buffer, stream, fgets);
22693 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22697 pm_node_destroy(parser, node);
22698 eof = pm_parse_stream_read(buffer, stream, fgets);
22700 pm_parser_free(parser);
22701 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22702 node = pm_parse(parser);
22712pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22714 pm_options_read(&options, data);
22717 pm_parser_init(&parser, source, size, &options);
22720 pm_node_destroy(&parser, node);
22723 pm_parser_free(&parser);
22724 pm_options_free(&options);
22729#undef PM_CASE_KEYWORD
22730#undef PM_CASE_OPERATOR
22731#undef PM_CASE_WRITABLE
22732#undef PM_STRING_EMPTY
22733#undef PM_LOCATION_NODE_BASE_VALUE
22734#undef PM_LOCATION_NODE_VALUE
22735#undef PM_LOCATION_NULL_VALUE
22736#undef PM_LOCATION_TOKEN_VALUE
22741#ifndef PRISM_EXCLUDE_SERIALIZATION
22745 pm_buffer_append_string(buffer,
"PRISM", 5);
22757 pm_serialize_header(buffer);
22759 pm_buffer_append_byte(buffer,
'\0');
22767pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22769 pm_options_read(&options, data);
22772 pm_parser_init(&parser, source, size, &options);
22776 pm_serialize_header(buffer);
22778 pm_buffer_append_byte(buffer,
'\0');
22780 pm_node_destroy(&parser, node);
22781 pm_parser_free(&parser);
22782 pm_options_free(&options);
22793 pm_options_read(&options, data);
22796 pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, fgets, &options);
22797 pm_serialize_header(buffer);
22799 pm_buffer_append_byte(buffer,
'\0');
22801 pm_node_destroy(&parser, node);
22802 pm_buffer_free(&parser_buffer);
22803 pm_parser_free(&parser);
22804 pm_options_free(&options);
22811pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22813 pm_options_read(&options, data);
22816 pm_parser_init(&parser, source, size, &options);
22819 pm_serialize_header(buffer);
22821 pm_buffer_append_varsint(buffer, parser.
start_line);
22824 pm_node_destroy(&parser, node);
22825 pm_parser_free(&parser);
22826 pm_options_free(&options);
22838 PM_SLICE_TYPE_ERROR = -1,
22841 PM_SLICE_TYPE_NONE,
22844 PM_SLICE_TYPE_LOCAL,
22847 PM_SLICE_TYPE_CONSTANT,
22850 PM_SLICE_TYPE_METHOD_NAME
22857pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22859 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22860 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22863 if (length == 0)
return PM_SLICE_TYPE_NONE;
22866 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22868 }
else if (*source ==
'_') {
22871 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22875 return PM_SLICE_TYPE_NONE;
22879 const uint8_t *end = source + length;
22880 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22886 while (source < end) {
22887 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22890 }
else if (*source ==
'_') {
22893 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22903 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22905 result = PM_SLICE_TYPE_METHOD_NAME;
22909 return source == end ? result : PM_SLICE_TYPE_NONE;
22916pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22917 switch (pm_slice_type(source, length, encoding_name)) {
22918 case PM_SLICE_TYPE_ERROR:
22920 case PM_SLICE_TYPE_NONE:
22921 case PM_SLICE_TYPE_CONSTANT:
22922 case PM_SLICE_TYPE_METHOD_NAME:
22924 case PM_SLICE_TYPE_LOCAL:
22928 assert(
false &&
"unreachable");
22936pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22937 switch (pm_slice_type(source, length, encoding_name)) {
22938 case PM_SLICE_TYPE_ERROR:
22940 case PM_SLICE_TYPE_NONE:
22941 case PM_SLICE_TYPE_LOCAL:
22942 case PM_SLICE_TYPE_METHOD_NAME:
22944 case PM_SLICE_TYPE_CONSTANT:
22948 assert(
false &&
"unreachable");
22956pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22957#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22958#define C1(c) (*source == c)
22959#define C2(s) (memcmp(source, s, 2) == 0)
22960#define C3(s) (memcmp(source, s, 3) == 0)
22962 switch (pm_slice_type(source, length, encoding_name)) {
22963 case PM_SLICE_TYPE_ERROR:
22965 case PM_SLICE_TYPE_NONE:
22967 case PM_SLICE_TYPE_LOCAL:
22969 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22970 case PM_SLICE_TYPE_CONSTANT:
22972 case PM_SLICE_TYPE_METHOD_NAME:
22979 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22981 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22983 return B(C3(
"===") || C3(
"<=>") || C3(
"[]="));
struct pm_block_parameter_node pm_block_parameter_node_t
BlockParameterNode.
struct pm_else_node pm_else_node_t
ElseNode.
struct pm_assoc_node pm_assoc_node_t
AssocNode.
struct pm_undef_node pm_undef_node_t
UndefNode.
struct pm_local_variable_target_node pm_local_variable_target_node_t
LocalVariableTargetNode.
struct pm_block_node pm_block_node_t
BlockNode.
struct pm_hash_pattern_node pm_hash_pattern_node_t
HashPatternNode.
struct pm_optional_parameter_node pm_optional_parameter_node_t
OptionalParameterNode.
struct pm_x_string_node pm_x_string_node_t
XStringNode.
struct pm_class_variable_write_node pm_class_variable_write_node_t
ClassVariableWriteNode.
struct pm_interpolated_string_node pm_interpolated_string_node_t
InterpolatedStringNode.
struct pm_call_node pm_call_node_t
CallNode.
struct pm_class_variable_read_node pm_class_variable_read_node_t
ClassVariableReadNode.
@ PM_RANGE_FLAGS_EXCLUDE_END
... operator
struct pm_local_variable_read_node pm_local_variable_read_node_t
LocalVariableReadNode.
struct pm_arguments_node pm_arguments_node_t
ArgumentsNode.
@ PM_DEFINED_NODE
DefinedNode.
@ PM_PRE_EXECUTION_NODE
PreExecutionNode.
@ PM_RETRY_NODE
RetryNode.
@ PM_CONSTANT_PATH_WRITE_NODE
ConstantPathWriteNode.
@ PM_SOURCE_LINE_NODE
SourceLineNode.
@ PM_UNLESS_NODE
UnlessNode.
@ PM_GLOBAL_VARIABLE_READ_NODE
GlobalVariableReadNode.
@ PM_RATIONAL_NODE
RationalNode.
@ PM_FIND_PATTERN_NODE
FindPatternNode.
@ PM_ARRAY_NODE
ArrayNode.
@ PM_CONSTANT_PATH_TARGET_NODE
ConstantPathTargetNode.
@ PM_MULTI_WRITE_NODE
MultiWriteNode.
@ PM_INTERPOLATED_STRING_NODE
InterpolatedStringNode.
@ PM_FALSE_NODE
FalseNode.
@ PM_MATCH_PREDICATE_NODE
MatchPredicateNode.
@ PM_X_STRING_NODE
XStringNode.
@ PM_GLOBAL_VARIABLE_TARGET_NODE
GlobalVariableTargetNode.
@ PM_CONSTANT_TARGET_NODE
ConstantTargetNode.
@ PM_IT_LOCAL_VARIABLE_READ_NODE
ItLocalVariableReadNode.
@ PM_SOURCE_FILE_NODE
SourceFileNode.
@ PM_NO_KEYWORDS_PARAMETER_NODE
NoKeywordsParameterNode.
@ PM_MULTI_TARGET_NODE
MultiTargetNode.
@ PM_SPLAT_NODE
SplatNode.
@ PM_CLASS_VARIABLE_READ_NODE
ClassVariableReadNode.
@ PM_INTERPOLATED_MATCH_LAST_LINE_NODE
InterpolatedMatchLastLineNode.
@ PM_SYMBOL_NODE
SymbolNode.
@ PM_RESCUE_MODIFIER_NODE
RescueModifierNode.
@ PM_ALIAS_METHOD_NODE
AliasMethodNode.
@ PM_MATCH_REQUIRED_NODE
MatchRequiredNode.
@ PM_BACK_REFERENCE_READ_NODE
BackReferenceReadNode.
@ PM_BLOCK_ARGUMENT_NODE
BlockArgumentNode.
@ PM_MISSING_NODE
MissingNode.
@ PM_ASSOC_SPLAT_NODE
AssocSplatNode.
@ PM_RANGE_NODE
RangeNode.
@ PM_LOCAL_VARIABLE_READ_NODE
LocalVariableReadNode.
@ PM_REGULAR_EXPRESSION_NODE
RegularExpressionNode.
@ PM_CONSTANT_WRITE_NODE
ConstantWriteNode.
@ PM_HASH_PATTERN_NODE
HashPatternNode.
@ PM_UNDEF_NODE
UndefNode.
@ PM_ENSURE_NODE
EnsureNode.
@ PM_LOCAL_VARIABLE_WRITE_NODE
LocalVariableWriteNode.
@ PM_KEYWORD_HASH_NODE
KeywordHashNode.
@ PM_PARENTHESES_NODE
ParenthesesNode.
@ PM_CLASS_VARIABLE_WRITE_NODE
ClassVariableWriteNode.
@ PM_POST_EXECUTION_NODE
PostExecutionNode.
@ PM_RETURN_NODE
ReturnNode.
@ PM_ARRAY_PATTERN_NODE
ArrayPatternNode.
@ PM_MATCH_LAST_LINE_NODE
MatchLastLineNode.
@ PM_CONSTANT_PATH_NODE
ConstantPathNode.
@ PM_INTERPOLATED_SYMBOL_NODE
InterpolatedSymbolNode.
@ PM_CLASS_VARIABLE_TARGET_NODE
ClassVariableTargetNode.
@ PM_BREAK_NODE
BreakNode.
@ PM_IMAGINARY_NODE
ImaginaryNode.
@ PM_CONSTANT_READ_NODE
ConstantReadNode.
@ PM_GLOBAL_VARIABLE_WRITE_NODE
GlobalVariableWriteNode.
@ PM_SOURCE_ENCODING_NODE
SourceEncodingNode.
@ PM_BEGIN_NODE
BeginNode.
@ PM_INSTANCE_VARIABLE_READ_NODE
InstanceVariableReadNode.
@ PM_FLIP_FLOP_NODE
FlipFlopNode.
@ PM_INSTANCE_VARIABLE_WRITE_NODE
InstanceVariableWriteNode.
@ PM_INSTANCE_VARIABLE_TARGET_NODE
InstanceVariableTargetNode.
@ PM_FLOAT_NODE
FloatNode.
@ PM_ASSOC_NODE
AssocNode.
@ PM_INTEGER_NODE
IntegerNode.
@ PM_LOCAL_VARIABLE_TARGET_NODE
LocalVariableTargetNode.
@ PM_STRING_NODE
StringNode.
@ PM_ALIAS_GLOBAL_VARIABLE_NODE
AliasGlobalVariableNode.
@ PM_NUMBERED_REFERENCE_READ_NODE
NumberedReferenceReadNode.
@ PM_STATEMENTS_NODE
StatementsNode.
@ PM_BLOCK_NODE
BlockNode.
@ PM_INTERPOLATED_REGULAR_EXPRESSION_NODE
InterpolatedRegularExpressionNode.
struct pm_begin_node pm_begin_node_t
BeginNode.
struct pm_statements_node pm_statements_node_t
StatementsNode.
struct pm_instance_variable_write_node pm_instance_variable_write_node_t
InstanceVariableWriteNode.
struct pm_keyword_hash_node pm_keyword_hash_node_t
KeywordHashNode.
static const pm_node_flags_t PM_NODE_FLAG_NEWLINE
We store the flags enum in every node in the tree.
@ PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING
internal bytes forced the encoding to US-ASCII
struct pm_constant_path_node pm_constant_path_node_t
ConstantPathNode.
struct pm_local_variable_write_node pm_local_variable_write_node_t
LocalVariableWriteNode.
@ PM_STRING_FLAGS_FROZEN
frozen by virtue of a frozen_string_literal: true comment or --enable-frozen-string-literal
@ PM_STRING_FLAGS_FORCED_BINARY_ENCODING
internal bytes forced the encoding to binary
@ PM_STRING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING
if the arguments contain forwarding
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS
if the arguments contain keywords
@ PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT
if the arguments contain a keyword splat
struct pm_parameters_node pm_parameters_node_t
ParametersNode.
#define PM_NODE_FLAG_P(node, flag)
Return true if the given flag is set on the given node.
struct pm_case_node pm_case_node_t
CaseNode.
struct pm_if_node pm_if_node_t
IfNode.
struct pm_rescue_modifier_node pm_rescue_modifier_node_t
RescueModifierNode.
struct pm_splat_node pm_splat_node_t
SplatNode.
struct pm_match_write_node pm_match_write_node_t
MatchWriteNode.
struct pm_multi_write_node pm_multi_write_node_t
MultiWriteNode.
struct pm_interpolated_x_string_node pm_interpolated_x_string_node_t
InterpolatedXStringNode.
struct pm_constant_write_node pm_constant_write_node_t
ConstantWriteNode.
struct pm_flip_flop_node pm_flip_flop_node_t
FlipFlopNode.
#define PM_NODE_TYPE_P(node, type)
Return true if the type of the given node matches the given type.
#define PM_NODE_TYPE(node)
Cast the type to an enum to allow the compiler to provide exhaustiveness checking.
struct pm_global_variable_read_node pm_global_variable_read_node_t
GlobalVariableReadNode.
struct pm_match_last_line_node pm_match_last_line_node_t
MatchLastLineNode.
struct pm_hash_node pm_hash_node_t
HashNode.
struct pm_block_local_variable_node pm_block_local_variable_node_t
BlockLocalVariableNode.
struct pm_multi_target_node pm_multi_target_node_t
MultiTargetNode.
@ PM_INTEGER_BASE_FLAGS_HEXADECIMAL
0x prefix
@ PM_INTEGER_BASE_FLAGS_OCTAL
0o or 0 prefix
@ PM_INTEGER_BASE_FLAGS_DECIMAL
0d or no prefix
@ PM_INTEGER_BASE_FLAGS_BINARY
0b prefix
struct pm_rational_node pm_rational_node_t
RationalNode.
struct pm_ensure_node pm_ensure_node_t
EnsureNode.
struct pm_forwarding_parameter_node pm_forwarding_parameter_node_t
ForwardingParameterNode.
struct pm_when_node pm_when_node_t
WhenNode.
enum pm_token_type pm_token_type_t
This enum represents every type of token in the Ruby source.
struct pm_range_node pm_range_node_t
RangeNode.
struct pm_and_node pm_and_node_t
AndNode.
#define PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
When we're serializing to Java, we want to skip serializing the location fields as they won't be used...
@ PM_CALL_NODE_FLAGS_SAFE_NAVIGATION
&.
@ PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE
a call that is an attribute write, so the value being written should be returned
@ PM_CALL_NODE_FLAGS_VARIABLE_CALL
a call that could have been a local variable
struct pm_constant_read_node pm_constant_read_node_t
ConstantReadNode.
struct pm_or_node pm_or_node_t
OrNode.
struct pm_case_match_node pm_case_match_node_t
CaseMatchNode.
struct pm_imaginary_node pm_imaginary_node_t
ImaginaryNode.
struct pm_array_pattern_node pm_array_pattern_node_t
ArrayPatternNode.
struct pm_integer_node pm_integer_node_t
IntegerNode.
struct pm_constant_path_target_node pm_constant_path_target_node_t
ConstantPathTargetNode.
struct pm_global_variable_target_node pm_global_variable_target_node_t
GlobalVariableTargetNode.
struct pm_node_list pm_node_list_t
A list of nodes in the source, most often used for lists of children.
struct pm_required_parameter_node pm_required_parameter_node_t
RequiredParameterNode.
struct pm_symbol_node pm_symbol_node_t
SymbolNode.
struct pm_block_parameters_node pm_block_parameters_node_t
BlockParametersNode.
struct pm_parentheses_node pm_parentheses_node_t
ParenthesesNode.
@ PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING
internal bytes forced the encoding to US-ASCII
@ PM_REGULAR_EXPRESSION_FLAGS_EXTENDED
x - ignores whitespace and allows comments in regular expressions
struct pm_instance_variable_read_node pm_instance_variable_read_node_t
InstanceVariableReadNode.
struct pm_constant_target_node pm_constant_target_node_t
ConstantTargetNode.
struct pm_node pm_node_t
This is the base structure that represents a node in the syntax tree.
struct pm_interpolated_symbol_node pm_interpolated_symbol_node_t
InterpolatedSymbolNode.
struct pm_class_variable_target_node pm_class_variable_target_node_t
ClassVariableTargetNode.
uint16_t pm_node_flags_t
These are the flags embedded in the node struct.
struct pm_regular_expression_node pm_regular_expression_node_t
RegularExpressionNode.
@ PM_TOKEN_DOT_DOT_DOT
the ... range operator or forwarding parameter
@ PM_TOKEN_IGNORED_NEWLINE
an ignored newline
@ PM_TOKEN_KEYWORD___FILE__
FILE
@ PM_TOKEN_KEYWORD_WHEN
when
@ PM_TOKEN_FLOAT
a floating point number
@ PM_TOKEN_UDOT_DOT
unary .
@ PM_TOKEN_AMPERSAND_DOT
&.
@ PM_TOKEN_NEWLINE
a newline character outside of other tokens
@ PM_TOKEN_NUMBERED_REFERENCE
a numbered reference to a capture group in the previous regular expression match
@ PM_TOKEN_KEYWORD_YIELD
yield
@ PM_TOKEN_KEYWORD_END
end
@ PM_TOKEN_KEYWORD_UNTIL_MODIFIER
until in the modifier form
@ PM_TOKEN_EQUAL_EQUAL_EQUAL
===
@ PM_TOKEN_INTEGER_RATIONAL
an integer with a rational suffix
@ PM_TOKEN_KEYWORD___ENCODING__
ENCODING
@ PM_TOKEN_REGEXP_END
the end of a regular expression
@ PM_TOKEN_KEYWORD_UNTIL
until
@ PM_TOKEN_MAXIMUM
The maximum token value.
@ PM_TOKEN_INTEGER
an integer (any base)
@ PM_TOKEN_UMINUS_NUM
-@ for a number
@ PM_TOKEN_KEYWORD_UNLESS_MODIFIER
unless in the modifier form
@ PM_TOKEN_INTEGER_RATIONAL_IMAGINARY
an integer with a rational and imaginary suffix
@ PM_TOKEN_FLOAT_RATIONAL_IMAGINARY
a floating pointer number with a rational and imaginary suffix
@ PM_TOKEN_BRACKET_LEFT_RIGHT
[]
@ PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL
&&=
@ PM_TOKEN_KEYWORD_CLASS
class
@ PM_TOKEN_KEYWORD_BEGIN
begin
@ PM_TOKEN_NOT_PROVIDED
a token that was not present but it is okay
@ PM_TOKEN_USTAR_STAR
unary **
@ PM_TOKEN_GREATER_GREATER_EQUAL
@ PM_TOKEN_PERCENT_EQUAL
%=
@ PM_TOKEN_KEYWORD_NOT
not
@ PM_TOKEN_BRACKET_LEFT_ARRAY
[ for the beginning of an array
@ PM_TOKEN_HEREDOC_END
the end of a heredoc
@ PM_TOKEN_HEREDOC_START
the start of a heredoc
@ PM_TOKEN_KEYWORD_DEFINED
defined?
@ PM_TOKEN_UCOLON_COLON
unary ::
@ PM_TOKEN_LABEL_END
the end of a label
@ PM_TOKEN_EQUAL_GREATER
=>
@ PM_TOKEN_KEYWORD_UNLESS
unless
@ PM_TOKEN_KEYWORD_ENSURE
ensure
@ PM_TOKEN_AMPERSAND_EQUAL
&=
@ PM_TOKEN_FLOAT_IMAGINARY
a floating pointer number with an imaginary suffix
@ PM_TOKEN_KEYWORD_BEGIN_UPCASE
BEGIN.
@ PM_TOKEN_LESS_EQUAL_GREATER
<=>
@ PM_TOKEN_KEYWORD_RESCUE_MODIFIER
rescue in the modifier form
@ PM_TOKEN_MISSING
a token that was expected but not found
@ PM_TOKEN_MINUS_GREATER
->
@ PM_TOKEN_KEYWORD_FALSE
false
@ PM_TOKEN_PIPE_PIPE_EQUAL
||=
@ PM_TOKEN_EMBEXPR_BEGIN
#{
@ PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES
( for a parentheses node
@ PM_TOKEN_EMBDOC_END
=end
@ PM_TOKEN_KEYWORD_ELSE
else
@ PM_TOKEN_BACK_REFERENCE
a back reference
@ PM_TOKEN_EOF
final token in the file
@ PM_TOKEN_KEYWORD_NIL
nil
@ PM_TOKEN_PERCENT_UPPER_W
W
@ PM_TOKEN_KEYWORD_RETURN
return
@ PM_TOKEN_CLASS_VARIABLE
a class variable
@ PM_TOKEN_PARENTHESIS_LEFT
(
@ PM_TOKEN_PARENTHESIS_RIGHT
)
@ PM_TOKEN_KEYWORD_RESCUE
rescue
@ PM_TOKEN_INSTANCE_VARIABLE
an instance variable
@ PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL
[]=
@ PM_TOKEN_UAMPERSAND
unary &
@ PM_TOKEN_CONSTANT
a constant
@ PM_TOKEN_IDENTIFIER
an identifier
@ PM_TOKEN_EMBDOC_BEGIN
=begin
@ PM_TOKEN_KEYWORD_AND
and
@ PM_TOKEN_KEYWORD_BREAK
break
@ PM_TOKEN_PERCENT_LOWER_W
w
@ PM_TOKEN_SYMBOL_BEGIN
the beginning of a symbol
@ PM_TOKEN_METHOD_NAME
a method name
@ PM_TOKEN_KEYWORD_CASE
case
@ PM_TOKEN_WORDS_SEP
a separator between words in a list
@ PM_TOKEN_FLOAT_RATIONAL
a floating pointer number with a rational suffix
@ PM_TOKEN_LESS_LESS_EQUAL
<<=
@ PM_TOKEN_EMBDOC_LINE
a line inside of embedded documentation
@ PM_TOKEN_KEYWORD_SUPER
super
@ PM_TOKEN_KEYWORD_REDO
redo
@ PM_TOKEN_KEYWORD_END_UPCASE
END.
@ PM_TOKEN_KEYWORD___LINE__
LINE
@ PM_TOKEN_STRING_END
the end of a string
@ PM_TOKEN_STRING_CONTENT
the contents of a string
@ PM_TOKEN_GREATER_GREATER
@ PM_TOKEN_PERCENT_LOWER_X
x
@ PM_TOKEN_KEYWORD_SELF
self
@ PM_TOKEN_PERCENT_LOWER_I
i
@ PM_TOKEN_KEYWORD_ALIAS
alias
@ PM_TOKEN_GLOBAL_VARIABLE
a global variable
@ PM_TOKEN_KEYWORD_IF_MODIFIER
if in the modifier form
@ PM_TOKEN_KEYWORD_RETRY
retry
@ PM_TOKEN_KEYWORD_UNDEF
undef
@ PM_TOKEN_BRACKET_RIGHT
]
@ PM_TOKEN_KEYWORD_FOR
for
@ PM_TOKEN_KEYWORD_THEN
then
@ PM_TOKEN_QUESTION_MARK
?
@ PM_TOKEN___END__
marker for the point in the file at which the parser should stop
@ PM_TOKEN_KEYWORD_WHILE
while
@ PM_TOKEN_KEYWORD_DEF
def
@ PM_TOKEN_UDOT_DOT_DOT
unary ... operator
@ PM_TOKEN_KEYWORD_WHILE_MODIFIER
while in the modifier form
@ PM_TOKEN_KEYWORD_TRUE
true
@ PM_TOKEN_REGEXP_BEGIN
the beginning of a regular expression
@ PM_TOKEN_PERCENT_UPPER_I
I
@ PM_TOKEN_KEYWORD_DO_LOOP
do keyword for a predicate in a while, until, or for loop
@ PM_TOKEN_KEYWORD_MODULE
module
@ PM_TOKEN_KEYWORD_NEXT
next
@ PM_TOKEN_INTEGER_IMAGINARY
an integer with an imaginary suffix
@ PM_TOKEN_STAR_STAR_EQUAL
**=
@ PM_TOKEN_CHARACTER_LITERAL
a character literal
@ PM_TOKEN_AMPERSAND_AMPERSAND
&&
@ PM_TOKEN_GREATER_EQUAL
>=
@ PM_TOKEN_COMMENT
a comment
@ PM_TOKEN_KEYWORD_ELSIF
elsif
@ PM_TOKEN_STRING_BEGIN
the beginning of a string
struct pm_rescue_node pm_rescue_node_t
RescueNode.
struct pm_array_node pm_array_node_t
ArrayNode.
struct pm_global_variable_write_node pm_global_variable_write_node_t
GlobalVariableWriteNode.
@ PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING
internal bytes forced the encoding to UTF-8
struct pm_interpolated_match_last_line_node pm_interpolated_match_last_line_node_t
InterpolatedMatchLastLineNode.
struct pm_unless_node pm_unless_node_t
UnlessNode.
struct pm_interpolated_regular_expression_node pm_interpolated_regular_expression_node_t
InterpolatedRegularExpressionNode.
struct pm_instance_variable_target_node pm_instance_variable_target_node_t
InstanceVariableTargetNode.
struct pm_string_node pm_string_node_t
StringNode.
struct pm_float_node pm_float_node_t
FloatNode.
@ PM_LOOP_FLAGS_BEGIN_MODIFIER
a loop after a begin statement, so the body is executed first before the condition
struct pm_find_pattern_node pm_find_pattern_node_t
FindPatternNode.
pm_diagnostic_id_t
The diagnostic IDs of all of the diagnostics, used to communicate the types of errors between the par...
#define xfree
Old name of ruby_xfree.
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
VALUE type(ANYARGS)
ANYARGS-ed function type.
struct pm_options_scope pm_options_scope_t
A scope of locals surrounding the code that is being parsed.
struct pm_options pm_options_t
The options that can be passed to the parser.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
String literals may be frozen or mutable depending on the implementation default.
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
struct pm_locals pm_locals_t
This is a set of local variables in a certain lexical context (method, class, module,...
pm_heredoc_indent_t
The type of indentation that a heredoc uses.
struct pm_context_node pm_context_node_t
This is a node in a linked list of contexts.
#define PM_LEX_STACK_SIZE
We pre-allocate a certain number of lex states in order to avoid having to call malloc too many times...
struct pm_parser pm_parser_t
The parser used to parse Ruby source.
struct pm_lex_mode pm_lex_mode_t
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
struct pm_comment pm_comment_t
This is a node in the linked list of comments that we've found while parsing.
pm_lex_state_t
This enum combines the various bits from the above enum into individual values that represent the var...
struct pm_scope pm_scope_t
This struct represents a node in a linked list of scopes.
pm_heredoc_quote_t
The type of quote that a heredoc uses.
void(* pm_encoding_changed_callback_t)(pm_parser_t *parser)
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
pm_context_t
While parsing, we keep track of a stack of contexts.
@ PM_CONTEXT_CLASS_RESCUE
a rescue statement within a class statement
@ PM_CONTEXT_ELSIF
an elsif clause
@ PM_CONTEXT_DEF_RESCUE
a rescue statement within a method definition
@ PM_CONTEXT_ELSE
an else clause
@ PM_CONTEXT_FOR_INDEX
a for loop's index
@ PM_CONTEXT_CASE_WHEN
a case when statements
@ PM_CONTEXT_BLOCK_RESCUE
a rescue statement within a do..end block
@ PM_CONTEXT_MODULE
a module declaration
@ PM_CONTEXT_DEF_PARAMS
a method definition's parameters
@ PM_CONTEXT_CASE_IN
a case in statements
@ PM_CONTEXT_BLOCK_ELSE
a rescue else statement within a do..end block
@ PM_CONTEXT_LOOP_PREDICATE
the predicate clause of a loop statement
@ PM_CONTEXT_SCLASS
a singleton class definition
@ PM_CONTEXT_UNLESS
an unless statement
@ PM_CONTEXT_POSTEXE
an END block
@ PM_CONTEXT_IF
an if statement
@ PM_CONTEXT_MULTI_TARGET
a multiple target expression
@ PM_CONTEXT_LAMBDA_RESCUE
a rescue statement within a lambda expression
@ PM_CONTEXT_BEGIN_ELSE
a rescue else statement with an explicit begin
@ PM_CONTEXT_NONE
a null context, used for returning a value from a function
@ PM_CONTEXT_CLASS_ELSE
a rescue else statement within a class statement
@ PM_CONTEXT_LAMBDA_ENSURE
an ensure statement within a lambda expression
@ PM_CONTEXT_BLOCK_ENSURE
an ensure statement within a do..end block
@ PM_CONTEXT_CLASS_ENSURE
an ensure statement within a class statement
@ PM_CONTEXT_LAMBDA_BRACES
a lambda expression with braces
@ PM_CONTEXT_MODULE_ELSE
a rescue else statement within a module statement
@ PM_CONTEXT_PARENS
a parenthesized expression
@ PM_CONTEXT_BLOCK_BRACES
expressions in block arguments using braces
@ PM_CONTEXT_DEF_ENSURE
an ensure statement within a method definition
@ PM_CONTEXT_SCLASS_RESCUE
a rescue statement with a singleton class
@ PM_CONTEXT_PREEXE
a BEGIN block
@ PM_CONTEXT_DEFINED
a defined?
@ PM_CONTEXT_MODULE_ENSURE
an ensure statement within a module statement
@ PM_CONTEXT_BEGIN_RESCUE
a rescue statement with an explicit begin
@ PM_CONTEXT_UNTIL
an until statement
@ PM_CONTEXT_DEF_ELSE
a rescue else statement within a method definition
@ PM_CONTEXT_FOR
a for loop
@ PM_CONTEXT_PREDICATE
a predicate inside an if/elsif/unless statement
@ PM_CONTEXT_BEGIN_ENSURE
an ensure statement with an explicit begin
@ PM_CONTEXT_SCLASS_ENSURE
an ensure statement with a singleton class
@ PM_CONTEXT_DEFAULT_PARAMS
a method definition's default parameter
@ PM_CONTEXT_LAMBDA_ELSE
a rescue else statement within a lambda expression
@ PM_CONTEXT_CLASS
a class declaration
@ PM_CONTEXT_MAIN
the top level context
@ PM_CONTEXT_LAMBDA_DO_END
a lambda expression with do..end
@ PM_CONTEXT_BEGIN
a begin statement
@ PM_CONTEXT_RESCUE_MODIFIER
a modifier rescue clause
@ PM_CONTEXT_EMBEXPR
an interpolated expression
@ PM_CONTEXT_TERNARY
a ternary expression
@ PM_CONTEXT_DEF
a method definition
@ PM_CONTEXT_SCLASS_ELSE
a rescue else statement with a singleton class
@ PM_CONTEXT_MODULE_RESCUE
a rescue statement within a module statement
@ PM_CONTEXT_BLOCK_KEYWORDS
expressions in block arguments using do..end
@ PM_CONTEXT_WHILE
a while statement
uint8_t pm_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.
struct pm_list_node pm_list_node_t
This struct represents an abstract linked list that provides common functionality.
#define PM_STRING_EMPTY
Defines an empty string.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_DEPTH_MAXIMUM
When we are parsing using recursive descent, we want to protect against malicious payloads that could...
#define PM_STATIC_ASSERT(line, condition, message)
We want to be able to use static assertions, but they weren't standardized until C11.
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
#define PM_ENCODING_US_ASCII_ENTRY
This is the US-ASCII encoding.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PRISM_ENCODING_ALPHABETIC_BIT
All of the lookup tables use the first bit of each embedded byte to indicate whether the codepoint is...
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
The main header file for the prism parser.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the encoding, metadata, nodes, and constant pool.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
char * pm_parse_stream_fgets_t(char *string, int size, void *stream)
This function is used in pm_parse_stream to retrieve a line of input from a stream.
void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer)
Serialize the given list of comments to the given buffer.
const char * pm_token_type_human(pm_token_type_t token_type)
Returns the human name of the given token type.
This struct is used to pass information between the regular expression parser and the error callback.
pm_parser_t * parser
The parser that we are parsing the regular expression for.
const uint8_t * start
The start of the regular expression.
bool shared
Whether or not the source of the regular expression is shared.
const uint8_t * end
The end of the regular expression.
This struct is used to pass information between the regular expression parser and the named capture c...
pm_constant_id_list_t names
The list of names that have been parsed.
pm_parser_t * parser
The parser that is parsing the regular expression.
pm_match_write_node_t * match
The match write node that is being created.
pm_call_node_t * call
The call node wrapping the regular expression node.
bool shared
Whether the content of the regular expression is shared.
struct pm_node * left
AndNode#left.
struct pm_node * right
AndNode#right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode#arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode#elements.
struct pm_node * constant
ArrayPatternNode#constant.
pm_location_t opening_loc
ArrayPatternNode#opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
ArrayPatternNode#closing_loc.
struct pm_node * value
AssocNode#value.
struct pm_node * key
AssocNode#key.
struct pm_ensure_node * ensure_clause
BeginNode#ensure_clause.
struct pm_rescue_node * rescue_clause
BeginNode#rescue_clause.
struct pm_statements_node * statements
BeginNode#statements.
pm_node_t base
The embedded base node.
struct pm_else_node * else_clause
BeginNode#else_clause.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
size_t length
The length of the buffer in bytes.
char * value
A pointer to the start of the buffer.
pm_location_t opening_loc
CallNode#opening_loc.
pm_location_t closing_loc
CallNode#closing_loc.
struct pm_node * receiver
CallNode#receiver.
pm_constant_id_t name
CallNode::name.
pm_node_t base
The embedded base node.
pm_location_t call_operator_loc
CallNode#call_operator_loc.
pm_location_t message_loc
CallNode#message_loc.
struct pm_arguments_node * arguments
CallNode#arguments.
struct pm_node * block
CallNode#block.
struct pm_node_list conditions
CaseMatchNode#conditions.
struct pm_node_list conditions
CaseNode#conditions.
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
pm_context_t context
The context that this node represents.
struct pm_context_node * prev
A pointer to the previous context in the linked list.
This struct represents a diagnostic generated during parsing.
struct pm_statements_node * statements
ElseNode#statements.
This struct defines the functions necessary to implement the encoding interface so we can determine h...
size_t(* alpha_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphab...
size_t(* char_width)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding.
bool(* isupper_char)(const uint8_t *b, ptrdiff_t n)
Return true if the next character is valid in the encoding and is an uppercase character.
const char * name
The name of the encoding.
size_t(* alnum_char)(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphan...
struct pm_statements_node * statements
EnsureNode#statements.
struct pm_node * constant
FindPatternNode#constant.
pm_location_t opening_loc
FindPatternNode#opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
FindPatternNode#closing_loc.
double value
FloatNode#value.
pm_node_t base
The embedded base node.
struct pm_node_list elements
HashNode#elements.
pm_location_t opening_loc
HashPatternNode#opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
HashPatternNode#closing_loc.
struct pm_node * constant
HashPatternNode#constant.
All of the information necessary to store to lexing a heredoc.
size_t ident_length
The length of the heredoc identifier.
pm_heredoc_quote_t quote
The type of quote that the heredoc uses.
pm_heredoc_indent_t indent
The type of indentation that the heredoc uses.
const uint8_t * ident_start
A pointer to the start of the heredoc identifier.
struct pm_statements_node * statements
IfNode#statements.
struct pm_node * subsequent
IfNode#subsequent.
pm_integer_t value
IntegerNode#value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode#opening_loc.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedXStringNode#opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode#parts.
void(* callback)(void *data, pm_parser_t *parser, pm_token_t *token)
This is the callback that is called when a token is lexed.
void * data
This opaque pointer is used to provide whatever information the user deemed necessary to the callback...
uint8_t terminator
This is the terminator of the list literal.
size_t nesting
This keeps track of the nesting level of the list.
bool interpolation
Whether or not interpolation is allowed in this list.
uint8_t incrementor
When lexing a list, it takes into account balancing the terminator if the terminator is one of (),...
uint8_t breakpoints[11]
This is the character set that should be used to delimit the tokens within the list.
pm_heredoc_lex_mode_t base
All of the data necessary to lex a heredoc.
bool line_continuation
True if the previous token ended with a line continuation.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
union pm_lex_mode::@303336126360075302344075121136356113360170030306 as
The data associated with this type of lex mode.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
size_t * common_whitespace
This is used to track the amount of common whitespace on each line so that we know how much to dedent...
enum pm_lex_mode::@204051102252353332352362146052355003264223055126 mode
The type of this lex mode.
struct pm_list_node * next
A pointer to the next node in the list.
This represents the overall linked list.
pm_list_node_t * head
A pointer to the head of the list.
size_t size
The size of the list.
This tracks an individual local variable in a certain lexical context, as well as the number of times...
pm_constant_id_t name
The name of the local variable.
pm_location_t location
The location of the local variable in the source.
uint32_t hash
The hash of the local variable.
uint32_t index
The index of the local variable in the local table.
uint32_t reads
The number of times the local variable is read.
uint32_t depth
LocalVariableReadNode#depth.
pm_constant_id_t name
LocalVariableReadNode#name.
uint32_t depth
LocalVariableWriteNode#depth.
pm_constant_id_t name
LocalVariableWriteNode#name.
pm_local_t * locals
The nullable allocated memory for the local variables in the set.
uint32_t capacity
The capacity of the local variables set.
uint32_t size
The number of local variables in the set.
This represents a range of bytes in the source string to which a node or token corresponds.
const uint8_t * start
A pointer to the start location of the range in the source.
const uint8_t * end
A pointer to the end location of the range in the source.
struct pm_node_list targets
MatchWriteNode#targets.
pm_node_t base
The embedded base node.
pm_location_t lparen_loc
MultiTargetNode#lparen_loc.
struct pm_node_list lefts
MultiTargetNode#lefts.
pm_location_t rparen_loc
MultiTargetNode#rparen_loc.
size_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
pm_node_type_t type
This represents the type of the node.
pm_node_flags_t flags
This represents any flags on the node.
pm_location_t location
This is the location of the node in the source.
size_t locals_count
The number of locals in the scope.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
uint8_t command_line
A bitset of the various options that were set on the command line.
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
bool encoding_locked
Whether or not the encoding magic comments should be respected.
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
pm_string_t encoding
The name of the encoding that the source file is in.
int32_t line
The line within the file that the parse starts on.
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
bool partial_script
When the file being parsed is considered a "partial" script, jumps will not be marked as errors if th...
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
pm_string_t filepath
The name of the file that is currently being parsed.
pm_options_version_t version
The version of prism that we should be parsing with.
struct pm_node * left
OrNode#left.
struct pm_node * right
OrNode#right.
struct pm_node * rest
ParametersNode#rest.
struct pm_block_parameter_node * block
ParametersNode#block.
pm_node_t base
The embedded base node.
struct pm_node * keyword_rest
ParametersNode#keyword_rest.
struct pm_node * body
ParenthesesNode#body.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
pm_lex_state_t lex_state
The current state of the lexer.
uint8_t command_line
The command line flags given from the options.
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool partial_script
Whether or not we are parsing a "partial" script, which is a script that will be evaluated in the con...
bool pattern_matching_newlines
This flag indicates that we are currently parsing a pattern matching expression and impacts that calc...
const uint8_t * end
The pointer to the end of the source.
bool recovering
Whether or not we're currently recovering from a syntax error.
pm_node_flags_t integer_base
We want to add a flag to integer nodes that indicates their base.
bool warn_mismatched_indentation
By default, Ruby always warns about mismatched indentation.
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
bool in_keyword_arg
This flag indicates that we are currently parsing a keyword argument.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
pm_token_t previous
The previous token we were considering.
pm_string_t current_string
This string is used to pass information from the lexer to the parser.
bool parsing_eval
Whether or not we are parsing an eval string.
bool current_regular_expression_ascii_only
True if the current regular expression being lexed contains only ASCII characters.
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
pm_location_t data_loc
An optional location that represents the location of the END marker and the rest of the content of th...
pm_context_node_t * current_context
The current parsing context.
const uint8_t * start
The pointer to the start of the source.
int enclosure_nesting
Tracks the current nesting of (), [], and {}.
pm_list_t error_list
The list of errors that have been found while parsing.
int8_t frozen_string_literal
Whether or not we have found a frozen_string_literal magic comment with a true or false value.
pm_node_list_t * current_block_exits
When parsing block exits (e.g., break, next, redo), we need to validate that they are in correct cont...
const uint8_t * encoding_comment_start
This pointer indicates where a comment must start if it is to be considered an encoding comment.
pm_lex_mode_t stack[PM_LEX_STACK_SIZE]
The stack of lexer modes.
pm_list_t warning_list
The list of warnings that have been found while parsing.
const uint8_t * heredoc_end
This field indicates the end of a heredoc whose identifier was found on the current line.
int brace_nesting
Used to track the nesting of braces to ensure we get the correct value when we are interpolating bloc...
pm_encoding_changed_callback_t encoding_changed_callback
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
int32_t start_line
The line number at the start of the parse.
bool encoding_locked
This is very specialized behavior for when you want to parse in a context that does not respect encod...
pm_lex_mode_t * current
The current mode of the lexer.
struct pm_parser::@236040131255244317313236162207277265316171136011 lex_modes
A stack of lex modes.
pm_list_t comment_list
The list of comments that have been found while parsing.
size_t index
The current index into the lexer mode stack.
pm_string_t filepath
This is the path of the file being parsed.
pm_scope_t * current_scope
The current local scope.
bool command_start
Whether or not we're at the beginning of a command.
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
bool semantic_token_seen
Whether or not the parser has seen a token that has semantic meaning (i.e., a token that is not a com...
struct pm_node * right
RangeNode#right.
struct pm_node * left
RangeNode#left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode#numerator.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode#unescaped.
struct pm_node * rescue_expression
RescueModifierNode#rescue_expression.
struct pm_rescue_node * subsequent
RescueNode#subsequent.
pm_node_t base
The embedded base node.
struct pm_scope * previous
A pointer to the previous scope in the linked list.
pm_node_list_t implicit_parameters
This is a list of the implicit parameters contained within the block.
pm_shareable_constant_value_t shareable_constant
The current state of constant shareability for this scope.
pm_locals_t locals
The IDs of the locals in the given scope.
pm_scope_parameters_t parameters
This is a bitfield that indicates the parameters that are being used in this scope.
bool closed
A boolean indicating whether or not this scope can see into its parent.
struct pm_node * expression
SplatNode#expression.
struct pm_node_list body
StatementsNode#body.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode#unescaped.
pm_location_t closing_loc
StringNode#closing_loc.
pm_location_t opening_loc
StringNode#opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
size_t length
The length of the string in bytes of memory.
enum pm_string_t::@346265266332060241255337121126133217326336224105 type
The type of the string.
pm_location_t value_loc
SymbolNode#value_loc.
pm_string_t unescaped
SymbolNode#unescaped.
When we're lexing certain types (strings, symbols, lists, etc.) we have string content associated wit...
pm_buffer_t buffer
The buffer that we're using to keep track of the string content.
const uint8_t * cursor
The cursor into the source string that points to how far we have currently copied into the buffer.
This struct represents a token in the Ruby source.
const uint8_t * end
A pointer to the end location of the token in the source.
const uint8_t * start
A pointer to the start location of the token in the source.
pm_token_type_t type
The type of the token.
struct pm_statements_node * statements
UnlessNode#statements.
struct pm_else_node * else_clause
UnlessNode#else_clause.