5#include "prism/internal/allocator.h"
6#include "prism/internal/arena.h"
7#include "prism/internal/bit.h"
8#include "prism/internal/buffer.h"
9#include "prism/internal/char.h"
10#include "prism/internal/comments.h"
11#include "prism/internal/constant_pool.h"
12#include "prism/internal/diagnostic.h"
13#include "prism/internal/encoding.h"
14#include "prism/internal/integer.h"
15#include "prism/internal/isinf.h"
16#include "prism/internal/line_offset_list.h"
17#include "prism/internal/list.h"
18#include "prism/internal/magic_comments.h"
19#include "prism/internal/memchr.h"
20#include "prism/internal/node.h"
21#include "prism/internal/options.h"
22#include "prism/internal/parser.h"
23#include "prism/internal/regexp.h"
24#include "prism/internal/serialize.h"
25#include "prism/internal/source.h"
26#include "prism/internal/static_literals.h"
27#include "prism/internal/stringy.h"
28#include "prism/internal/strncasecmp.h"
29#include "prism/internal/strpbrk.h"
30#include "prism/internal/tokens.h"
50#ifndef PRISM_DEPTH_MAXIMUM
51 #define PRISM_DEPTH_MAXIMUM 10000
58#define PM_CONCATENATE(left, right) left ## right
65#if defined(_Static_assert)
66# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message)
68# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
75#if defined(__GNUC__) || defined(__clang__)
77 #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
80 #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
83 #define PRISM_LIKELY(x) (x)
86 #define PRISM_UNLIKELY(x) (x)
101#define PM_TAB_WHITESPACE_SIZE 8
104#define MIN(a,b) (((a)<(b))?(a):(b))
105#define MAX(a,b) (((a)>(b))?(a):(b))
111#define U32(value_) ((uint32_t) (value_))
113#define FL PM_NODE_FLAGS
114#define UP PM_NODE_UPCAST
116#define PM_LOCATION_START(location_) ((location_)->start)
117#define PM_LOCATION_END(location_) ((location_)->start + (location_)->length)
119#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
120#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
121#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
122#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
124#define PM_NODE_START(node_) (UP(node_)->location.start)
125#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
126#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
127#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
129#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
130#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
132#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
133#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
134#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
135#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
136#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
138#define PM_LOCATION_INIT(start_, length_) ((pm_location_t) { .start = (start_), .length = (length_) })
139#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
140#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
141#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
143#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
144#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
145#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
146#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
148#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
149#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
150#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
161lex_mode_incrementor(
const uint8_t start) {
178lex_mode_terminator(
const uint8_t start) {
200 lex_mode.prev = parser->lex_modes.current;
201 parser->lex_modes.index++;
203 if (parser->lex_modes.index > PM_LEX_STACK_SIZE - 1) {
205 if (parser->lex_modes.current == NULL)
return false;
207 *parser->lex_modes.current = lex_mode;
209 parser->lex_modes.stack[parser->lex_modes.index] = lex_mode;
210 parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
220lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
221 uint8_t incrementor = lex_mode_incrementor(delimiter);
222 uint8_t terminator = lex_mode_terminator(delimiter);
228 .interpolation = interpolation,
229 .incrementor = incrementor,
230 .terminator = terminator
236 uint8_t *breakpoints = lex_mode.as.list.breakpoints;
237 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
238 memcpy(breakpoints,
"\\ \t\f\r\v\n",
sizeof(
"\\ \t\f\r\v\n") - 1);
243 if (terminator !=
'\0') {
244 breakpoints[index++] = terminator;
250 breakpoints[index++] =
'#';
254 if (incrementor !=
'\0') {
255 breakpoints[index++] = incrementor;
258 parser->explicit_encoding = NULL;
259 return lex_mode_push(parser, lex_mode);
269 return lex_mode_push_list(parser,
false,
'\0');
276lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
278 .mode = PM_LEX_REGEXP,
281 .incrementor = incrementor,
282 .terminator = terminator
289 uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
290 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
291 memcpy(breakpoints,
"\r\n\\#",
sizeof(
"\r\n\\#") - 1);
295 if (terminator !=
'\0') {
296 breakpoints[index++] = terminator;
300 if (incrementor !=
'\0') {
301 breakpoints[index++] = incrementor;
304 parser->explicit_encoding = NULL;
305 return lex_mode_push(parser, lex_mode);
312lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
314 .mode = PM_LEX_STRING,
317 .interpolation = interpolation,
318 .label_allowed = label_allowed,
319 .incrementor = incrementor,
320 .terminator = terminator
326 uint8_t *breakpoints = lex_mode.as.string.breakpoints;
327 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
328 memcpy(breakpoints,
"\r\n\\",
sizeof(
"\r\n\\") - 1);
333 if (terminator !=
'\0') {
334 breakpoints[index++] = terminator;
340 breakpoints[index++] =
'#';
345 if (incrementor !=
'\0') {
346 breakpoints[index++] = incrementor;
349 parser->explicit_encoding = NULL;
350 return lex_mode_push(parser, lex_mode);
360 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
370 if (parser->lex_modes.index == 0) {
371 parser->lex_modes.current->mode = PM_LEX_DEFAULT;
372 }
else if (parser->lex_modes.index < PM_LEX_STACK_SIZE) {
373 parser->lex_modes.index--;
374 parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
376 parser->lex_modes.index--;
378 xfree_sized(parser->lex_modes.current,
sizeof(
pm_lex_mode_t));
379 parser->lex_modes.current = prev;
387lex_state_p(
const pm_parser_t *parser, pm_lex_state_t state) {
388 return parser->lex_state & state;
392 PM_IGNORED_NEWLINE_NONE = 0,
393 PM_IGNORED_NEWLINE_ALL,
394 PM_IGNORED_NEWLINE_PATTERN
395} pm_ignored_newline_type_t;
399 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);
402 return PM_IGNORED_NEWLINE_ALL;
403 }
else if ((parser->lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
404 return PM_IGNORED_NEWLINE_PATTERN;
406 return PM_IGNORED_NEWLINE_NONE;
412 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));
417 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
421lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
422 if (parser->current.end >= parser->end) {
425 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
430 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
438 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
446lex_state_set(
pm_parser_t *parser, pm_lex_state_t state) {
447 parser->lex_state = state;
450#ifndef PM_DEBUG_LOGGING
455#define PM_DEBUG_LOGGING 0
461 fprintf(stderr,
"STATE: ");
464 if (parser->lex_state == PM_LEX_STATE_NONE) {
465 fprintf(stderr,
"NONE\n");
469#define CHECK_STATE(state) \
470 if (parser->lex_state & state) { \
471 if (!first) fprintf(stderr, "|"); \
472 fprintf(stderr, "%s", #state); \
476 CHECK_STATE(PM_LEX_STATE_BEG)
477 CHECK_STATE(PM_LEX_STATE_END)
478 CHECK_STATE(PM_LEX_STATE_ENDARG)
479 CHECK_STATE(PM_LEX_STATE_ENDFN)
480 CHECK_STATE(PM_LEX_STATE_ARG)
481 CHECK_STATE(PM_LEX_STATE_CMDARG)
482 CHECK_STATE(PM_LEX_STATE_MID)
483 CHECK_STATE(PM_LEX_STATE_FNAME)
484 CHECK_STATE(PM_LEX_STATE_DOT)
485 CHECK_STATE(PM_LEX_STATE_CLASS)
486 CHECK_STATE(PM_LEX_STATE_LABEL)
487 CHECK_STATE(PM_LEX_STATE_LABELED)
488 CHECK_STATE(PM_LEX_STATE_FITEM)
492 fprintf(stderr,
"\n");
496debug_lex_state_set(
pm_parser_t *parser, pm_lex_state_t state,
char const * caller_name,
int line_number) {
497 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
499 lex_state_set(parser, state);
500 fprintf(stderr,
"Now: ");
502 fprintf(stderr,
"\n");
505#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
513#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
516#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
519#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
522#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
525#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
528#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
531#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
541pm_parser_err(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
542 pm_diagnostic_list_append(&parser->metadata_arena, &parser->error_list, start, length, diag_id);
551 pm_parser_err(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
559pm_parser_err_current(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
560 pm_parser_err_token(parser, &parser->current, diag_id);
568pm_parser_err_previous(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
569 pm_parser_err_token(parser, &parser->previous, diag_id);
578 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
584#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
585 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
591#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
592 PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
598#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
599 PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
605#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
606 PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id, __VA_ARGS__)
612#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
613 PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
619pm_parser_warn(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
620 pm_diagnostic_list_append(&parser->metadata_arena, &parser->warning_list, start, length, diag_id);
629 pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
638 pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
645#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
646 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->warning_list, start_, length_, diag_id_, __VA_ARGS__)
652#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
653 PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id_, __VA_ARGS__)
659#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
660 PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
666#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
667 PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
675pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
676 PM_PARSER_ERR_FORMAT(
678 U32(ident_start - parser->start),
682 (
const char *) ident_start
694pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
696 if (scope == NULL)
return false;
699 .previous = parser->current_scope,
701 .parameters = PM_SCOPE_PARAMETERS_NONE,
702 .implicit_parameters = { 0 },
703 .shareable_constant = parser->current_scope == NULL ? PM_SCOPE_SHAREABLE_CONSTANT_NONE : parser->current_scope->shareable_constant,
707 parser->current_scope = scope;
720 if (scope->previous == NULL)
return true;
721 if (scope->closed)
return false;
722 }
while ((scope = scope->previous) != NULL);
724 assert(
false &&
"unreachable");
732pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
735 while (depth-- > 0) {
736 assert(scope != NULL);
737 scope = scope->previous;
744 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
745 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
746 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
747} pm_scope_forwarding_param_check_result_t;
749static pm_scope_forwarding_param_check_result_t
750pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
752 bool conflict =
false;
754 while (scope != NULL) {
755 if (scope->parameters & mask) {
758 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
760 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
767 if (scope->closed)
break;
768 scope = scope->previous;
771 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
776 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
777 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
780 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
781 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
783 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
784 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
791 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
792 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
795 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
796 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
798 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
799 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
806 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
807 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
810 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
815 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
816 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
823 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
824 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
827 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
828 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
830 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
831 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
840pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
841 return parser->current_scope->shareable_constant;
849pm_parser_scope_shareable_constant_set(
pm_parser_t *parser, pm_shareable_constant_value_t shareable_constant) {
853 scope->shareable_constant = shareable_constant;
854 }
while (!scope->closed && (scope = scope->previous) != NULL);
864#define PM_LOCALS_HASH_THRESHOLD 5
868 if (locals->capacity > 0) {
869 xfree_sized(locals->locals, locals->capacity *
sizeof(
pm_local_t));
879 name = ((name >> 16) ^ name) * 0x45d9f3b;
880 name = ((name >> 16) ^ name) * 0x45d9f3b;
881 name = (name >> 16) ^ name;
891 uint32_t next_capacity = locals->capacity == 0 ? 4 : (locals->capacity * 2);
892 assert(next_capacity > locals->capacity);
895 if (next_locals == NULL) abort();
897 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
898 if (locals->size > 0) {
899 memcpy(next_locals, locals->locals, locals->size *
sizeof(
pm_local_t));
904 bool hash_needed = (locals->capacity <= PM_LOCALS_HASH_THRESHOLD);
905 uint32_t mask = next_capacity - 1;
907 for (uint32_t index = 0; index < locals->capacity; index++) {
910 if (local->name != PM_CONSTANT_ID_UNSET) {
911 if (hash_needed) local->hash = pm_locals_hash(local->name);
913 uint32_t hash = local->hash;
914 while (next_locals[hash & mask].name != PM_CONSTANT_ID_UNSET) hash++;
915 next_locals[hash & mask] = *local;
920 pm_locals_free(locals);
921 locals->locals = next_locals;
922 locals->capacity = next_capacity;
942 if (locals->size >= (locals->capacity / 4 * 3)) {
943 pm_locals_resize(locals);
946 locals->bloom |= (1u << (name & 31));
948 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
949 for (uint32_t index = 0; index < locals->capacity; index++) {
952 if (local->name == PM_CONSTANT_ID_UNSET) {
955 .location = { .start = start, .length = length },
956 .index = locals->size++,
961 }
else if (local->name == name) {
966 uint32_t mask = locals->capacity - 1;
967 uint32_t hash = pm_locals_hash(name);
968 uint32_t initial_hash = hash;
971 pm_local_t *local = &locals->locals[hash & mask];
973 if (local->name == PM_CONSTANT_ID_UNSET) {
976 .location = { .start = start, .length = length },
977 .index = locals->size++,
982 }
else if (local->name == name) {
987 }
while ((hash & mask) != initial_hash);
990 assert(
false &&
"unreachable");
1000 if (!(locals->bloom & (1u << (name & 31))))
return UINT32_MAX;
1002 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
1003 for (uint32_t index = 0; index < locals->size; index++) {
1005 if (local->name == name)
return index;
1008 uint32_t mask = locals->capacity - 1;
1009 uint32_t hash = pm_locals_hash(name);
1010 uint32_t initial_hash = hash & mask;
1013 pm_local_t *local = &locals->locals[hash & mask];
1015 if (local->name == PM_CONSTANT_ID_UNSET) {
1017 }
else if (local->name == name) {
1022 }
while ((hash & mask) != initial_hash);
1034 uint32_t index = pm_locals_find(locals, name);
1035 assert(index != UINT32_MAX);
1038 assert(local->reads < UINT32_MAX);
1049 uint32_t index = pm_locals_find(locals, name);
1050 assert(index != UINT32_MAX);
1053 assert(local->reads > 0);
1063 uint32_t index = pm_locals_find(locals, name);
1064 assert(index != UINT32_MAX);
1066 return locals->locals[index].reads;
1079 pm_constant_id_list_init_capacity(parser->arena, list, locals->size);
1084 uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
1088 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
1090 for (uint32_t index = 0; index < capacity; index++) {
1093 if (local->name != PM_CONSTANT_ID_UNSET) {
1094 pm_constant_id_list_insert(list, (
size_t) local->index, local->name);
1096 if (warn_unused && local->reads == 0 && ((parser->start_line >= 0) || (pm_line_offset_list_line(&parser->line_offsets, local->location.
start, parser->start_line) >= 0))) {
1097 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->name);
1099 if (constant->length >= 1 && *constant->start !=
'_') {
1100 PM_PARSER_WARN_FORMAT(
1102 local->location.
start,
1104 PM_WARN_UNUSED_LOCAL_VARIABLE,
1105 (
int) constant->length,
1106 (
const char *) constant->start
1122pm_parser_constant_id_raw(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1125 if (start == parser->constant_cache.start && end == parser->constant_cache.end) {
1126 return parser->constant_cache.id;
1129 pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (
size_t) (end - start));
1131 parser->constant_cache.start = start;
1132 parser->constant_cache.end = end;
1133 parser->constant_cache.id = id;
1142pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1143 return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length);
1150pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1151 return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (
const uint8_t *) start, length);
1159 return pm_parser_constant_id_raw(parser, token->start, token->end);
1166#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1167 case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1178 while (node != NULL) {
1179 switch (PM_NODE_TYPE(node)) {
1180 case PM_CASE_VOID_VALUE:
1181 return void_node != NULL ? void_node : node;
1182 case PM_MATCH_PREDICATE_NODE:
1184 case PM_BEGIN_NODE: {
1190 if (vn != NULL)
return vn;
1195 if (vn != NULL)
return vn;
1201 if (cast->
else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1205 if (vn == NULL)
return NULL;
1206 if (void_node == NULL) void_node = vn;
1210 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1214 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1226 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1227 pm_node_t *vn = pm_check_value_expression(parser, node);
1228 if (vn != NULL)
return vn;
1239 case PM_CASE_NODE: {
1241 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1250 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1254 if (vn == NULL)
return NULL;
1255 if (void_node == NULL) void_node = vn;
1258 node = UP(cast->else_clause);
1261 case PM_CASE_MATCH_NODE: {
1263 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1272 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1276 if (vn == NULL)
return NULL;
1277 if (void_node == NULL) void_node = vn;
1280 node = UP(cast->else_clause);
1283 case PM_ENSURE_NODE: {
1288 case PM_PARENTHESES_NODE: {
1290 node = UP(cast->
body);
1293 case PM_STATEMENTS_NODE: {
1297 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1300 switch (PM_NODE_TYPE(body_part)) {
1301 case PM_CASE_VOID_VALUE:
1302 if (void_node == NULL) {
1303 void_node = body_part;
1323 if (void_node == NULL) {
1329 case PM_UNLESS_NODE: {
1338 if (void_node == NULL) {
1344 case PM_ELSE_NODE: {
1359 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1363 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->previous;
1365 pm_locals_read(&scope->locals, cast->
name);
1378 pm_node_t *void_node = pm_check_value_expression(parser, node);
1379 if (void_node != NULL) {
1380 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1389 const char *
type = NULL;
1392 switch (PM_NODE_TYPE(node)) {
1393 case PM_BACK_REFERENCE_READ_NODE:
1394 case PM_CLASS_VARIABLE_READ_NODE:
1395 case PM_GLOBAL_VARIABLE_READ_NODE:
1396 case PM_INSTANCE_VARIABLE_READ_NODE:
1397 case PM_LOCAL_VARIABLE_READ_NODE:
1398 case PM_NUMBERED_REFERENCE_READ_NODE:
1399 type =
"a variable";
1402 case PM_CALL_NODE: {
1406 const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->
name);
1407 switch (message->length) {
1409 switch (message->start[0]) {
1420 type = (
const char *) message->start;
1426 switch (message->start[1]) {
1428 if (message->start[0] ==
'<' || message->start[0] ==
'>' || message->start[0] ==
'!' || message->start[0] ==
'=') {
1429 type = (
const char *) message->start;
1434 if (message->start[0] ==
'+' || message->start[0] ==
'-') {
1435 type = (
const char *) message->start;
1440 if (message->start[0] ==
'*') {
1441 type = (
const char *) message->start;
1448 if (memcmp(message->start,
"<=>", 3) == 0) {
1457 case PM_CONSTANT_PATH_NODE:
1461 case PM_CONSTANT_READ_NODE:
1462 type =
"a constant";
1465 case PM_DEFINED_NODE:
1474 case PM_IMAGINARY_NODE:
1475 case PM_INTEGER_NODE:
1476 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1477 case PM_INTERPOLATED_STRING_NODE:
1478 case PM_RATIONAL_NODE:
1479 case PM_REGULAR_EXPRESSION_NODE:
1480 case PM_SOURCE_ENCODING_NODE:
1481 case PM_SOURCE_FILE_NODE:
1482 case PM_SOURCE_LINE_NODE:
1483 case PM_STRING_NODE:
1484 case PM_SYMBOL_NODE:
1492 case PM_RANGE_NODE: {
1495 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1518 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1529 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1530 for (
size_t index = 0; index < size; index++) {
1531 pm_void_statement_check(parser, node->
body.
nodes[index]);
1541 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1542 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1543 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1544} pm_conditional_predicate_type_t;
1550pm_parser_warn_conditional_predicate_literal(
pm_parser_t *parser,
pm_node_t *node, pm_conditional_predicate_type_t
type, pm_diagnostic_id_t diag_id,
const char *prefix) {
1552 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1553 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1555 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1556 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1558 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1568pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1569 switch (PM_NODE_TYPE(node)) {
1570 case PM_ARRAY_NODE: {
1571 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1574 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1575 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1580 case PM_HASH_NODE: {
1581 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1584 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1586 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1589 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1596 case PM_IMAGINARY_NODE:
1597 case PM_INTEGER_NODE:
1599 case PM_RATIONAL_NODE:
1600 case PM_REGULAR_EXPRESSION_NODE:
1601 case PM_SOURCE_ENCODING_NODE:
1602 case PM_SOURCE_FILE_NODE:
1603 case PM_SOURCE_LINE_NODE:
1604 case PM_STRING_NODE:
1605 case PM_SYMBOL_NODE:
1619 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1620 pm_parser_warn_node(parser, node, parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_WARN_EQUAL_IN_CONDITIONAL_3_3 : PM_WARN_EQUAL_IN_CONDITIONAL);
1638 switch (PM_NODE_TYPE(node)) {
1641 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1642 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1647 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1648 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1651 case PM_PARENTHESES_NODE: {
1654 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1656 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1661 case PM_BEGIN_NODE: {
1669 case PM_RANGE_NODE: {
1672 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1673 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1681 node->
type = PM_FLIP_FLOP_NODE;
1685 case PM_REGULAR_EXPRESSION_NODE:
1690 node->
type = PM_MATCH_LAST_LINE_NODE;
1692 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1693 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1697 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1702 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1704 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1705 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1709 case PM_INTEGER_NODE:
1710 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1711 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1712 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1715 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1718 case PM_STRING_NODE:
1719 case PM_SOURCE_FILE_NODE:
1720 case PM_INTERPOLATED_STRING_NODE:
1721 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1723 case PM_SYMBOL_NODE:
1724 case PM_INTERPOLATED_SYMBOL_NODE:
1725 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1727 case PM_SOURCE_LINE_NODE:
1728 case PM_SOURCE_ENCODING_NODE:
1730 case PM_RATIONAL_NODE:
1731 case PM_IMAGINARY_NODE:
1732 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1734 case PM_CLASS_VARIABLE_WRITE_NODE:
1737 case PM_CONSTANT_WRITE_NODE:
1740 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1743 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1746 case PM_LOCAL_VARIABLE_WRITE_NODE:
1749 case PM_MULTI_WRITE_NODE:
1785 if (arguments->
block != NULL) {
1786 uint32_t end = PM_NODE_END(arguments->
block);
1789 uint32_t arguments_end = PM_LOCATION_END(&arguments->
closing_loc);
1790 if (arguments_end > end) {
1833 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1847char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1848 if (n <= 0)
return 0;
1850 if (parser->encoding_changed) {
1853 if ((width = parser->encoding->alpha_char(b, n)) != 0) {
1855 }
else if (*b ==
'_') {
1857 }
else if (*b >= 0x80) {
1858 return parser->encoding->char_width(b, n);
1862 }
else if (*b < 0x80) {
1863 return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b ==
'_');
1865 return pm_encoding_utf_8_char_width(b, n);
1874char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1877 }
else if (*b < 0x80) {
1878 return (*b ==
'_') || (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0);
1880 return pm_encoding_utf_8_char_width(b, n);
1897#if defined(PRISM_HAS_NEON)
1898#include <arm_neon.h>
1901scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1902 const uint8_t *cursor = start;
1909 static const uint8_t low_lut_data[16] = {
1910 0x15, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
1911 0x1F, 0x1F, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0E
1913 static const uint8_t high_lut_data[16] = {
1914 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
1915 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1917 const uint8x16_t low_lut = vld1q_u8(low_lut_data);
1918 const uint8x16_t high_lut = vld1q_u8(high_lut_data);
1919 const uint8x16_t mask_0f = vdupq_n_u8(0x0F);
1921 while (cursor + 16 <= end) {
1922 uint8x16_t v = vld1q_u8(cursor);
1924 uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
1925 uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
1926 uint8x16_t ident = vandq_u8(lo_class, hi_class);
1929 if (vminvq_u8(ident) != 0) {
1935 uint8x16_t is_zero = vceqq_u8(ident, vdupq_n_u8(0));
1936 uint64_t lo = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 0);
1939 cursor += pm_ctzll(lo) / 8;
1941 uint64_t hi = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 1);
1942 cursor += 8 + pm_ctzll(hi) / 8;
1945 return (
size_t) (cursor - start);
1948 return (
size_t) (cursor - start);
1951#elif defined(PRISM_HAS_SSSE3)
1952#include <tmmintrin.h>
1955scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1956 const uint8_t *cursor = start;
1958 while (cursor + 16 <= end) {
1959 __m128i v = _mm_loadu_si128((
const __m128i *) cursor);
1960 __m128i zero = _mm_setzero_si128();
1967 __m128i lowered = _mm_or_si128(v, _mm_set1_epi8(0x20));
1968 __m128i letter = _mm_and_si128(
1969 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x61), lowered), zero),
1970 _mm_cmpeq_epi8(_mm_subs_epu8(lowered, _mm_set1_epi8(0x7A)), zero));
1972 __m128i digit = _mm_and_si128(
1973 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x30), v), zero),
1974 _mm_cmpeq_epi8(_mm_subs_epu8(v, _mm_set1_epi8(0x39)), zero));
1976 __m128i underscore = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5F));
1978 __m128i ident = _mm_or_si128(_mm_or_si128(letter, digit), underscore);
1979 int mask = _mm_movemask_epi8(ident);
1981 if (mask == 0xFFFF) {
1986 cursor += pm_ctzll((uint64_t) (~mask & 0xFFFF));
1987 return (
size_t) (cursor - start);
1990 return (
size_t) (cursor - start);
1997#elif defined(PRISM_HAS_SWAR)
2009scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
2010 static const uint64_t ones = 0x0101010101010101ULL;
2011 static const uint64_t highs = 0x8080808080808080ULL;
2012 const uint8_t *cursor = start;
2014 while (cursor + 8 <= end) {
2016 memcpy(&word, cursor, 8);
2019 if (word & highs)
break;
2021 uint64_t digit = ((word | highs) - ones * 0x30) & ((ones * 0x39 | highs) - word) & highs;
2028 uint64_t lowered = word | (ones * 0x20);
2029 uint64_t letter = ((lowered | highs) - ones * 0x61) & ((ones * 0x7A | highs) - lowered) & highs;
2034 uint64_t xor_us = word ^ (ones * 0x5F);
2035 uint64_t underscore = (xor_us - ones) & ~xor_us & highs;
2037 uint64_t ident = digit | letter | underscore;
2039 if (ident == highs) {
2046 uint64_t not_ident = ~ident & highs;
2047 cursor += pm_ctzll(not_ident) / 8;
2048 return (
size_t) (cursor - start);
2051 return (
size_t) (cursor - start);
2058#define scan_identifier_ascii(start, end) ((size_t) 0)
2068char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
2071 }
else if (parser->encoding_changed) {
2074 if ((width = parser->encoding->alnum_char(b, n)) != 0) {
2076 }
else if (*b ==
'_') {
2078 }
else if (*b >= 0x80) {
2079 return parser->encoding->char_width(b, n);
2084 return char_is_identifier_utf8(b, n);
2091#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
2092#define PUNCT(idx) ( \
2093 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
2094 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
2095 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
2096 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
2097 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
2100const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
2105static PRISM_INLINE bool
2106char_is_global_name_punctuation(const uint8_t b) {
2107 const unsigned int i = (const unsigned int) b;
2108 if (i <= 0x20 || 0x7e < i) return false;
2110 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
2113static PRISM_INLINE bool
2114token_is_setter_name(pm_token_t *token) {
2116 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
2117 ((token->type == PM_TOKEN_IDENTIFIER) &&
2118 (token->end - token->start >= 2) &&
2119 (token->end[-1] == '='))
2127pm_local_is_keyword(const char *source, size_t length) {
2128#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
2132 switch (source[0]) {
2133 case 'd': KEYWORD("do"); return false;
2134 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
2135 case 'o': KEYWORD("or"); return false;
2136 default: return false;
2139 switch (source[0]) {
2140 case 'a': KEYWORD("and"); return false;
2141 case 'd': KEYWORD("def"); return false;
2142 case 'e': KEYWORD("end"); return false;
2143 case 'f': KEYWORD("for"); return false;
2144 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
2145 default: return false;
2148 switch (source[0]) {
2149 case 'c': KEYWORD("case"); return false;
2150 case 'e': KEYWORD("else"); return false;
2151 case 'n': KEYWORD("next"); return false;
2152 case 'r': KEYWORD("redo"); return false;
2153 case 's': KEYWORD("self"); return false;
2154 case 't': KEYWORD("then"); KEYWORD("true"); return false;
2155 case 'w': KEYWORD("when"); return false;
2156 default: return false;
2159 switch (source[0]) {
2160 case 'a': KEYWORD("alias"); return false;
2161 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
2162 case 'c': KEYWORD("class"); return false;
2163 case 'e': KEYWORD("elsif"); return false;
2164 case 'f': KEYWORD("false"); return false;
2165 case 'r': KEYWORD("retry"); return false;
2166 case 's': KEYWORD("super"); return false;
2167 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
2168 case 'w': KEYWORD("while"); return false;
2169 case 'y': KEYWORD("yield"); return false;
2170 default: return false;
2173 switch (source[0]) {
2174 case 'e': KEYWORD("ensure"); return false;
2175 case 'm': KEYWORD("module"); return false;
2176 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
2177 case 'u': KEYWORD("unless"); return false;
2178 default: return false;
2181 KEYWORD("__LINE__");
2182 KEYWORD("__FILE__");
2185 KEYWORD("__ENCODING__");
2194/******************************************************************************/
2195/* Node flag handling functions */
2196/******************************************************************************/
2201static PRISM_INLINE void
2202pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
2203 node->flags |= flag;
2209static PRISM_INLINE void
2210pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
2211 node->flags &= (pm_node_flags_t) ~flag;
2217static PRISM_INLINE void
2218pm_node_flag_set_repeated_parameter(pm_node_t *node) {
2219 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
2220 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
2221 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
2222 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
2223 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
2224 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
2225 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
2226 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
2228 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
2231/******************************************************************************/
2232/* Node creation functions */
2233/******************************************************************************/
2240#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)
2245static PRISM_INLINE pm_node_flags_t
2246pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
2247 pm_node_flags_t flags = 0;
2249 if (closing->type == PM_TOKEN_REGEXP_END) {
2250 pm_buffer_t unknown_flags = { 0 };
2252 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
2254 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
2255 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
2256 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
2257 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
2259 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
2260 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
2261 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
2262 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
2264 default: pm_buffer_append_byte(&unknown_flags, *flag);
2268 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
2269 if (unknown_flags_length != 0) {
2270 const char *word = unknown_flags_length >= 2 ? "options" : "option";
2271 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
2273 pm_buffer_cleanup(&unknown_flags);
2279#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
2281static pm_statements_node_t *
2282pm_statements_node_create(pm_parser_t *parser);
2285pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
2288pm_statements_node_body_length(pm_statements_node_t *node);
2294static PRISM_INLINE void
2295pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
2296 if (integer->values != NULL) {
2297 size_t byte_size = integer->length * sizeof(uint32_t);
2298 uint32_t *old_values = integer->values;
2299 integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
2307static pm_error_recovery_node_t *
2308pm_error_recovery_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
2309 return pm_error_recovery_node_new(
2313 ((pm_location_t) { .start = start, .length = length }),
2321static pm_error_recovery_node_t *
2322pm_error_recovery_node_create_unexpected(pm_parser_t *parser, pm_node_t *unexpected) {
2323 return pm_error_recovery_node_new(
2327 unexpected->location,
2335static pm_alias_global_variable_node_t *
2336pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2337 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2339 return pm_alias_global_variable_node_new(
2343 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2346 TOK2LOC(parser, keyword)
2353static pm_alias_method_node_t *
2354pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2355 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2357 return pm_alias_method_node_new(
2361 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2364 TOK2LOC(parser, keyword)
2371static pm_alternation_pattern_node_t *
2372pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2373 return pm_alternation_pattern_node_new(
2377 PM_LOCATION_INIT_NODES(left, right),
2380 TOK2LOC(parser, operator)
2387static pm_and_node_t *
2388pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2389 pm_assert_value_expression(parser, left);
2391 return pm_and_node_new(
2395 PM_LOCATION_INIT_NODES(left, right),
2398 TOK2LOC(parser, operator)
2405static pm_arguments_node_t *
2406pm_arguments_node_create(pm_parser_t *parser) {
2407 return pm_arguments_node_new(
2411 PM_LOCATION_INIT_UNSET,
2412 ((pm_node_list_t) { 0 })
2420pm_arguments_node_size(pm_arguments_node_t *node) {
2421 return node->arguments.size;
2428pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
2429 if (pm_arguments_node_size(node) == 0) {
2430 PM_NODE_START_SET_NODE(node, argument);
2433 if (PM_NODE_END(node) < PM_NODE_END(argument)) {
2434 PM_NODE_LENGTH_SET_NODE(node, argument);
2437 pm_node_list_append(arena, &node->arguments, argument);
2439 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2440 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2441 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2443 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2451static pm_array_node_t *
2452pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2453 if (opening == NULL) {
2454 return pm_array_node_new(
2457 PM_NODE_FLAG_STATIC_LITERAL,
2458 PM_LOCATION_INIT_UNSET,
2459 ((pm_node_list_t) { 0 }),
2460 ((pm_location_t) { 0 }),
2461 ((pm_location_t) { 0 })
2464 return pm_array_node_new(
2467 PM_NODE_FLAG_STATIC_LITERAL,
2468 PM_LOCATION_INIT_TOKEN(parser, opening),
2469 ((pm_node_list_t) { 0 }),
2470 TOK2LOC(parser, opening),
2471 TOK2LOC(parser, opening)
2479static PRISM_INLINE void
2480pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
2481 if (!node->elements.size && !node->opening_loc.length) {
2482 PM_NODE_START_SET_NODE(node, element);
2485 pm_node_list_append(arena, &node->elements, element);
2486 PM_NODE_LENGTH_SET_NODE(node, element);
2488 // If the element is not a static literal, then the array is not a static
2489 // literal. Turn that flag off.
2490 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)) {
2491 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2494 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2495 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2503pm_array_node_close_set(const pm_parser_t *parser, pm_array_node_t *node, const pm_token_t *closing) {
2504 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == 0);
2505 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2506 node->closing_loc = TOK2LOC(parser, closing);
2513static pm_array_pattern_node_t *
2514pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2515 pm_array_pattern_node_t *node = pm_array_pattern_node_new(
2519 PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2521 ((pm_node_list_t) { 0 }),
2523 ((pm_node_list_t) { 0 }),
2524 ((pm_location_t) { 0 }),
2525 ((pm_location_t) { 0 })
2528 // For now we're going to just copy over each pointer manually. This could be
2529 // much more efficient, as we could instead resize the node list.
2530 bool found_rest = false;
2533 PM_NODE_LIST_FOREACH(nodes, index, child) {
2534 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2537 } else if (found_rest) {
2538 pm_node_list_append(parser->arena, &node->posts, child);
2540 pm_node_list_append(parser->arena, &node->requireds, child);
2550static pm_array_pattern_node_t *
2551pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2552 return pm_array_pattern_node_new(
2556 PM_LOCATION_INIT_NODE(rest),
2558 ((pm_node_list_t) { 0 }),
2560 ((pm_node_list_t) { 0 }),
2561 ((pm_location_t) { 0 }),
2562 ((pm_location_t) { 0 })
2570static pm_array_pattern_node_t *
2571pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2572 return pm_array_pattern_node_new(
2576 PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
2578 ((pm_node_list_t) { 0 }),
2580 ((pm_node_list_t) { 0 }),
2581 TOK2LOC(parser, opening),
2582 TOK2LOC(parser, closing)
2590static pm_array_pattern_node_t *
2591pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2592 return pm_array_pattern_node_new(
2596 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2598 ((pm_node_list_t) { 0 }),
2600 ((pm_node_list_t) { 0 }),
2601 TOK2LOC(parser, opening),
2602 TOK2LOC(parser, closing)
2606static PRISM_INLINE void
2607pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
2608 pm_node_list_append(arena, &node->requireds, inner);
2614static pm_assoc_node_t *
2615pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2618 if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
2619 end = PM_NODE_END(value);
2620 } else if (operator != NULL) {
2621 end = PM_TOKEN_END(parser, operator);
2623 end = PM_NODE_END(key);
2626 // Hash string keys will be frozen, so we can mark them as frozen here so
2627 // that the compiler picks them up and also when we check for static literal
2628 // on the keys it gets factored in.
2629 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2630 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2633 // If the key and value of this assoc node are both static literals, then
2634 // we can mark this node as a static literal.
2635 pm_node_flags_t flags = 0;
2637 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2638 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)
2640 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2643 return pm_assoc_node_new(
2647 ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
2650 NTOK2LOC(parser, operator)
2657static pm_assoc_splat_node_t *
2658pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2659 assert(operator->type == PM_TOKEN_USTAR_STAR);
2661 return pm_assoc_splat_node_new(
2665 (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
2667 TOK2LOC(parser, operator)
2674static pm_back_reference_read_node_t *
2675pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2676 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2678 return pm_back_reference_read_node_new(
2682 PM_LOCATION_INIT_TOKEN(parser, name),
2683 pm_parser_constant_id_token(parser, name)
2690static pm_begin_node_t *
2691pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2692 uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
2693 uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
2695 return pm_begin_node_new(
2699 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2700 NTOK2LOC(parser, begin_keyword),
2705 ((pm_location_t) { 0 })
2713pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2714 if (node->begin_keyword_loc.length == 0) {
2715 PM_NODE_START_SET_NODE(node, rescue_clause);
2717 PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
2718 node->rescue_clause = rescue_clause;
2725pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2726 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2727 PM_NODE_START_SET_NODE(node, else_clause);
2729 PM_NODE_LENGTH_SET_NODE(node, else_clause);
2730 node->else_clause = else_clause;
2737pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2738 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2739 PM_NODE_START_SET_NODE(node, ensure_clause);
2741 PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
2742 node->ensure_clause = ensure_clause;
2749pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
2750 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
2751 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
2752 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
2758static pm_block_argument_node_t *
2759pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2760 assert(operator->type == PM_TOKEN_UAMPERSAND);
2762 return pm_block_argument_node_new(
2766 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
2768 TOK2LOC(parser, operator)
2775static pm_block_node_t *
2776pm_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) {
2777 return pm_block_node_new(
2781 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2785 TOK2LOC(parser, opening),
2786 TOK2LOC(parser, closing)
2793static pm_block_parameter_node_t *
2794pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2795 assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2797 return pm_block_parameter_node_new(
2801 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
2802 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
2803 NTOK2LOC(parser, name),
2804 TOK2LOC(parser, operator)
2811static pm_block_parameters_node_t *
2812pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2814 if (opening != NULL) {
2815 start = PM_TOKEN_START(parser, opening);
2816 } else if (parameters != NULL) {
2817 start = PM_NODE_START(parameters);
2823 if (parameters != NULL) {
2824 end = PM_NODE_END(parameters);
2825 } else if (opening != NULL) {
2826 end = PM_TOKEN_END(parser, opening);
2831 return pm_block_parameters_node_new(
2835 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2837 ((pm_node_list_t) { 0 }),
2838 NTOK2LOC(parser, opening),
2839 ((pm_location_t) { 0 })
2847pm_block_parameters_node_closing_set(const pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_token_t *closing) {
2848 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == 0);
2849 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2850 node->closing_loc = TOK2LOC(parser, closing);
2856static pm_block_local_variable_node_t *
2857pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2858 return pm_block_local_variable_node_new(
2862 PM_LOCATION_INIT_TOKEN(parser, name),
2863 pm_parser_constant_id_token(parser, name)
2871pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2872 pm_node_list_append(arena, &node->locals, UP(local));
2874 if (PM_NODE_LENGTH(node) == 0) {
2875 PM_NODE_START_SET_NODE(node, local);
2878 PM_NODE_LENGTH_SET_NODE(node, local);
2884static pm_break_node_t *
2885pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2886 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2888 return pm_break_node_new(
2892 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
2894 TOK2LOC(parser, keyword)
2898// There are certain flags that we want to use internally but don't want to
2899// expose because they are not relevant beyond parsing. Therefore we'll define
2900// them here and not define them in config.yml/a header file.
2901static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2903static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2904static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2905static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2912static pm_call_node_t *
2913pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2914 return pm_call_node_new(
2918 PM_LOCATION_INIT_UNSET,
2920 ((pm_location_t) { 0 }),
2922 ((pm_location_t) { 0 }),
2923 ((pm_location_t) { 0 }),
2925 ((pm_location_t) { 0 }),
2926 ((pm_location_t) { 0 }),
2935static PRISM_INLINE pm_node_flags_t
2936pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2937 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2944static pm_call_node_t *
2945pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2946 pm_assert_value_expression(parser, receiver);
2948 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2949 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2950 flags |= PM_CALL_NODE_FLAGS_INDEX;
2953 pm_call_node_t *node = pm_call_node_create(parser, flags);
2955 PM_NODE_START_SET_NODE(node, receiver);
2957 const pm_location_t *end = pm_arguments_end(arguments);
2958 assert(end != NULL && "unreachable");
2959 PM_NODE_LENGTH_SET_LOCATION(node, end);
2961 node->receiver = receiver;
2962 node->message_loc.start = arguments->opening_loc.start;
2963 node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
2965 node->opening_loc = arguments->opening_loc;
2966 node->arguments = arguments->arguments;
2967 node->closing_loc = arguments->closing_loc;
2968 node->block = arguments->block;
2970 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2977static pm_call_node_t *
2978pm_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) {
2979 pm_assert_value_expression(parser, receiver);
2980 pm_assert_value_expression(parser, argument);
2982 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2984 PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
2985 PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
2987 node->receiver = receiver;
2988 node->message_loc = TOK2LOC(parser, operator);
2990 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2991 pm_arguments_node_arguments_append(parser->arena, arguments, argument);
2992 node->arguments = arguments;
2994 node->name = pm_parser_constant_id_token(parser, operator);
2998static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
3003static pm_call_node_t *
3004pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
3005 pm_assert_value_expression(parser, receiver);
3007 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3009 PM_NODE_START_SET_NODE(node, receiver);
3010 const pm_location_t *end = pm_arguments_end(arguments);
3012 PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
3014 PM_NODE_LENGTH_SET_LOCATION(node, end);
3017 node->receiver = receiver;
3018 node->call_operator_loc = TOK2LOC(parser, operator);
3019 node->message_loc = TOK2LOC(parser, message);
3020 node->opening_loc = arguments->opening_loc;
3021 node->arguments = arguments->arguments;
3022 node->closing_loc = arguments->closing_loc;
3023 node->block = arguments->block;
3025 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3026 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3033 node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
3040static pm_call_node_t *
3041pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
3042 pm_call_node_t *node = pm_call_node_create(parser, 0);
3043 node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
3045 node->receiver = receiver;
3046 node->arguments = arguments;
3048 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
3056static pm_call_node_t *
3057pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
3058 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3060 PM_NODE_START_SET_TOKEN(parser, node, message);
3061 const pm_location_t *end = pm_arguments_end(arguments);
3062 assert(end != NULL && "unreachable");
3063 PM_NODE_LENGTH_SET_LOCATION(node, end);
3065 node->message_loc = TOK2LOC(parser, message);
3066 node->opening_loc = arguments->opening_loc;
3067 node->arguments = arguments->arguments;
3068 node->closing_loc = arguments->closing_loc;
3069 node->block = arguments->block;
3071 node->name = pm_parser_constant_id_token(parser, message);
3079static pm_call_node_t *
3080pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
3081 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3083 node->base.location = (pm_location_t) { 0 };
3084 node->arguments = arguments;
3093static pm_call_node_t *
3094pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
3095 pm_assert_value_expression(parser, receiver);
3096 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
3098 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
3100 PM_NODE_START_SET_TOKEN(parser, node, message);
3101 if (arguments->closing_loc.length > 0) {
3102 PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
3104 assert(receiver != NULL);
3105 PM_NODE_LENGTH_SET_NODE(node, receiver);
3108 node->receiver = receiver;
3109 node->message_loc = TOK2LOC(parser, message);
3110 node->opening_loc = arguments->opening_loc;
3111 node->arguments = arguments->arguments;
3112 node->closing_loc = arguments->closing_loc;
3114 node->name = pm_parser_constant_id_constant(parser, "!", 1);
3121static pm_call_node_t *
3122pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
3123 pm_assert_value_expression(parser, receiver);
3125 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3127 PM_NODE_START_SET_NODE(node, receiver);
3128 const pm_location_t *end = pm_arguments_end(arguments);
3129 assert(end != NULL && "unreachable");
3130 PM_NODE_LENGTH_SET_LOCATION(node, end);
3132 node->receiver = receiver;
3133 node->call_operator_loc = TOK2LOC(parser, operator);
3134 node->opening_loc = arguments->opening_loc;
3135 node->arguments = arguments->arguments;
3136 node->closing_loc = arguments->closing_loc;
3137 node->block = arguments->block;
3139 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3140 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3143 node->name = pm_parser_constant_id_constant(parser, "call", 4);
3150static pm_call_node_t *
3151pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
3152 pm_assert_value_expression(parser, receiver);
3154 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3156 PM_NODE_START_SET_TOKEN(parser, node, operator);
3157 PM_NODE_LENGTH_SET_NODE(node, receiver);
3159 node->receiver = receiver;
3160 node->message_loc = TOK2LOC(parser, operator);
3162 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
3170static pm_call_node_t *
3171pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
3172 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3174 node->base.location = TOK2LOC(parser, message);
3175 node->message_loc = TOK2LOC(parser, message);
3177 node->name = pm_parser_constant_id_token(parser, message);
3185static PRISM_INLINE bool
3186pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
3188 (node->message_loc.length > 0) &&
3189 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
3190 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
3191 char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
3192 (node->opening_loc.length == 0) &&
3193 (node->arguments == NULL) &&
3194 (node->block == NULL)
3202pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
3203 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
3205 if (write_constant->length > 0) {
3206 size_t length = write_constant->length - 1;
3208 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
3209 memcpy(memory, write_constant->start, length);
3211 *read_name = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, memory, length);
3213 // We can get here if the message was missing because of a syntax error.
3214 *read_name = pm_parser_constant_id_constant(parser, "", 0);
3221static pm_call_and_write_node_t *
3222pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3223 assert(target->block == NULL);
3224 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3226 pm_call_and_write_node_t *node = pm_call_and_write_node_new(
3230 PM_LOCATION_INIT_NODES(target, value),
3232 target->call_operator_loc,
3233 target->message_loc,
3236 TOK2LOC(parser, operator),
3240 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3242 // The target is no longer necessary because we've reused its children.
3243 // It is arena-allocated so no explicit free is needed.
3253pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
3254 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
3255 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
3257 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
3258 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
3259 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
3265 if (block != NULL) {
3266 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
3274static pm_index_and_write_node_t *
3275pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3276 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3278 pm_index_arguments_check(parser, target->arguments, target->block);
3280 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3282 pm_index_and_write_node_t *node = pm_index_and_write_node_new(
3286 PM_LOCATION_INIT_NODES(target, value),
3288 target->call_operator_loc,
3289 target->opening_loc,
3291 target->closing_loc,
3292 (pm_block_argument_node_t *) target->block,
3293 TOK2LOC(parser, operator),
3297 // The target is no longer necessary because we've reused its children.
3298 // It is arena-allocated so no explicit free is needed.
3306static pm_call_operator_write_node_t *
3307pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3308 assert(target->block == NULL);
3310 pm_call_operator_write_node_t *node = pm_call_operator_write_node_new(
3314 PM_LOCATION_INIT_NODES(target, value),
3316 target->call_operator_loc,
3317 target->message_loc,
3320 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3321 TOK2LOC(parser, operator),
3325 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3327 // The target is no longer necessary because we've reused its children.
3328 // It is arena-allocated so no explicit free is needed.
3336static pm_index_operator_write_node_t *
3337pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3338 pm_index_arguments_check(parser, target->arguments, target->block);
3340 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3342 pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
3346 PM_LOCATION_INIT_NODES(target, value),
3348 target->call_operator_loc,
3349 target->opening_loc,
3351 target->closing_loc,
3352 (pm_block_argument_node_t *) target->block,
3353 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3354 TOK2LOC(parser, operator),
3358 // The target is no longer necessary because we've reused its children.
3359 // It is arena-allocated so no explicit free is needed.
3367static pm_call_or_write_node_t *
3368pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3369 assert(target->block == NULL);
3370 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3372 pm_call_or_write_node_t *node = pm_call_or_write_node_new(
3376 PM_LOCATION_INIT_NODES(target, value),
3378 target->call_operator_loc,
3379 target->message_loc,
3382 TOK2LOC(parser, operator),
3386 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3388 // The target is no longer necessary because we've reused its children.
3389 // It is arena-allocated so no explicit free is needed.
3397static pm_index_or_write_node_t *
3398pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3399 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3401 pm_index_arguments_check(parser, target->arguments, target->block);
3403 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3405 pm_index_or_write_node_t *node = pm_index_or_write_node_new(
3409 PM_LOCATION_INIT_NODES(target, value),
3411 target->call_operator_loc,
3412 target->opening_loc,
3414 target->closing_loc,
3415 (pm_block_argument_node_t *) target->block,
3416 TOK2LOC(parser, operator),
3420 // The target is no longer necessary because we've reused its children.
3421 // It is arena-allocated so no explicit free is needed.
3430static pm_call_target_node_t *
3431pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3432 pm_call_target_node_t *node = pm_call_target_node_new(
3436 PM_LOCATION_INIT_NODE(target),
3438 target->call_operator_loc,
3443 /* It is possible to get here where we have parsed an invalid syntax tree
3444 * where the call operator was not present. In that case we will have a
3445 * problem because it is a required location. In this case we need to fill
3446 * it in with a fake location so that the syntax tree remains valid. */
3447 if (node->call_operator_loc.length == 0) {
3448 node->call_operator_loc = target->base.location;
3451 // The target is no longer necessary because we've reused its children.
3452 // It is arena-allocated so no explicit free is needed.
3461static pm_index_target_node_t *
3462pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3463 pm_index_arguments_check(parser, target->arguments, target->block);
3464 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3466 pm_index_target_node_t *node = pm_index_target_node_new(
3469 FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3470 PM_LOCATION_INIT_NODE(target),
3472 target->opening_loc,
3474 target->closing_loc,
3475 (pm_block_argument_node_t *) target->block
3478 // The target is no longer necessary because we've reused its children.
3479 // It is arena-allocated so no explicit free is needed.
3487static pm_capture_pattern_node_t *
3488pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3489 return pm_capture_pattern_node_new(
3493 PM_LOCATION_INIT_NODES(value, target),
3496 TOK2LOC(parser, operator)
3503static pm_case_node_t *
3504pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3505 return pm_case_node_new(
3509 PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
3511 ((pm_node_list_t) { 0 }),
3513 TOK2LOC(parser, case_keyword),
3514 NTOK2LOC(parser, end_keyword)
3522pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
3523 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3525 pm_node_list_append(arena, &node->conditions, condition);
3526 PM_NODE_LENGTH_SET_NODE(node, condition);
3533pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3534 node->else_clause = else_clause;
3535 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3542pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
3543 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3544 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3550static pm_case_match_node_t *
3551pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
3552 return pm_case_match_node_new(
3556 PM_LOCATION_INIT_TOKEN(parser, case_keyword),
3558 ((pm_node_list_t) { 0 }),
3560 TOK2LOC(parser, case_keyword),
3561 ((pm_location_t) { 0 })
3569pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
3570 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3572 pm_node_list_append(arena, &node->conditions, condition);
3573 PM_NODE_LENGTH_SET_NODE(node, condition);
3580pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3581 node->else_clause = else_clause;
3582 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3589pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3590 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3591 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3597static pm_class_node_t *
3598pm_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) {
3599 return pm_class_node_new(
3603 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
3605 TOK2LOC(parser, class_keyword),
3607 NTOK2LOC(parser, inheritance_operator),
3610 TOK2LOC(parser, end_keyword),
3611 pm_parser_constant_id_token(parser, name)
3618static pm_class_variable_and_write_node_t *
3619pm_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) {
3620 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3622 return pm_class_variable_and_write_node_new(
3626 PM_LOCATION_INIT_NODES(target, value),
3628 target->base.location,
3629 TOK2LOC(parser, operator),
3637static pm_class_variable_operator_write_node_t *
3638pm_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) {
3639 return pm_class_variable_operator_write_node_new(
3643 PM_LOCATION_INIT_NODES(target, value),
3645 target->base.location,
3646 TOK2LOC(parser, operator),
3648 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3655static pm_class_variable_or_write_node_t *
3656pm_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) {
3657 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3659 return pm_class_variable_or_write_node_new(
3663 PM_LOCATION_INIT_NODES(target, value),
3665 target->base.location,
3666 TOK2LOC(parser, operator),
3674static pm_class_variable_read_node_t *
3675pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3676 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3678 return pm_class_variable_read_node_new(
3682 PM_LOCATION_INIT_TOKEN(parser, token),
3683 pm_parser_constant_id_token(parser, token)
3693static PRISM_INLINE pm_node_flags_t
3694pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3695 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
3704static pm_class_variable_write_node_t *
3705pm_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) {
3706 return pm_class_variable_write_node_new(
3709 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3710 PM_LOCATION_INIT_NODES(read_node, value),
3712 read_node->base.location,
3714 TOK2LOC(parser, operator)
3721static pm_constant_path_and_write_node_t *
3722pm_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) {
3723 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3725 return pm_constant_path_and_write_node_new(
3729 PM_LOCATION_INIT_NODES(target, value),
3731 TOK2LOC(parser, operator),
3739static pm_constant_path_operator_write_node_t *
3740pm_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) {
3741 return pm_constant_path_operator_write_node_new(
3745 PM_LOCATION_INIT_NODES(target, value),
3747 TOK2LOC(parser, operator),
3749 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3756static pm_constant_path_or_write_node_t *
3757pm_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) {
3758 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3760 return pm_constant_path_or_write_node_new(
3764 PM_LOCATION_INIT_NODES(target, value),
3766 TOK2LOC(parser, operator),
3774static pm_constant_path_node_t *
3775pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3776 pm_assert_value_expression(parser, parent);
3778 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3779 if (name_token->type == PM_TOKEN_CONSTANT) {
3780 name = pm_parser_constant_id_token(parser, name_token);
3783 return pm_constant_path_node_new(
3787 (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
3790 TOK2LOC(parser, delimiter),
3791 TOK2LOC(parser, name_token)
3798static pm_constant_path_write_node_t *
3799pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3800 return pm_constant_path_write_node_new(
3803 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3804 PM_LOCATION_INIT_NODES(target, value),
3806 TOK2LOC(parser, operator),
3814static pm_constant_and_write_node_t *
3815pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3816 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3818 return pm_constant_and_write_node_new(
3822 PM_LOCATION_INIT_NODES(target, value),
3824 target->base.location,
3825 TOK2LOC(parser, operator),
3833static pm_constant_operator_write_node_t *
3834pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3835 return pm_constant_operator_write_node_new(
3839 PM_LOCATION_INIT_NODES(target, value),
3841 target->base.location,
3842 TOK2LOC(parser, operator),
3844 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3851static pm_constant_or_write_node_t *
3852pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3853 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3855 return pm_constant_or_write_node_new(
3859 PM_LOCATION_INIT_NODES(target, value),
3861 target->base.location,
3862 TOK2LOC(parser, operator),
3870static pm_constant_read_node_t *
3871pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3872 assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
3874 return pm_constant_read_node_new(
3878 PM_LOCATION_INIT_TOKEN(parser, name),
3879 pm_parser_constant_id_token(parser, name)
3886static pm_constant_write_node_t *
3887pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3888 return pm_constant_write_node_new(
3891 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3892 PM_LOCATION_INIT_NODES(target, value),
3894 target->base.location,
3896 TOK2LOC(parser, operator)
3904pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3905 switch (PM_NODE_TYPE(node)) {
3906 case PM_BEGIN_NODE: {
3907 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3908 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3911 case PM_PARENTHESES_NODE: {
3912 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3913 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3916 case PM_STATEMENTS_NODE: {
3917 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3918 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3923 case PM_IMAGINARY_NODE:
3924 case PM_INTEGER_NODE:
3925 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3926 case PM_INTERPOLATED_STRING_NODE:
3927 case PM_INTERPOLATED_SYMBOL_NODE:
3928 case PM_INTERPOLATED_X_STRING_NODE:
3929 case PM_RATIONAL_NODE:
3930 case PM_REGULAR_EXPRESSION_NODE:
3931 case PM_SOURCE_ENCODING_NODE:
3932 case PM_SOURCE_FILE_NODE:
3933 case PM_SOURCE_LINE_NODE:
3934 case PM_STRING_NODE:
3935 case PM_SYMBOL_NODE:
3936 case PM_X_STRING_NODE:
3937 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3947static pm_def_node_t *
3949 pm_parser_t *parser,
3950 pm_constant_id_t name,
3951 const pm_token_t *name_loc,
3952 pm_node_t *receiver,
3953 pm_parameters_node_t *parameters,
3955 pm_constant_id_list_t *locals,
3956 const pm_token_t *def_keyword,
3957 const pm_token_t *operator,
3958 const pm_token_t *lparen,
3959 const pm_token_t *rparen,
3960 const pm_token_t *equal,
3961 const pm_token_t *end_keyword
3963 if (receiver != NULL) {
3964 pm_def_node_receiver_check(parser, receiver);
3967 return pm_def_node_new(
3971 (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
3973 TOK2LOC(parser, name_loc),
3978 TOK2LOC(parser, def_keyword),
3979 NTOK2LOC(parser, operator),
3980 NTOK2LOC(parser, lparen),
3981 NTOK2LOC(parser, rparen),
3982 NTOK2LOC(parser, equal),
3983 NTOK2LOC(parser, end_keyword)
3990static pm_defined_node_t *
3991pm_defined_node_create(pm_parser_t *parser, const pm_token_t *lparen, pm_node_t *value, const pm_token_t *rparen, const pm_token_t *keyword) {
3992 return pm_defined_node_new(
3996 (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
3997 NTOK2LOC(parser, lparen),
3999 NTOK2LOC(parser, rparen),
4000 TOK2LOC(parser, keyword)
4007static pm_else_node_t *
4008pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4009 return pm_else_node_new(
4013 ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
4014 TOK2LOC(parser, else_keyword),
4016 NTOK2LOC(parser, end_keyword)
4023static pm_embedded_statements_node_t *
4024pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
4025 return pm_embedded_statements_node_new(
4029 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4030 TOK2LOC(parser, opening),
4032 TOK2LOC(parser, closing)
4039static pm_embedded_variable_node_t *
4040pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
4041 return pm_embedded_variable_node_new(
4045 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
4046 TOK2LOC(parser, operator),
4054static pm_ensure_node_t *
4055pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4056 return pm_ensure_node_new(
4060 PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
4061 TOK2LOC(parser, ensure_keyword),
4063 TOK2LOC(parser, end_keyword)
4070static pm_false_node_t *
4071pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4072 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4074 return pm_false_node_new(
4077 PM_NODE_FLAG_STATIC_LITERAL,
4078 PM_LOCATION_INIT_TOKEN(parser, token)
4086static pm_find_pattern_node_t *
4087pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4088 assert(nodes->size >= 2);
4089 pm_node_t *left = nodes->nodes[0];
4090 pm_node_t *right = nodes->nodes[nodes->size - 1];
4092 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4093 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4095 pm_find_pattern_node_t *node = pm_find_pattern_node_new(
4099 PM_LOCATION_INIT_NODES(left, right),
4101 (pm_splat_node_t *) left,
4102 ((pm_node_list_t) { 0 }),
4103 (pm_splat_node_t *) right,
4104 ((pm_location_t) { 0 }),
4105 ((pm_location_t) { 0 })
4108 // For now we're going to just copy over each pointer manually. This could be
4109 // much more efficient, as we could instead resize the node list to only point
4111 for (size_t index = 1; index < nodes->size - 1; index++) {
4112 pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
4123pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4124 ptrdiff_t diff = token->end - token->start;
4125 if (diff <= 0) return 0.0;
4127 // First, get a buffer of the content.
4128 size_t length = (size_t) diff;
4129 const size_t buffer_size = sizeof(char) * (length + 1);
4130 char *buffer = xmalloc(buffer_size);
4131 memcpy((void *) buffer, token->start, length);
4133 // Next, determine if we need to replace the decimal point because of
4134 // locale-specific options, and then normalize them if we have to.
4135 char decimal_point = *localeconv()->decimal_point;
4136 if (decimal_point != '.') {
4137 for (size_t index = 0; index < length; index++) {
4138 if (buffer[index] == '.') buffer[index] = decimal_point;
4142 // Next, handle underscores by removing them from the buffer.
4143 for (size_t index = 0; index < length; index++) {
4144 if (buffer[index] == '_') {
4145 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4150 // Null-terminate the buffer so that strtod cannot read off the end.
4151 buffer[length] = '\0';
4153 // Now, call strtod to parse the value. Note that CRuby has their own
4154 // version of strtod which avoids locales. We're okay using the locale-aware
4155 // version because we've already validated through the parser that the token
4156 // is in a valid format.
4159 double value = strtod(buffer, &eptr);
4161 // This should never happen, because we've already checked that the token
4162 // is in a valid format. However it's good to be safe.
4163 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4164 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
4165 xfree_sized(buffer, buffer_size);
4169 // If errno is set, then it should only be ERANGE. At this point we need to
4170 // check if it's infinity (it should be).
4171 if (errno == ERANGE && PRISM_ISINF(value)) {
4173 const char *ellipsis;
4179 warn_width = (int) length;
4183 pm_diagnostic_list_append_format(&parser->metadata_arena, &parser->warning_list, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
4184 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4187 // Finally we can free the buffer and return the value.
4188 xfree_sized(buffer, buffer_size);
4195static pm_float_node_t *
4196pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4197 assert(token->type == PM_TOKEN_FLOAT);
4199 return pm_float_node_new(
4202 PM_NODE_FLAG_STATIC_LITERAL,
4203 PM_LOCATION_INIT_TOKEN(parser, token),
4204 pm_double_parse(parser, token)
4211static pm_imaginary_node_t *
4212pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4213 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4215 return pm_imaginary_node_new(
4218 PM_NODE_FLAG_STATIC_LITERAL,
4219 PM_LOCATION_INIT_TOKEN(parser, token),
4220 UP(pm_float_node_create(parser, &((pm_token_t) {
4221 .type = PM_TOKEN_FLOAT,
4222 .start = token->start,
4223 .end = token->end - 1
4231static pm_rational_node_t *
4232pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4233 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4235 pm_rational_node_t *node = pm_rational_node_new(
4238 PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4239 PM_LOCATION_INIT_TOKEN(parser, token),
4240 ((pm_integer_t) { 0 }),
4241 ((pm_integer_t) { 0 })
4244 const uint8_t *start = token->start;
4245 const uint8_t *end = token->end - 1; // r
4247 while (start < end && *start == '0') start++; // 0.1 -> .1
4248 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4250 size_t length = (size_t) (end - start);
4252 node->denominator.value = 1;
4256 const uint8_t *point = memchr(start, '.', length);
4257 assert(point && "should have a decimal point");
4259 uint8_t *digits = xmalloc(length);
4260 if (digits == NULL) {
4261 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4265 memcpy(digits, start, (unsigned long) (point - start));
4266 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4267 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4269 size_t fract_length = 0;
4270 for (const uint8_t *fract = point; fract < end; ++fract) {
4271 if (*fract != '_') ++fract_length;
4274 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
4275 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
4276 xfree_sized(digits, length);
4278 pm_integers_reduce(&node->numerator, &node->denominator);
4279 pm_integer_arena_move(parser->arena, &node->numerator);
4280 pm_integer_arena_move(parser->arena, &node->denominator);
4288static pm_imaginary_node_t *
4289pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4290 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4292 return pm_imaginary_node_new(
4295 PM_NODE_FLAG_STATIC_LITERAL,
4296 PM_LOCATION_INIT_TOKEN(parser, token),
4297 UP(pm_float_node_rational_create(parser, &((pm_token_t) {
4298 .type = PM_TOKEN_FLOAT_RATIONAL,
4299 .start = token->start,
4300 .end = token->end - 1
4308static pm_for_node_t *
4310 pm_parser_t *parser,
4312 pm_node_t *collection,
4313 pm_statements_node_t *statements,
4314 const pm_token_t *for_keyword,
4315 const pm_token_t *in_keyword,
4316 const pm_token_t *do_keyword,
4317 const pm_token_t *end_keyword
4319 return pm_for_node_new(
4323 PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
4327 TOK2LOC(parser, for_keyword),
4328 TOK2LOC(parser, in_keyword),
4329 NTOK2LOC(parser, do_keyword),
4330 TOK2LOC(parser, end_keyword)
4337static pm_forwarding_arguments_node_t *
4338pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4339 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4341 return pm_forwarding_arguments_node_new(
4345 PM_LOCATION_INIT_TOKEN(parser, token)
4352static pm_forwarding_parameter_node_t *
4353pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4354 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4356 return pm_forwarding_parameter_node_new(
4360 PM_LOCATION_INIT_TOKEN(parser, token)
4367static pm_forwarding_super_node_t *
4368pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4369 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4370 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4372 pm_block_node_t *block = NULL;
4373 if (arguments->block != NULL) {
4374 block = (pm_block_node_t *) arguments->block;
4377 return pm_forwarding_super_node_new(
4381 (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
4382 PM_LOCATION_INIT_TOKEN(parser, token),
4391static pm_hash_pattern_node_t *
4392pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4393 return pm_hash_pattern_node_new(
4397 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4399 ((pm_node_list_t) { 0 }),
4401 TOK2LOC(parser, opening),
4402 TOK2LOC(parser, closing)
4409static pm_hash_pattern_node_t *
4410pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4414 if (elements->size > 0) {
4416 start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
4417 end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
4419 start = PM_NODE_START(elements->nodes[0]);
4420 end = PM_NODE_END(elements->nodes[elements->size - 1]);
4423 assert(rest != NULL);
4424 start = PM_NODE_START(rest);
4425 end = PM_NODE_END(rest);
4428 pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
4432 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4434 ((pm_node_list_t) { 0 }),
4436 ((pm_location_t) { 0 }),
4437 ((pm_location_t) { 0 })
4440 pm_node_list_concat(parser->arena, &node->elements, elements);
4447static pm_constant_id_t
4448pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4449 switch (PM_NODE_TYPE(target)) {
4450 case PM_GLOBAL_VARIABLE_READ_NODE:
4451 return ((pm_global_variable_read_node_t *) target)->name;
4452 case PM_BACK_REFERENCE_READ_NODE:
4453 return ((pm_back_reference_read_node_t *) target)->name;
4454 case PM_NUMBERED_REFERENCE_READ_NODE:
4455 // This will only ever happen in the event of a syntax error, but we
4456 // still need to provide something for the node.
4457 return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
4459 assert(false && "unreachable");
4460 return (pm_constant_id_t) -1;
4467static pm_global_variable_and_write_node_t *
4468pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4469 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4471 return pm_global_variable_and_write_node_new(
4475 PM_LOCATION_INIT_NODES(target, value),
4476 pm_global_variable_write_name(parser, target),
4478 TOK2LOC(parser, operator),
4486static pm_global_variable_operator_write_node_t *
4487pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4488 return pm_global_variable_operator_write_node_new(
4492 PM_LOCATION_INIT_NODES(target, value),
4493 pm_global_variable_write_name(parser, target),
4495 TOK2LOC(parser, operator),
4497 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4504static pm_global_variable_or_write_node_t *
4505pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4506 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4508 return pm_global_variable_or_write_node_new(
4512 PM_LOCATION_INIT_NODES(target, value),
4513 pm_global_variable_write_name(parser, target),
4515 TOK2LOC(parser, operator),
4523static pm_global_variable_read_node_t *
4524pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4525 return pm_global_variable_read_node_new(
4529 PM_LOCATION_INIT_TOKEN(parser, name),
4530 pm_parser_constant_id_token(parser, name)
4537static pm_global_variable_read_node_t *
4538pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4539 return pm_global_variable_read_node_new(
4543 PM_LOCATION_INIT_UNSET,
4551static pm_global_variable_write_node_t *
4552pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4553 return pm_global_variable_write_node_new(
4556 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4557 PM_LOCATION_INIT_NODES(target, value),
4558 pm_global_variable_write_name(parser, target),
4561 TOK2LOC(parser, operator)
4568static pm_global_variable_write_node_t *
4569pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4570 return pm_global_variable_write_node_new(
4574 PM_LOCATION_INIT_UNSET,
4576 ((pm_location_t) { 0 }),
4578 ((pm_location_t) { 0 })
4585static pm_hash_node_t *
4586pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4587 assert(opening != NULL);
4589 return pm_hash_node_new(
4592 PM_NODE_FLAG_STATIC_LITERAL,
4593 PM_LOCATION_INIT_TOKEN(parser, opening),
4594 TOK2LOC(parser, opening),
4595 ((pm_node_list_t) { 0 }),
4596 ((pm_location_t) { 0 })
4603static PRISM_INLINE void
4604pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
4605 pm_node_list_append(arena, &hash->elements, element);
4607 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4608 if (static_literal) {
4609 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4610 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);
4611 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4612 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4615 if (!static_literal) {
4616 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4620static PRISM_INLINE void
4621pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
4622 PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
4623 hash->closing_loc = TOK2LOC(parser, token);
4629static pm_if_node_t *
4630pm_if_node_create(pm_parser_t *parser,
4631 const pm_token_t *if_keyword,
4632 pm_node_t *predicate,
4633 const pm_token_t *then_keyword,
4634 pm_statements_node_t *statements,
4635 pm_node_t *subsequent,
4636 const pm_token_t *end_keyword
4638 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4640 uint32_t start = PM_TOKEN_START(parser, if_keyword);
4643 if (end_keyword != NULL) {
4644 end = PM_TOKEN_END(parser, end_keyword);
4645 } else if (subsequent != NULL) {
4646 end = PM_NODE_END(subsequent);
4647 } else if (pm_statements_node_body_length(statements) != 0) {
4648 end = PM_NODE_END(statements);
4650 end = PM_NODE_END(predicate);
4653 return pm_if_node_new(
4656 PM_NODE_FLAG_NEWLINE,
4657 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4658 TOK2LOC(parser, if_keyword),
4660 NTOK2LOC(parser, then_keyword),
4663 NTOK2LOC(parser, end_keyword)
4670static pm_if_node_t *
4671pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4672 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4674 pm_statements_node_t *statements = pm_statements_node_create(parser);
4675 pm_statements_node_body_append(parser, statements, statement, true);
4677 return pm_if_node_new(
4680 PM_NODE_FLAG_NEWLINE,
4681 PM_LOCATION_INIT_NODES(statement, predicate),
4682 TOK2LOC(parser, if_keyword),
4684 ((pm_location_t) { 0 }),
4687 ((pm_location_t) { 0 })
4694static pm_if_node_t *
4695pm_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) {
4696 pm_assert_value_expression(parser, predicate);
4697 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4699 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4700 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4702 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4703 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4705 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
4706 return pm_if_node_new(
4709 PM_NODE_FLAG_NEWLINE,
4710 PM_LOCATION_INIT_NODES(predicate, false_expression),
4711 ((pm_location_t) { 0 }),
4713 TOK2LOC(parser, qmark),
4716 ((pm_location_t) { 0 })
4720static PRISM_INLINE void
4721pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
4722 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4723 node->end_keyword_loc = TOK2LOC(parser, keyword);
4726static PRISM_INLINE void
4727pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
4728 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4729 node->end_keyword_loc = TOK2LOC(parser, keyword);
4735static pm_implicit_node_t *
4736pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4737 return pm_implicit_node_new(
4741 PM_LOCATION_INIT_NODE(value),
4749static pm_implicit_rest_node_t *
4750pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4751 assert(token->type == PM_TOKEN_COMMA);
4753 return pm_implicit_rest_node_new(
4757 PM_LOCATION_INIT_TOKEN(parser, token)
4764static pm_integer_node_t *
4765pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4766 assert(token->type == PM_TOKEN_INTEGER);
4768 pm_integer_node_t *node = pm_integer_node_new(
4771 base | PM_NODE_FLAG_STATIC_LITERAL,
4772 PM_LOCATION_INIT_TOKEN(parser, token),
4773 ((pm_integer_t) { 0 })
4776 if (parser->integer.lexed) {
4777 // The value was already computed during lexing.
4778 node->value.value = parser->integer.value;
4779 parser->integer.lexed = false;
4781 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4783 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4784 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4785 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4786 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4787 default: assert(false && "unreachable"); break;
4790 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4791 pm_integer_arena_move(parser->arena, &node->value);
4801static pm_imaginary_node_t *
4802pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4803 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4805 return pm_imaginary_node_new(
4808 PM_NODE_FLAG_STATIC_LITERAL,
4809 PM_LOCATION_INIT_TOKEN(parser, token),
4810 UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4811 .type = PM_TOKEN_INTEGER,
4812 .start = token->start,
4813 .end = token->end - 1
4822static pm_rational_node_t *
4823pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4824 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4826 pm_rational_node_t *node = pm_rational_node_new(
4829 base | PM_NODE_FLAG_STATIC_LITERAL,
4830 PM_LOCATION_INIT_TOKEN(parser, token),
4831 ((pm_integer_t) { 0 }),
4832 ((pm_integer_t) { .value = 1 })
4835 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4837 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4838 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4839 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4840 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4841 default: assert(false && "unreachable"); break;
4844 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4845 pm_integer_arena_move(parser->arena, &node->numerator);
4854static pm_imaginary_node_t *
4855pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4856 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4858 return pm_imaginary_node_new(
4861 PM_NODE_FLAG_STATIC_LITERAL,
4862 PM_LOCATION_INIT_TOKEN(parser, token),
4863 UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4864 .type = PM_TOKEN_INTEGER_RATIONAL,
4865 .start = token->start,
4866 .end = token->end - 1
4874static pm_in_node_t *
4875pm_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) {
4876 uint32_t start = PM_TOKEN_START(parser, in_keyword);
4879 if (statements != NULL) {
4880 end = PM_NODE_END(statements);
4881 } else if (then_keyword != NULL) {
4882 end = PM_TOKEN_END(parser, then_keyword);
4884 end = PM_NODE_END(pattern);
4887 return pm_in_node_new(
4891 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4894 TOK2LOC(parser, in_keyword),
4895 NTOK2LOC(parser, then_keyword)
4902static pm_instance_variable_and_write_node_t *
4903pm_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) {
4904 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4906 return pm_instance_variable_and_write_node_new(
4910 PM_LOCATION_INIT_NODES(target, value),
4912 target->base.location,
4913 TOK2LOC(parser, operator),
4921static pm_instance_variable_operator_write_node_t *
4922pm_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) {
4923 return pm_instance_variable_operator_write_node_new(
4927 PM_LOCATION_INIT_NODES(target, value),
4929 target->base.location,
4930 TOK2LOC(parser, operator),
4932 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4939static pm_instance_variable_or_write_node_t *
4940pm_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) {
4941 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4943 return pm_instance_variable_or_write_node_new(
4947 PM_LOCATION_INIT_NODES(target, value),
4949 target->base.location,
4950 TOK2LOC(parser, operator),
4958static pm_instance_variable_read_node_t *
4959pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4960 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4962 return pm_instance_variable_read_node_new(
4966 PM_LOCATION_INIT_TOKEN(parser, token),
4967 pm_parser_constant_id_token(parser, token)
4975static pm_instance_variable_write_node_t *
4976pm_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) {
4977 return pm_instance_variable_write_node_new(
4980 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4981 PM_LOCATION_INIT_NODES(read_node, value),
4983 read_node->base.location,
4985 TOK2LOC(parser, operator)
4995pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4996 switch (PM_NODE_TYPE(part)) {
4997 case PM_STRING_NODE:
4998 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5000 case PM_EMBEDDED_STATEMENTS_NODE: {
5001 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5002 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5004 if (embedded == NULL) {
5005 // If there are no statements or more than one statement, then
5006 // we lose the static literal flag.
5007 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5008 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5009 // If the embedded statement is a string, then we can keep the
5010 // static literal flag and mark the string as frozen.
5011 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5012 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5013 // If the embedded statement is an interpolated string and it's
5014 // a static literal, then we can keep the static literal flag.
5016 // Otherwise we lose the static literal flag.
5017 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5022 case PM_EMBEDDED_VARIABLE_NODE:
5023 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5026 assert(false && "unexpected node type");
5030 pm_node_list_append(arena, parts, part);
5036static pm_interpolated_regular_expression_node_t *
5037pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5038 return pm_interpolated_regular_expression_node_new(
5041 PM_NODE_FLAG_STATIC_LITERAL,
5042 PM_LOCATION_INIT_TOKEN(parser, opening),
5043 TOK2LOC(parser, opening),
5044 ((pm_node_list_t) { 0 }),
5045 TOK2LOC(parser, opening)
5049static PRISM_INLINE void
5050pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5051 if (PM_NODE_START(node) > PM_NODE_START(part)) {
5052 PM_NODE_START_SET_NODE(node, part);
5054 if (PM_NODE_END(node) < PM_NODE_END(part)) {
5055 PM_NODE_LENGTH_SET_NODE(node, part);
5058 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5061static PRISM_INLINE void
5062pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5063 node->closing_loc = TOK2LOC(parser, closing);
5064 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5065 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
5091static PRISM_INLINE void
5092pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
5093 pm_arena_t *arena = parser->arena;
5094#define CLEAR_FLAGS(node) \
5095 node->base.flags = (pm_node_flags_t) (FL(node) & ~(PM_NODE_FLAG_STATIC_LITERAL | PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE))
5097#define MUTABLE_FLAGS(node) \
5098 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5100 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5101 PM_NODE_START_SET_NODE(node, part);
5104 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5105 PM_NODE_LENGTH_SET_NODE(node, part);
5108 switch (PM_NODE_TYPE(part)) {
5109 case PM_STRING_NODE:
5110 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5111 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5112 // as long as this interpolation only consists of other string literals.
5113 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5114 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5116 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5118 case PM_INTERPOLATED_STRING_NODE:
5119 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5120 // If the string that we're concatenating is a static literal,
5121 // then we can keep the static literal flag for this string.
5123 // Otherwise, we lose the static literal flag here and we should
5124 // also clear the mutability flags.
5128 case PM_EMBEDDED_STATEMENTS_NODE: {
5129 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5130 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5132 if (embedded == NULL) {
5133 // If we're embedding multiple statements or no statements, then
5134 // the string is not longer a static literal.
5136 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5137 // If the embedded statement is a string, then we can make that
5138 // string as frozen and static literal, and not touch the static
5139 // literal status of this string.
5140 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5142 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5143 MUTABLE_FLAGS(node);
5145 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5146 // If the embedded statement is an interpolated string, but that
5147 // string is marked as static literal, then we can keep our
5148 // static literal status for this string.
5149 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5150 MUTABLE_FLAGS(node);
5153 // In all other cases, we lose the static literal flag here and
5160 case PM_EMBEDDED_VARIABLE_NODE:
5161 // Embedded variables clear static literal, which means we also
5162 // should clear the mutability flags.
5165 case PM_X_STRING_NODE:
5166 case PM_INTERPOLATED_X_STRING_NODE:
5167 case PM_SYMBOL_NODE:
5168 case PM_INTERPOLATED_SYMBOL_NODE:
5169 // These will only happen in error cases. But we want to handle it
5170 // here so that we don't fail the assertion.
5172 pm_node_list_append(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
5174 case PM_ERROR_RECOVERY_NODE:
5178 assert(false && "unexpected node type");
5182 pm_node_list_append(arena, &node->parts, part);
5191static pm_interpolated_string_node_t *
5192pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5193 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5195 switch (parser->frozen_string_literal) {
5196 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5197 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5199 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5200 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5204 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5205 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5207 pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
5211 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5212 NTOK2LOC(parser, opening),
5213 ((pm_node_list_t) { 0 }),
5214 NTOK2LOC(parser, closing)
5217 if (parts != NULL) {
5219 PM_NODE_LIST_FOREACH(parts, index, part) {
5220 pm_interpolated_string_node_append(parser, node, part);
5231pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5232 node->closing_loc = TOK2LOC(parser, closing);
5233 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5237pm_interpolated_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5238 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5239 PM_NODE_START_SET_NODE(node, part);
5242 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5244 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5245 PM_NODE_LENGTH_SET_NODE(node, part);
5250pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5251 node->closing_loc = TOK2LOC(parser, closing);
5252 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5258static pm_interpolated_symbol_node_t *
5259pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5260 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5261 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5263 pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
5266 PM_NODE_FLAG_STATIC_LITERAL,
5267 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5268 NTOK2LOC(parser, opening),
5269 ((pm_node_list_t) { 0 }),
5270 NTOK2LOC(parser, closing)
5273 if (parts != NULL) {
5275 PM_NODE_LIST_FOREACH(parts, index, part) {
5276 pm_interpolated_symbol_node_append(parser->arena, node, part);
5286static pm_interpolated_x_string_node_t *
5287pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5288 return pm_interpolated_x_string_node_new(
5292 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5293 TOK2LOC(parser, opening),
5294 ((pm_node_list_t) { 0 }),
5295 TOK2LOC(parser, closing)
5299static PRISM_INLINE void
5300pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5301 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5302 PM_NODE_LENGTH_SET_NODE(node, part);
5305static PRISM_INLINE void
5306pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5307 node->closing_loc = TOK2LOC(parser, closing);
5308 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5314static pm_it_local_variable_read_node_t *
5315pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5316 return pm_it_local_variable_read_node_new(
5320 PM_LOCATION_INIT_TOKEN(parser, name)
5327static pm_it_parameters_node_t *
5328pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5329 return pm_it_parameters_node_new(
5333 PM_LOCATION_INIT_TOKENS(parser, opening, closing)
5340static pm_keyword_hash_node_t *
5341pm_keyword_hash_node_create(pm_parser_t *parser) {
5342 return pm_keyword_hash_node_new(
5345 PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5346 PM_LOCATION_INIT_UNSET,
5347 ((pm_node_list_t) { 0 })
5355pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *hash, pm_node_t *element) {
5356 // If the element being added is not an AssocNode or does not have a symbol
5357 // key, then we want to turn the SYMBOL_KEYS flag off.
5358 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5359 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5362 pm_node_list_append(arena, &hash->elements, element);
5363 if (PM_NODE_LENGTH(hash) == 0) {
5364 PM_NODE_START_SET_NODE(hash, element);
5366 PM_NODE_LENGTH_SET_NODE(hash, element);
5372static pm_required_keyword_parameter_node_t *
5373pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5374 return pm_required_keyword_parameter_node_new(
5378 PM_LOCATION_INIT_TOKEN(parser, name),
5379 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5380 TOK2LOC(parser, name)
5387static pm_optional_keyword_parameter_node_t *
5388pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5389 return pm_optional_keyword_parameter_node_new(
5393 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5394 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5395 TOK2LOC(parser, name),
5403static pm_keyword_rest_parameter_node_t *
5404pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5405 return pm_keyword_rest_parameter_node_new(
5409 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
5410 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
5411 NTOK2LOC(parser, name),
5412 TOK2LOC(parser, operator)
5419static pm_lambda_node_t *
5420pm_lambda_node_create(
5421 pm_parser_t *parser,
5422 pm_constant_id_list_t *locals,
5423 const pm_token_t *operator,
5424 const pm_token_t *opening,
5425 const pm_token_t *closing,
5426 pm_node_t *parameters,
5429 return pm_lambda_node_new(
5433 PM_LOCATION_INIT_TOKENS(parser, operator, closing),
5435 TOK2LOC(parser, operator),
5436 TOK2LOC(parser, opening),
5437 TOK2LOC(parser, closing),
5446static pm_local_variable_and_write_node_t *
5447pm_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) {
5448 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));
5449 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5451 return pm_local_variable_and_write_node_new(
5455 PM_LOCATION_INIT_NODES(target, value),
5457 TOK2LOC(parser, operator),
5467static pm_local_variable_operator_write_node_t *
5468pm_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) {
5469 return pm_local_variable_operator_write_node_new(
5473 PM_LOCATION_INIT_NODES(target, value),
5475 TOK2LOC(parser, operator),
5478 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
5486static pm_local_variable_or_write_node_t *
5487pm_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) {
5488 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));
5489 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5491 return pm_local_variable_or_write_node_new(
5495 PM_LOCATION_INIT_NODES(target, value),
5497 TOK2LOC(parser, operator),
5507static pm_local_variable_read_node_t *
5508pm_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) {
5509 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5511 return pm_local_variable_read_node_new(
5515 PM_LOCATION_INIT_TOKEN(parser, name),
5524static pm_local_variable_read_node_t *
5525pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5526 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5527 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5534static pm_local_variable_read_node_t *
5535pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5536 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5537 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5543static pm_local_variable_write_node_t *
5544pm_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) {
5545 return pm_local_variable_write_node_new(
5548 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5549 ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
5554 TOK2LOC(parser, operator)
5561static PRISM_INLINE bool
5562pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5563 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5570static PRISM_INLINE bool
5571pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
5574 (parser->start[start] == '_') &&
5575 (parser->start[start + 1] != '0') &&
5576 pm_char_is_decimal_digit(parser->start[start + 1])
5584static PRISM_INLINE void
5585pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
5586 if (pm_token_is_numbered_parameter(parser, start, length)) {
5587 PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
5595static pm_local_variable_target_node_t *
5596pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5597 pm_refute_numbered_parameter(parser, location->start, location->length);
5599 return pm_local_variable_target_node_new(
5603 ((pm_location_t) { .start = location->start, .length = location->length }),
5612static pm_match_predicate_node_t *
5613pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5614 pm_assert_value_expression(parser, value);
5616 return pm_match_predicate_node_new(
5620 PM_LOCATION_INIT_NODES(value, pattern),
5623 TOK2LOC(parser, operator)
5630static pm_match_required_node_t *
5631pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5632 pm_assert_value_expression(parser, value);
5634 return pm_match_required_node_new(
5638 PM_LOCATION_INIT_NODES(value, pattern),
5641 TOK2LOC(parser, operator)
5648static pm_match_write_node_t *
5649pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5650 return pm_match_write_node_new(
5654 PM_LOCATION_INIT_NODE(call),
5656 ((pm_node_list_t) { 0 })
5663static pm_module_node_t *
5664pm_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) {
5665 return pm_module_node_new(
5669 PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
5670 (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5671 TOK2LOC(parser, module_keyword),
5674 TOK2LOC(parser, end_keyword),
5675 pm_parser_constant_id_token(parser, name)
5682static pm_multi_target_node_t *
5683pm_multi_target_node_create(pm_parser_t *parser) {
5684 return pm_multi_target_node_new(
5688 PM_LOCATION_INIT_UNSET,
5689 ((pm_node_list_t) { 0 }),
5691 ((pm_node_list_t) { 0 }),
5692 ((pm_location_t) { 0 }),
5693 ((pm_location_t) { 0 })
5701pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5702 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5703 if (node->rest == NULL) {
5704 node->rest = target;
5706 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5707 pm_node_list_append(parser->arena, &node->rights, target);
5709 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5710 if (node->rest == NULL) {
5711 node->rest = target;
5713 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5714 pm_node_list_append(parser->arena, &node->rights, target);
5716 } else if (node->rest == NULL) {
5717 pm_node_list_append(parser->arena, &node->lefts, target);
5719 pm_node_list_append(parser->arena, &node->rights, target);
5722 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
5723 PM_NODE_START_SET_NODE(node, target);
5726 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
5727 PM_NODE_LENGTH_SET_NODE(node, target);
5735pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
5736 PM_NODE_START_SET_TOKEN(parser, node, lparen);
5737 PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
5738 node->lparen_loc = TOK2LOC(parser, lparen);
5745pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
5746 PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
5747 node->rparen_loc = TOK2LOC(parser, rparen);
5753static pm_multi_write_node_t *
5754pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5755 /* The target is no longer necessary because we have reused its children. It
5756 * is arena-allocated so no explicit free is needed. */
5757 return pm_multi_write_node_new(
5760 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5761 PM_LOCATION_INIT_NODES(target, value),
5767 TOK2LOC(parser, operator),
5775static pm_next_node_t *
5776pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5777 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5779 return pm_next_node_new(
5783 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
5785 TOK2LOC(parser, keyword)
5792static pm_nil_node_t *
5793pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5794 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5796 return pm_nil_node_new(
5799 PM_NODE_FLAG_STATIC_LITERAL,
5800 PM_LOCATION_INIT_TOKEN(parser, token)
5807static pm_no_block_parameter_node_t *
5808pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5809 assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5810 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5812 return pm_no_block_parameter_node_new(
5816 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5817 TOK2LOC(parser, operator),
5818 TOK2LOC(parser, keyword)
5825static pm_no_keywords_parameter_node_t *
5826pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5827 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5828 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5830 return pm_no_keywords_parameter_node_new(
5834 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5835 TOK2LOC(parser, operator),
5836 TOK2LOC(parser, keyword)
5843static pm_numbered_parameters_node_t *
5844pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
5845 return pm_numbered_parameters_node_new(
5849 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5858#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5867pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5868 const uint8_t *start = token->start + 1;
5869 const uint8_t *end = token->end;
5871 ptrdiff_t diff = end - start;
5873#if PTRDIFF_MAX > SIZE_MAX
5874 assert(diff < (ptrdiff_t) SIZE_MAX);
5876 size_t length = (size_t) diff;
5878 char *digits = xcalloc(length + 1, sizeof(char));
5879 memcpy(digits, start, length);
5880 digits[length] = '\0';
5884 unsigned long value = strtoul(digits, &endptr, 10);
5886 if ((digits == endptr) || (*endptr != '\0')) {
5887 pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
5891 xfree_sized(digits, sizeof(char) * (length + 1));
5893 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5894 PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5898 return (uint32_t) value;
5906static pm_numbered_reference_read_node_t *
5907pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5908 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5910 return pm_numbered_reference_read_node_new(
5914 PM_LOCATION_INIT_TOKEN(parser, name),
5915 pm_numbered_reference_read_node_number(parser, name)
5922static pm_optional_parameter_node_t *
5923pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5924 return pm_optional_parameter_node_new(
5928 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5929 pm_parser_constant_id_token(parser, name),
5930 TOK2LOC(parser, name),
5931 TOK2LOC(parser, operator),
5939static pm_or_node_t *
5940pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5941 pm_assert_value_expression(parser, left);
5943 return pm_or_node_new(
5947 PM_LOCATION_INIT_NODES(left, right),
5950 TOK2LOC(parser, operator)
5957static pm_parameters_node_t *
5958pm_parameters_node_create(pm_parser_t *parser) {
5959 return pm_parameters_node_new(
5963 PM_LOCATION_INIT_UNSET,
5964 ((pm_node_list_t) { 0 }),
5965 ((pm_node_list_t) { 0 }),
5967 ((pm_node_list_t) { 0 }),
5968 ((pm_node_list_t) { 0 }),
5978pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5979 if ((params->base.location.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
5980 PM_NODE_START_SET_NODE(params, param);
5983 if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
5984 PM_NODE_LENGTH_SET_NODE(params, param);
5992pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
5993 pm_parameters_node_location_set(params, param);
5994 pm_node_list_append(arena, ¶ms->requireds, param);
6001pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6002 pm_parameters_node_location_set(params, UP(param));
6003 pm_node_list_append(arena, ¶ms->optionals, UP(param));
6010pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6011 pm_parameters_node_location_set(params, param);
6012 pm_node_list_append(arena, ¶ms->posts, param);
6019pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6020 pm_parameters_node_location_set(params, param);
6021 params->rest = param;
6028pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6029 pm_parameters_node_location_set(params, param);
6030 pm_node_list_append(arena, ¶ms->keywords, param);
6037pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6038 assert(params->keyword_rest == NULL);
6039 pm_parameters_node_location_set(params, param);
6040 params->keyword_rest = param;
6047pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
6048 assert(params->block == NULL);
6049 pm_parameters_node_location_set(params, param);
6050 params->block = param;
6056static pm_program_node_t *
6057pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6058 return pm_program_node_new(
6062 PM_LOCATION_INIT_NODE(statements),
6071static pm_parentheses_node_t *
6072pm_parentheses_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_node_t *body, const pm_token_t *closing, pm_node_flags_t flags) {
6073 return pm_parentheses_node_new(
6077 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6079 TOK2LOC(parser, opening),
6080 TOK2LOC(parser, closing)
6087static pm_pinned_expression_node_t *
6088pm_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) {
6089 return pm_pinned_expression_node_new(
6093 PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
6095 TOK2LOC(parser, operator),
6096 TOK2LOC(parser, lparen),
6097 TOK2LOC(parser, rparen)
6104static pm_pinned_variable_node_t *
6105pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6106 return pm_pinned_variable_node_new(
6110 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
6112 TOK2LOC(parser, operator)
6119static pm_post_execution_node_t *
6120pm_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) {
6121 return pm_post_execution_node_new(
6125 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6127 TOK2LOC(parser, keyword),
6128 TOK2LOC(parser, opening),
6129 TOK2LOC(parser, closing)
6136static pm_pre_execution_node_t *
6137pm_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) {
6138 return pm_pre_execution_node_new(
6142 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6144 TOK2LOC(parser, keyword),
6145 TOK2LOC(parser, opening),
6146 TOK2LOC(parser, closing)
6153static pm_range_node_t *
6154pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6155 pm_assert_value_expression(parser, left);
6156 pm_assert_value_expression(parser, right);
6157 pm_node_flags_t flags = 0;
6159 // Indicate that this node is an exclusive range if the operator is `...`.
6160 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6161 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6164 // Indicate that this node is a static literal (i.e., can be compiled with
6165 // a putobject in CRuby) if the left and right are implicit nil, explicit
6166 // nil, or integers.
6168 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6169 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6171 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6174 uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
6175 uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
6177 return pm_range_node_new(
6181 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6184 TOK2LOC(parser, operator)
6191static pm_redo_node_t *
6192pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6193 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6195 return pm_redo_node_new(
6199 PM_LOCATION_INIT_TOKEN(parser, token)
6207static pm_regular_expression_node_t *
6208pm_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) {
6209 return pm_regular_expression_node_new(
6212 pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6213 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6214 TOK2LOC(parser, opening),
6215 TOK2LOC(parser, content),
6216 TOK2LOC(parser, closing),
6224static PRISM_INLINE pm_regular_expression_node_t *
6225pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6226 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6232static pm_required_parameter_node_t *
6233pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6234 return pm_required_parameter_node_new(
6238 PM_LOCATION_INIT_TOKEN(parser, token),
6239 pm_parser_constant_id_token(parser, token)
6246static pm_rescue_modifier_node_t *
6247pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6248 return pm_rescue_modifier_node_new(
6252 PM_LOCATION_INIT_NODES(expression, rescue_expression),
6254 TOK2LOC(parser, keyword),
6262static pm_rescue_node_t *
6263pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6264 return pm_rescue_node_new(
6268 PM_LOCATION_INIT_TOKEN(parser, keyword),
6269 TOK2LOC(parser, keyword),
6270 ((pm_node_list_t) { 0 }),
6271 ((pm_location_t) { 0 }),
6273 ((pm_location_t) { 0 }),
6279static PRISM_INLINE void
6280pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
6281 node->operator_loc = TOK2LOC(parser, operator);
6288pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6289 node->reference = reference;
6290 PM_NODE_LENGTH_SET_NODE(node, reference);
6297pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6298 node->statements = statements;
6299 if (pm_statements_node_body_length(statements) > 0) {
6300 PM_NODE_LENGTH_SET_NODE(node, statements);
6308pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6309 node->subsequent = subsequent;
6310 PM_NODE_LENGTH_SET_NODE(node, subsequent);
6317pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
6318 pm_node_list_append(arena, &node->exceptions, exception);
6319 PM_NODE_LENGTH_SET_NODE(node, exception);
6325static pm_rest_parameter_node_t *
6326pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6327 return pm_rest_parameter_node_new(
6331 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
6332 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
6333 NTOK2LOC(parser, name),
6334 TOK2LOC(parser, operator)
6341static pm_retry_node_t *
6342pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6343 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6345 return pm_retry_node_new(
6349 PM_LOCATION_INIT_TOKEN(parser, token)
6356static pm_return_node_t *
6357pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6358 return pm_return_node_new(
6362 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
6363 TOK2LOC(parser, keyword),
6371static pm_self_node_t *
6372pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6373 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6375 return pm_self_node_new(
6379 PM_LOCATION_INIT_TOKEN(parser, token)
6386static pm_shareable_constant_node_t *
6387pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6388 return pm_shareable_constant_node_new(
6391 (pm_node_flags_t) value,
6392 PM_LOCATION_INIT_NODE(write),
6400static pm_singleton_class_node_t *
6401pm_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) {
6402 return pm_singleton_class_node_new(
6406 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
6408 TOK2LOC(parser, class_keyword),
6409 TOK2LOC(parser, operator),
6412 TOK2LOC(parser, end_keyword)
6419static pm_source_encoding_node_t *
6420pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6421 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6423 return pm_source_encoding_node_new(
6426 PM_NODE_FLAG_STATIC_LITERAL,
6427 PM_LOCATION_INIT_TOKEN(parser, token)
6434static pm_source_file_node_t*
6435pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6436 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6438 pm_node_flags_t flags = 0;
6440 switch (parser->frozen_string_literal) {
6441 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6442 flags |= PM_STRING_FLAGS_MUTABLE;
6444 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6445 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6449 return pm_source_file_node_new(
6453 PM_LOCATION_INIT_TOKEN(parser, file_keyword),
6461static pm_source_line_node_t *
6462pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6463 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6465 return pm_source_line_node_new(
6468 PM_NODE_FLAG_STATIC_LITERAL,
6469 PM_LOCATION_INIT_TOKEN(parser, token)
6476static pm_splat_node_t *
6477pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6478 return pm_splat_node_new(
6482 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
6483 TOK2LOC(parser, operator),
6491static pm_statements_node_t *
6492pm_statements_node_create(pm_parser_t *parser) {
6493 return pm_statements_node_new(
6497 PM_LOCATION_INIT_UNSET,
6498 ((pm_node_list_t) { 0 })
6506pm_statements_node_body_length(pm_statements_node_t *node) {
6507 return node && node->body.size;
6514static PRISM_INLINE void
6515pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6516 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6517 PM_NODE_START_SET_NODE(node, statement);
6520 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6521 PM_NODE_LENGTH_SET_NODE(node, statement);
6529pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6530 pm_statements_node_body_update(node, statement);
6532 if (node->body.size > 0) {
6533 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6535 switch (PM_NODE_TYPE(previous)) {
6540 case PM_RETURN_NODE:
6541 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6548 pm_node_list_append(parser->arena, &node->body, statement);
6549 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6556pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
6557 pm_statements_node_body_update(node, statement);
6558 pm_node_list_prepend(arena, &node->body, statement);
6559 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6565static PRISM_INLINE pm_string_node_t *
6566pm_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) {
6567 pm_node_flags_t flags = 0;
6569 switch (parser->frozen_string_literal) {
6570 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6571 flags = PM_STRING_FLAGS_MUTABLE;
6573 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6574 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6578 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6579 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6581 return pm_string_node_new(
6585 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6586 NTOK2LOC(parser, opening),
6587 TOK2LOC(parser, content),
6588 NTOK2LOC(parser, closing),
6596static pm_string_node_t *
6597pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6598 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6605static pm_string_node_t *
6606pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6607 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6608 parser->current_string = PM_STRING_EMPTY;
6615static pm_super_node_t *
6616pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6617 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6619 const pm_location_t *end = pm_arguments_end(arguments);
6620 assert(end != NULL && "unreachable");
6622 return pm_super_node_new(
6626 ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
6627 TOK2LOC(parser, keyword),
6628 arguments->opening_loc,
6629 arguments->arguments,
6630 arguments->closing_loc,
6640pm_ascii_only_p(const pm_string_t *contents) {
6641 const size_t length = pm_string_length(contents);
6642 const uint8_t *source = pm_string_source(contents);
6644 for (size_t index = 0; index < length; index++) {
6645 if (source[index] & 0x80) return false;
6655parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6656 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6657 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6660 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6673parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6674 const pm_encoding_t *encoding = parser->encoding;
6676 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6677 size_t width = encoding->char_width(cursor, end - cursor);
6680 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6697static PRISM_INLINE pm_node_flags_t
6698parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6699 if (parser->explicit_encoding != NULL) {
6700 // A Symbol may optionally have its encoding explicitly set. This will
6701 // happen if an escape sequence results in a non-ASCII code point.
6702 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6703 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6704 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6705 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6706 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6707 } else if (validate) {
6708 parse_symbol_encoding_validate_other(parser, location, contents);
6710 } else if (pm_ascii_only_p(contents)) {
6711 // Ruby stipulates that all source files must use an ASCII-compatible
6712 // encoding. Thus, all symbols appearing in source are eligible for
6713 // "downgrading" to US-ASCII.
6714 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6715 } else if (validate) {
6716 parse_symbol_encoding_validate_other(parser, location, contents);
6726static pm_symbol_node_t *
6727pm_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) {
6728 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6729 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6731 return pm_symbol_node_new(
6734 PM_NODE_FLAG_STATIC_LITERAL | flags,
6735 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6736 NTOK2LOC(parser, opening),
6737 NTOK2LOC(parser, value),
6738 NTOK2LOC(parser, closing),
6746static PRISM_INLINE pm_symbol_node_t *
6747pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6748 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6754static pm_symbol_node_t *
6755pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6756 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));
6757 parser->current_string = PM_STRING_EMPTY;
6764static pm_symbol_node_t *
6765pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6766 assert(token->type == PM_TOKEN_LABEL);
6768 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6769 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6770 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6772 assert((label.end - label.start) >= 0);
6773 pm_string_shared_init(&node->unescaped, label.start, label.end);
6774 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
6782static pm_symbol_node_t *
6783pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6784 pm_symbol_node_t *node = pm_symbol_node_new(
6787 PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
6788 PM_LOCATION_INIT_UNSET,
6789 ((pm_location_t) { 0 }),
6790 ((pm_location_t) { 0 }),
6791 ((pm_location_t) { 0 }),
6792 ((pm_string_t) { 0 })
6795 pm_string_constant_init(&node->unescaped, content, strlen(content));
6803pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6804 const pm_location_t *location = NULL;
6806 switch (PM_NODE_TYPE(node)) {
6807 case PM_SYMBOL_NODE: {
6808 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6809 if (cast->closing_loc.length > 0) {
6810 location = &cast->closing_loc;
6814 case PM_INTERPOLATED_SYMBOL_NODE: {
6815 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6816 if (cast->closing_loc.length > 0) {
6817 location = &cast->closing_loc;
6825 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6831static pm_symbol_node_t *
6832pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6833 pm_symbol_node_t *new_node = pm_symbol_node_new(
6836 PM_NODE_FLAG_STATIC_LITERAL,
6837 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6838 TOK2LOC(parser, opening),
6840 TOK2LOC(parser, closing),
6844 pm_token_t content = {
6845 .type = PM_TOKEN_IDENTIFIER,
6846 .start = parser->start + node->content_loc.start,
6847 .end = parser->start + node->content_loc.start + node->content_loc.length
6850 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
6852 /* The old node is arena-allocated so no explicit free is needed. */
6859static pm_string_node_t *
6860pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6861 pm_node_flags_t flags = 0;
6863 switch (parser->frozen_string_literal) {
6864 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6865 flags = PM_STRING_FLAGS_MUTABLE;
6867 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6868 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6872 pm_string_node_t *new_node = pm_string_node_new(
6876 PM_LOCATION_INIT_NODE(node),
6883 /* The old node is arena-allocated so no explicit free is needed. */
6890static pm_true_node_t *
6891pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6892 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6894 return pm_true_node_new(
6897 PM_NODE_FLAG_STATIC_LITERAL,
6898 PM_LOCATION_INIT_TOKEN(parser, token)
6905static pm_true_node_t *
6906pm_true_node_synthesized_create(pm_parser_t *parser) {
6907 return pm_true_node_new(
6910 PM_NODE_FLAG_STATIC_LITERAL,
6911 PM_LOCATION_INIT_UNSET
6918static pm_undef_node_t *
6919pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6920 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6922 return pm_undef_node_new(
6926 PM_LOCATION_INIT_TOKEN(parser, token),
6927 ((pm_node_list_t) { 0 }),
6928 TOK2LOC(parser, token)
6936pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6937 PM_NODE_LENGTH_SET_NODE(node, name);
6938 pm_node_list_append(arena, &node->names, name);
6944static pm_unless_node_t *
6945pm_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) {
6946 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6947 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6949 return pm_unless_node_new(
6952 PM_NODE_FLAG_NEWLINE,
6953 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
6954 TOK2LOC(parser, keyword),
6956 NTOK2LOC(parser, then_keyword),
6959 ((pm_location_t) { 0 })
6966static pm_unless_node_t *
6967pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6968 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6970 pm_statements_node_t *statements = pm_statements_node_create(parser);
6971 pm_statements_node_body_append(parser, statements, statement, true);
6973 return pm_unless_node_new(
6976 PM_NODE_FLAG_NEWLINE,
6977 PM_LOCATION_INIT_NODES(statement, predicate),
6978 TOK2LOC(parser, unless_keyword),
6980 ((pm_location_t) { 0 }),
6983 ((pm_location_t) { 0 })
6987static PRISM_INLINE void
6988pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
6989 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
6990 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
6999pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7000 assert(parser->current_block_exits != NULL);
7002 // All of the block exits that we want to remove should be within the
7003 // statements, and since we are modifying the statements, we shouldn't have
7004 // to check the end location.
7005 uint32_t start = statements->base.location.start;
7007 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7008 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7009 if (block_exit->location.start < start) break;
7011 // Implicitly remove from the list by lowering the size.
7012 parser->current_block_exits->size--;
7019static pm_until_node_t *
7020pm_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) {
7021 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7023 return pm_until_node_new(
7027 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7028 TOK2LOC(parser, keyword),
7029 NTOK2LOC(parser, do_keyword),
7030 TOK2LOC(parser, closing),
7039static pm_until_node_t *
7040pm_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) {
7041 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7042 pm_loop_modifier_block_exits(parser, statements);
7044 return pm_until_node_new(
7048 PM_LOCATION_INIT_NODES(statements, predicate),
7049 TOK2LOC(parser, keyword),
7050 ((pm_location_t) { 0 }),
7051 ((pm_location_t) { 0 }),
7060static pm_when_node_t *
7061pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7062 return pm_when_node_new(
7066 PM_LOCATION_INIT_TOKEN(parser, keyword),
7067 TOK2LOC(parser, keyword),
7068 ((pm_node_list_t) { 0 }),
7069 ((pm_location_t) { 0 }),
7078pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
7079 PM_NODE_LENGTH_SET_NODE(node, condition);
7080 pm_node_list_append(arena, &node->conditions, condition);
7086static PRISM_INLINE void
7087pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
7088 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
7089 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
7096pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7097 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
7098 PM_NODE_LENGTH_SET_NODE(node, statements);
7101 node->statements = statements;
7107static pm_while_node_t *
7108pm_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) {
7109 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7111 return pm_while_node_new(
7115 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7116 TOK2LOC(parser, keyword),
7117 NTOK2LOC(parser, do_keyword),
7118 TOK2LOC(parser, closing),
7127static pm_while_node_t *
7128pm_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) {
7129 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7130 pm_loop_modifier_block_exits(parser, statements);
7132 return pm_while_node_new(
7136 PM_LOCATION_INIT_NODES(statements, predicate),
7137 TOK2LOC(parser, keyword),
7138 ((pm_location_t) { 0 }),
7139 ((pm_location_t) { 0 }),
7148static pm_while_node_t *
7149pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7150 return pm_while_node_new(
7154 PM_LOCATION_INIT_UNSET,
7155 ((pm_location_t) { 0 }),
7156 ((pm_location_t) { 0 }),
7157 ((pm_location_t) { 0 }),
7167static pm_x_string_node_t *
7168pm_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) {
7169 return pm_x_string_node_new(
7172 PM_STRING_FLAGS_FROZEN,
7173 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
7174 TOK2LOC(parser, opening),
7175 TOK2LOC(parser, content),
7176 TOK2LOC(parser, closing),
7184static PRISM_INLINE pm_x_string_node_t *
7185pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7186 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7192static pm_yield_node_t *
7193pm_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) {
7194 uint32_t start = PM_TOKEN_START(parser, keyword);
7197 if (rparen_loc->length > 0) {
7198 end = PM_LOCATION_END(rparen_loc);
7199 } else if (arguments != NULL) {
7200 end = PM_NODE_END(arguments);
7201 } else if (lparen_loc->length > 0) {
7202 end = PM_LOCATION_END(lparen_loc);
7204 end = PM_TOKEN_END(parser, keyword);
7207 return pm_yield_node_new(
7211 ((pm_location_t) { .start = start, .length = U32(end - start) }),
7212 TOK2LOC(parser, keyword),
7224pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7225 pm_scope_t *scope = parser->current_scope;
7228 while (scope != NULL) {
7229 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7230 if (scope->closed) break;
7232 scope = scope->previous;
7244static PRISM_INLINE int
7245pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7246 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7252static PRISM_INLINE void
7253pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7254 pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
7260static pm_constant_id_t
7261pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7262 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
7263 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7270static PRISM_INLINE pm_constant_id_t
7271pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
7272 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
7278static PRISM_INLINE pm_constant_id_t
7279pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7280 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
7286static pm_constant_id_t
7287pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7288 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7289 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7296static pm_constant_id_t
7297pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7298 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7299 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7311pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7312 // We want to check whether the parameter name is a numbered parameter or
7314 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7316 // Otherwise we'll fetch the constant id for the parameter name and check
7317 // whether it's already in the current scope.
7318 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7320 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7321 // Add an error if the parameter doesn't start with _ and has been seen before
7322 if ((name->start < name->end) && (*name->start != '_')) {
7323 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7334pm_parser_scope_pop(pm_parser_t *parser) {
7335 pm_scope_t *scope = parser->current_scope;
7336 parser->current_scope = scope->previous;
7337 pm_locals_free(&scope->locals);
7338 xfree_sized(scope, sizeof(pm_scope_t));
7341/******************************************************************************/
7343/******************************************************************************/
7348static PRISM_INLINE void
7349pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7350 *stack = (*stack << 1) | (value & 1);
7356static PRISM_INLINE void
7357pm_state_stack_pop(pm_state_stack_t *stack) {
7364static PRISM_INLINE bool
7365pm_state_stack_p(const pm_state_stack_t *stack) {
7369static PRISM_INLINE void
7370pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7371 // Use the negation of the value to prevent stack overflow.
7372 pm_state_stack_push(&parser->accepts_block_stack, !value);
7375static PRISM_INLINE void
7376pm_accepts_block_stack_pop(pm_parser_t *parser) {
7377 pm_state_stack_pop(&parser->accepts_block_stack);
7380static PRISM_INLINE bool
7381pm_accepts_block_stack_p(pm_parser_t *parser) {
7382 return !pm_state_stack_p(&parser->accepts_block_stack);
7385static PRISM_INLINE void
7386pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7387 pm_state_stack_push(&parser->do_loop_stack, value);
7390static PRISM_INLINE void
7391pm_do_loop_stack_pop(pm_parser_t *parser) {
7392 pm_state_stack_pop(&parser->do_loop_stack);
7395static PRISM_INLINE bool
7396pm_do_loop_stack_p(pm_parser_t *parser) {
7397 return pm_state_stack_p(&parser->do_loop_stack);
7400/******************************************************************************/
7401/* Lexer check helpers */
7402/******************************************************************************/
7408static PRISM_INLINE uint8_t
7409peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7410 if (cursor < parser->end) {
7422static PRISM_INLINE uint8_t
7423peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7424 return peek_at(parser, parser->current.end + offset);
7431static PRISM_INLINE uint8_t
7432peek(const pm_parser_t *parser) {
7433 return peek_at(parser, parser->current.end);
7440static PRISM_INLINE bool
7441match(pm_parser_t *parser, uint8_t value) {
7442 if (peek(parser) == value) {
7443 parser->current.end++;
7453static PRISM_INLINE size_t
7454match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7455 if (peek_at(parser, cursor) == '\n') {
7458 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7469static PRISM_INLINE size_t
7470match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7471 return match_eol_at(parser, parser->current.end + offset);
7479static PRISM_INLINE size_t
7480match_eol(pm_parser_t *parser) {
7481 return match_eol_at(parser, parser->current.end);
7487static PRISM_INLINE const uint8_t *
7488next_newline(const uint8_t *cursor, ptrdiff_t length) {
7489 assert(length >= 0);
7491 // Note that it's okay for us to use memchr here to look for \n because none
7492 // of the encodings that we support have \n as a component of a multi-byte
7494 return memchr(cursor, '\n', (size_t) length);
7500static PRISM_INLINE bool
7501ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7502 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));
7510parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7511 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7513 if (encoding != NULL) {
7514 if (parser->encoding != encoding) {
7515 parser->encoding = encoding;
7516 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7519 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7531parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7532 const uint8_t *cursor = parser->current.start + 1;
7533 const uint8_t *end = parser->current.end;
7535 bool separator = false;
7537 if (end - cursor <= 6) return;
7538 switch (cursor[6]) {
7539 case 'C': case 'c': cursor += 6; continue;
7540 case 'O': case 'o': cursor += 5; continue;
7541 case 'D': case 'd': cursor += 4; continue;
7542 case 'I': case 'i': cursor += 3; continue;
7543 case 'N': case 'n': cursor += 2; continue;
7544 case 'G': case 'g': cursor += 1; continue;
7551 if (pm_char_is_whitespace(*cursor)) break;
7554 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7560 if (++cursor >= end) return;
7561 } while (pm_char_is_whitespace(*cursor));
7563 if (separator) break;
7564 if (*cursor != '=' && *cursor != ':') return;
7570 const uint8_t *value_start = cursor;
7571 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7573 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7574 // If we were unable to parse the encoding value, then we've got an
7575 // issue because we didn't understand the encoding that the user was
7576 // trying to use. In this case we'll keep using the default encoding but
7577 // add an error to the parser to indicate an unsuccessful parse.
7578 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7583 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7584 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7585 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7586} pm_magic_comment_boolean_value_t;
7592static pm_magic_comment_boolean_value_t
7593parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7594 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7595 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7596 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7597 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7599 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7603static PRISM_INLINE bool
7604pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7605 return b == '\'' || b == '"' || b == ':' || b == ';';
7614parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7618 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1,
'*', (
size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7619 if (cursor[-1] ==
'-' && cursor + 1 < end && cursor[1] ==
'-') {
7637parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7640 const uint8_t *start = parser->current.start + 1;
7641 const uint8_t *end = parser->current.end;
7642 if (end - start <= 7)
return false;
7644 const uint8_t *cursor;
7645 bool indicator =
false;
7647 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7650 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7662 if (pm_memchr(start,
':', (
size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
7668 start += pm_strspn_whitespace(start, end - start);
7672 while (cursor < end) {
7674 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7677 const uint8_t *key_start = cursor;
7678 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7680 const uint8_t *key_end = cursor;
7681 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7682 if (cursor == end)
break;
7684 if (*cursor ==
':') {
7687 if (!indicator)
return false;
7691 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7692 if (cursor == end)
break;
7694 const uint8_t *value_start;
7695 const uint8_t *value_end;
7697 if (*cursor ==
'"') {
7698 value_start = ++cursor;
7699 for (; cursor < end && *cursor !=
'"'; cursor++) {
7700 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7703 if (cursor < end && *cursor ==
'"') cursor++;
7705 value_start = cursor;
7706 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7711 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7713 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7714 if (cursor != end)
return false;
7720 const size_t key_length = (size_t) (key_end - key_start);
7721 const uint8_t *dash = pm_memchr(key_start,
'-', key_length, parser->encoding_changed, parser->encoding);
7724 pm_string_shared_init(&key, key_start, key_end);
7726 uint8_t *buffer =
xmalloc(key_length);
7727 if (buffer == NULL)
break;
7729 memcpy(buffer, key_start, key_length);
7730 buffer[dash - key_start] =
'_';
7732 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7733 buffer[dash - key_start] =
'_';
7736 pm_string_owned_init(&key, buffer, key_length);
7741 const uint8_t *key_source = pm_string_source(&key);
7742 uint32_t value_length = (uint32_t) (value_end - value_start);
7746 if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7748 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7749 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7751 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7755 if (key_length == 11) {
7756 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7757 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7758 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7759 PM_PARSER_WARN_TOKEN_FORMAT(
7762 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7764 (
const char *) key_source,
7766 (
const char *) value_start
7769 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7770 parser->warn_mismatched_indentation =
false;
7772 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7773 parser->warn_mismatched_indentation =
true;
7777 }
else if (key_length == 21) {
7778 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7781 if (semantic_token_seen) {
7782 pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7784 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7785 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7786 PM_PARSER_WARN_TOKEN_FORMAT(
7789 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7791 (
const char *) key_source,
7793 (
const char *) value_start
7796 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7799 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7805 }
else if (key_length == 24) {
7806 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7807 const uint8_t *cursor = parser->current.start;
7808 while ((cursor > parser->start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7810 if (!((cursor == parser->start) || (cursor[-1] ==
'\n'))) {
7811 pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7812 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7813 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7814 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7815 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7816 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7817 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7818 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7819 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7821 PM_PARSER_WARN_TOKEN_FORMAT(
7824 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7826 (
const char *) key_source,
7828 (
const char *) value_start
7836 pm_string_cleanup(&key);
7853static const uint32_t context_terminators[] = {
7854 [PM_CONTEXT_NONE] = 0,
7855 [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7856 [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7857 [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7858 [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7859 [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7860 [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7861 [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7862 [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7863 [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
7864 [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7865 [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7866 [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7867 [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7868 [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7869 [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7870 [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7871 [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7872 [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7873 [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7874 [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7875 [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
7876 [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
7877 [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7878 [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
7879 [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7880 [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
7881 [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
7882 [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
7883 [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7884 [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7885 [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7886 [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7887 [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7888 [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7889 [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
7890 [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
7891 [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7892 [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7893 [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7894 [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7895 [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
7896 [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7897 [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7898 [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7899 [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7900 [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
7901 [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7902 [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7903 [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7904 [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7905 [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
7906 [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7907 [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
7908 [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
7912context_terminator(pm_context_t context,
pm_token_t *token) {
7913 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7924 while (context_node != NULL) {
7925 if (context_terminator(context_node->context, token))
return context_node->context;
7926 context_node = context_node->prev;
7929 return PM_CONTEXT_NONE;
7933context_push(
pm_parser_t *parser, pm_context_t context) {
7935 if (context_node == NULL)
return false;
7939 if (parser->current_context == NULL) {
7940 parser->current_context = context_node;
7942 context_node->prev = parser->current_context;
7943 parser->current_context = context_node;
7953 parser->current_context = prev;
7957context_p(
const pm_parser_t *parser, pm_context_t context) {
7960 while (context_node != NULL) {
7961 if (context_node->context == context)
return true;
7962 context_node = context_node->prev;
7972 while (context_node != NULL) {
7973 switch (context_node->context) {
7974 case PM_CONTEXT_DEF:
7975 case PM_CONTEXT_DEF_PARAMS:
7976 case PM_CONTEXT_DEF_ENSURE:
7977 case PM_CONTEXT_DEF_RESCUE:
7978 case PM_CONTEXT_DEF_ELSE:
7980 case PM_CONTEXT_CLASS:
7981 case PM_CONTEXT_CLASS_ENSURE:
7982 case PM_CONTEXT_CLASS_RESCUE:
7983 case PM_CONTEXT_CLASS_ELSE:
7984 case PM_CONTEXT_MODULE:
7985 case PM_CONTEXT_MODULE_ENSURE:
7986 case PM_CONTEXT_MODULE_RESCUE:
7987 case PM_CONTEXT_MODULE_ELSE:
7988 case PM_CONTEXT_SCLASS:
7989 case PM_CONTEXT_SCLASS_ENSURE:
7990 case PM_CONTEXT_SCLASS_RESCUE:
7991 case PM_CONTEXT_SCLASS_ELSE:
7994 context_node = context_node->prev;
8006context_human(pm_context_t context) {
8008 case PM_CONTEXT_NONE:
8009 assert(
false &&
"unreachable");
8011 case PM_CONTEXT_BEGIN:
return "begin statement";
8012 case PM_CONTEXT_BLOCK_BRACES:
return "'{'..'}' block";
8013 case PM_CONTEXT_BLOCK_KEYWORDS:
return "'do'..'end' block";
8014 case PM_CONTEXT_BLOCK_PARAMETERS:
return "'|'..'|' block parameter";
8015 case PM_CONTEXT_CASE_WHEN:
return "'when' clause";
8016 case PM_CONTEXT_CASE_IN:
return "'in' clause";
8017 case PM_CONTEXT_CLASS:
return "class definition";
8018 case PM_CONTEXT_DEF:
return "method definition";
8019 case PM_CONTEXT_DEF_PARAMS:
return "method parameters";
8020 case PM_CONTEXT_DEFAULT_PARAMS:
return "parameter default value";
8021 case PM_CONTEXT_DEFINED:
return "'defined?' expression";
8022 case PM_CONTEXT_ELSE:
8023 case PM_CONTEXT_BEGIN_ELSE:
8024 case PM_CONTEXT_BLOCK_ELSE:
8025 case PM_CONTEXT_CLASS_ELSE:
8026 case PM_CONTEXT_DEF_ELSE:
8027 case PM_CONTEXT_LAMBDA_ELSE:
8028 case PM_CONTEXT_MODULE_ELSE:
8029 case PM_CONTEXT_SCLASS_ELSE:
return "'else' clause";
8030 case PM_CONTEXT_ELSIF:
return "'elsif' clause";
8031 case PM_CONTEXT_EMBEXPR:
return "embedded expression";
8032 case PM_CONTEXT_BEGIN_ENSURE:
8033 case PM_CONTEXT_BLOCK_ENSURE:
8034 case PM_CONTEXT_CLASS_ENSURE:
8035 case PM_CONTEXT_DEF_ENSURE:
8036 case PM_CONTEXT_LAMBDA_ENSURE:
8037 case PM_CONTEXT_MODULE_ENSURE:
8038 case PM_CONTEXT_SCLASS_ENSURE:
return "'ensure' clause";
8039 case PM_CONTEXT_FOR:
return "for loop";
8040 case PM_CONTEXT_FOR_INDEX:
return "for loop index";
8041 case PM_CONTEXT_IF:
return "if statement";
8042 case PM_CONTEXT_LAMBDA_BRACES:
return "'{'..'}' lambda block";
8043 case PM_CONTEXT_LAMBDA_DO_END:
return "'do'..'end' lambda block";
8044 case PM_CONTEXT_LOOP_PREDICATE:
return "loop predicate";
8045 case PM_CONTEXT_MAIN:
return "top level context";
8046 case PM_CONTEXT_MODULE:
return "module definition";
8047 case PM_CONTEXT_MULTI_TARGET:
return "multiple targets";
8048 case PM_CONTEXT_PARENS:
return "parentheses";
8049 case PM_CONTEXT_POSTEXE:
return "'END' block";
8050 case PM_CONTEXT_PREDICATE:
return "predicate";
8051 case PM_CONTEXT_PREEXE:
return "'BEGIN' block";
8052 case PM_CONTEXT_BEGIN_RESCUE:
8053 case PM_CONTEXT_BLOCK_RESCUE:
8054 case PM_CONTEXT_CLASS_RESCUE:
8055 case PM_CONTEXT_DEF_RESCUE:
8056 case PM_CONTEXT_LAMBDA_RESCUE:
8057 case PM_CONTEXT_MODULE_RESCUE:
8058 case PM_CONTEXT_RESCUE_MODIFIER:
8059 case PM_CONTEXT_SCLASS_RESCUE:
return "'rescue' clause";
8060 case PM_CONTEXT_SCLASS:
return "singleton class definition";
8061 case PM_CONTEXT_TERNARY:
return "ternary expression";
8062 case PM_CONTEXT_UNLESS:
return "unless statement";
8063 case PM_CONTEXT_UNTIL:
return "until statement";
8064 case PM_CONTEXT_WHILE:
return "while statement";
8067 assert(
false &&
"unreachable");
8076pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8077 if (invalid != NULL) {
8078 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8079 pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
8084pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8085 const uint8_t *invalid = NULL;
8086 size_t length = pm_strspn_binary_number(
string, parser->end -
string, &invalid);
8087 pm_strspn_number_validate(parser,
string, length, invalid);
8092pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8093 const uint8_t *invalid = NULL;
8094 size_t length = pm_strspn_octal_number(
string, parser->end -
string, &invalid);
8095 pm_strspn_number_validate(parser,
string, length, invalid);
8100pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8101 const uint8_t *invalid = NULL;
8102 size_t length = pm_strspn_decimal_number(
string, parser->end -
string, &invalid);
8103 pm_strspn_number_validate(parser,
string, length, invalid);
8108pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8109 const uint8_t *invalid = NULL;
8110 size_t length = pm_strspn_hexadecimal_number(
string, parser->end -
string, &invalid);
8111 pm_strspn_number_validate(parser,
string, length, invalid);
8115static pm_token_type_t
8116lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8117 pm_token_type_t
type = PM_TOKEN_INTEGER;
8121 if (peek(parser) ==
'.') {
8122 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8123 parser->current.end += 2;
8124 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8125 type = PM_TOKEN_FLOAT;
8135 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8136 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8137 parser->current.end += 2;
8139 if (pm_char_is_decimal_digit(peek(parser))) {
8140 parser->current.end++;
8141 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8143 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8145 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8146 parser->current.end++;
8147 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8153 type = PM_TOKEN_FLOAT;
8159static pm_token_type_t
8160lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8161 pm_token_type_t
type = PM_TOKEN_INTEGER;
8164 if (peek_offset(parser, -1) ==
'0') {
8165 switch (*parser->current.end) {
8169 parser->current.end++;
8170 if (pm_char_is_decimal_digit(peek(parser))) {
8171 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8174 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8182 parser->current.end++;
8183 if (pm_char_is_binary_digit(peek(parser))) {
8184 parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
8187 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8190 parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
8196 parser->current.end++;
8197 if (pm_char_is_octal_digit(peek(parser))) {
8198 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8201 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8204 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8217 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8218 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8224 parser->current.end++;
8225 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8226 parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
8229 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8232 parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8237 type = lex_optional_float_suffix(parser, seen_e);
8244 type = lex_optional_float_suffix(parser, seen_e);
8253 const uint8_t *cursor = parser->current.end;
8254 const uint8_t *end = parser->end;
8255 uint64_t value = (uint64_t) (cursor[-1] -
'0');
8257 bool has_underscore =
false;
8258 bool prev_underscore =
false;
8259 const uint8_t *invalid = NULL;
8261 while (cursor < end) {
8262 uint8_t c = *cursor;
8263 if (c >=
'0' && c <=
'9') {
8264 if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c -
'0');
8265 prev_underscore =
false;
8267 }
else if (c ==
'_') {
8268 has_underscore =
true;
8269 if (prev_underscore && invalid == NULL) invalid = cursor;
8270 prev_underscore =
true;
8277 if (has_underscore) {
8278 if (prev_underscore && invalid == NULL) invalid = cursor - 1;
8279 pm_strspn_number_validate(parser, parser->current.end, (
size_t) (cursor - parser->current.end), invalid);
8282 if (value <= UINT32_MAX) {
8283 parser->integer.value = (uint32_t) value;
8284 parser->integer.lexed =
true;
8287 parser->current.end = cursor;
8295 uint8_t next = peek(parser);
8296 if (next ==
'.' || next ==
'e' || next ==
'E') {
8297 type = lex_optional_float_suffix(parser, seen_e);
8301 if (
type != PM_TOKEN_INTEGER) {
8302 parser->integer.lexed =
false;
8311 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8312 const uint8_t *fraction_start = parser->current.end;
8313 const uint8_t *fraction_end = parser->current.end + 2;
8314 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
8315 pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
8321static pm_token_type_t
8323 pm_token_type_t
type = PM_TOKEN_INTEGER;
8324 parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8325 parser->integer.lexed =
false;
8327 if (parser->current.end < parser->end) {
8328 bool seen_e =
false;
8329 type = lex_numeric_prefix(parser, &seen_e);
8331 const uint8_t *end = parser->current.end;
8332 pm_token_type_t suffix_type =
type;
8334 if (
type == PM_TOKEN_INTEGER) {
8335 if (match(parser,
'r')) {
8336 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8338 if (match(parser,
'i')) {
8339 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8341 }
else if (match(parser,
'i')) {
8342 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8345 if (!seen_e && match(parser,
'r')) {
8346 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8348 if (match(parser,
'i')) {
8349 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8351 }
else if (match(parser,
'i')) {
8352 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8356 const uint8_t b = peek(parser);
8357 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8358 parser->current.end = end;
8367static pm_token_type_t
8369 if (parser->current.end >= parser->end) {
8370 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8371 return PM_TOKEN_GLOBAL_VARIABLE;
8376 bool allow_multiple =
true;
8378 switch (*parser->current.end) {
8395 parser->current.end++;
8396 return PM_TOKEN_GLOBAL_VARIABLE;
8402 parser->current.end++;
8403 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8406 parser->current.end++;
8409 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8411 parser->current.end += width;
8412 }
while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8415 pm_diagnostic_id_t diag_id = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
8416 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
8419 return PM_TOKEN_GLOBAL_VARIABLE;
8431 parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
8432 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8435 parser->current.end++;
8436 allow_multiple =
false;
8441 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8443 parser->current.end += width;
8444 }
while (allow_multiple && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8445 }
else if (pm_char_is_whitespace(peek(parser))) {
8448 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8452 pm_diagnostic_id_t diag_id = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? PM_ERR_INVALID_VARIABLE_GLOBAL_3_3 : PM_ERR_INVALID_VARIABLE_GLOBAL;
8453 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8454 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), diag_id, (
int) (PM_TOKEN_LENGTH(&parser->current) + U32(width)), (
const char *) parser->current.start);
8457 return PM_TOKEN_GLOBAL_VARIABLE;
8475lex_keyword(
pm_parser_t *parser,
const uint8_t *current_start,
const char *value,
size_t vlen, pm_lex_state_t state, pm_token_type_t
type, pm_token_type_t modifier_type) {
8476 if (memcmp(current_start, value, vlen) == 0) {
8477 pm_lex_state_t last_state = parser->lex_state;
8479 if (parser->lex_state & PM_LEX_STATE_FNAME) {
8480 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8482 lex_state_set(parser, state);
8483 if (state == PM_LEX_STATE_BEG) {
8484 parser->command_start =
true;
8487 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8488 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8489 return modifier_type;
8496 return PM_TOKEN_EOF;
8499static pm_token_type_t
8500lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8503 const uint8_t *end = parser->end;
8504 const uint8_t *current_start = parser->current.start;
8505 const uint8_t *current_end = parser->current.end;
8506 bool encoding_changed = parser->encoding_changed;
8508 if (encoding_changed) {
8509 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8510 current_end += width;
8514 current_end += scan_identifier_ascii(current_end, end);
8517 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8518 current_end += width;
8521 parser->current.end = current_end;
8525 width = (size_t) (current_end - current_start);
8527 if (current_end < end) {
8528 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8534 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8535 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8539 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8540 (void) match(parser,
':');
8541 return PM_TOKEN_LABEL;
8544 if (parser->lex_state != PM_LEX_STATE_DOT) {
8545 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8546 return PM_TOKEN_KEYWORD_DEFINED;
8550 return PM_TOKEN_METHOD_NAME;
8553 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,
'=')) {
8556 return PM_TOKEN_IDENTIFIER;
8560 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8561 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8565 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8566 (void) match(parser,
':');
8567 return PM_TOKEN_LABEL;
8571 if (parser->lex_state != PM_LEX_STATE_DOT) {
8572 pm_token_type_t
type;
8575 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8576 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
8577 return PM_TOKEN_KEYWORD_DO;
8579 if (pm_do_loop_stack_p(parser)) {
8580 return PM_TOKEN_KEYWORD_DO_LOOP;
8582 if (!pm_accepts_block_stack_p(parser)) {
8583 return PM_TOKEN_KEYWORD_DO_BLOCK;
8585 return PM_TOKEN_KEYWORD_DO;
8588 if ((
type = lex_keyword(parser, current_start,
"if", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IF, PM_TOKEN_KEYWORD_IF_MODIFIER)) != PM_TOKEN_EOF)
return type;
8589 if ((
type = lex_keyword(parser, current_start,
"in", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8590 if ((
type = lex_keyword(parser, current_start,
"or", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_OR, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8593 if ((
type = lex_keyword(parser, current_start,
"and", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8594 if ((
type = lex_keyword(parser, current_start,
"def", width, PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8595 if ((
type = lex_keyword(parser, current_start,
"end", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8596 if ((
type = lex_keyword(parser, current_start,
"END", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8597 if ((
type = lex_keyword(parser, current_start,
"for", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8598 if ((
type = lex_keyword(parser, current_start,
"nil", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8599 if ((
type = lex_keyword(parser, current_start,
"not", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_NOT, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8602 if ((
type = lex_keyword(parser, current_start,
"case", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8603 if ((
type = lex_keyword(parser, current_start,
"else", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8604 if ((
type = lex_keyword(parser, current_start,
"next", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8605 if ((
type = lex_keyword(parser, current_start,
"redo", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8606 if ((
type = lex_keyword(parser, current_start,
"self", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8607 if ((
type = lex_keyword(parser, current_start,
"then", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8608 if ((
type = lex_keyword(parser, current_start,
"true", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8609 if ((
type = lex_keyword(parser, current_start,
"when", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8612 if ((
type = lex_keyword(parser, current_start,
"alias", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_ALIAS, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8613 if ((
type = lex_keyword(parser, current_start,
"begin", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8614 if ((
type = lex_keyword(parser, current_start,
"BEGIN", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8615 if ((
type = lex_keyword(parser, current_start,
"break", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8616 if ((
type = lex_keyword(parser, current_start,
"class", width, PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8617 if ((
type = lex_keyword(parser, current_start,
"elsif", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8618 if ((
type = lex_keyword(parser, current_start,
"false", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8619 if ((
type = lex_keyword(parser, current_start,
"retry", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8620 if ((
type = lex_keyword(parser, current_start,
"super", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8621 if ((
type = lex_keyword(parser, current_start,
"undef", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_UNDEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8622 if ((
type = lex_keyword(parser, current_start,
"until", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNTIL, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) != PM_TOKEN_EOF)
return type;
8623 if ((
type = lex_keyword(parser, current_start,
"while", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHILE, PM_TOKEN_KEYWORD_WHILE_MODIFIER)) != PM_TOKEN_EOF)
return type;
8624 if ((
type = lex_keyword(parser, current_start,
"yield", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_YIELD, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8627 if ((
type = lex_keyword(parser, current_start,
"ensure", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8628 if ((
type = lex_keyword(parser, current_start,
"module", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8629 if ((
type = lex_keyword(parser, current_start,
"rescue", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) != PM_TOKEN_EOF)
return type;
8630 if ((
type = lex_keyword(parser, current_start,
"return", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8631 if ((
type = lex_keyword(parser, current_start,
"unless", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNLESS, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) != PM_TOKEN_EOF)
return type;
8634 if ((
type = lex_keyword(parser, current_start,
"__LINE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8635 if ((
type = lex_keyword(parser, current_start,
"__FILE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___FILE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8638 if ((
type = lex_keyword(parser, current_start,
"__ENCODING__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8643 if (encoding_changed) {
8644 return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8646 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8655 return (parser->current.start == parser->start) || (parser->current.start[-1] ==
'\n');
8672static pm_token_type_t
8673lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8676 if (pound + 1 >= parser->end) {
8677 parser->current.end = pound + 1;
8678 return PM_TOKEN_STRING_CONTENT;
8687 if (pound + 2 >= parser->end) {
8688 parser->current.end = pound + 1;
8689 return PM_TOKEN_STRING_CONTENT;
8694 const uint8_t *variable = pound + 2;
8695 if (*variable ==
'@' && pound + 3 < parser->end) variable++;
8697 if (char_is_identifier_start(parser, variable, parser->end - variable)) {
8701 if (pound > parser->current.start) {
8702 parser->current.end = pound;
8703 return PM_TOKEN_STRING_CONTENT;
8708 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8709 parser->current.end = pound + 1;
8710 return PM_TOKEN_EMBVAR;
8716 parser->current.end = pound + 1;
8722 if (pound + 2 >= parser->end) {
8723 parser->current.end = pound + 1;
8724 return PM_TOKEN_STRING_CONTENT;
8730 const uint8_t *check = pound + 2;
8732 if (pound[2] ==
'-') {
8733 if (pound + 3 >= parser->end) {
8734 parser->current.end = pound + 2;
8735 return PM_TOKEN_STRING_CONTENT;
8746 char_is_identifier_start(parser, check, parser->end - check) ||
8747 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8752 if (pound > parser->current.start) {
8753 parser->current.end = pound;
8754 return PM_TOKEN_STRING_CONTENT;
8759 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8760 parser->current.end = pound + 1;
8761 return PM_TOKEN_EMBVAR;
8766 parser->current.end = pound + 1;
8772 if (pound > parser->current.start) {
8773 parser->current.end = pound;
8774 return PM_TOKEN_STRING_CONTENT;
8777 parser->enclosure_nesting++;
8781 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8782 parser->current.end = pound + 2;
8783 parser->command_start =
true;
8784 pm_do_loop_stack_push(parser,
false);
8785 return PM_TOKEN_EMBEXPR_BEGIN;
8790 parser->current.end = pound + 1;
8795static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8796static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8797static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8798static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8799static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8804static const bool ascii_printable_chars[] = {
8805 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8806 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8807 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8808 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8809 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8810 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8811 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8812 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8816char_is_ascii_printable(
const uint8_t b) {
8817 return (b < 0x80) && ascii_printable_chars[b];
8825escape_hexadecimal_digit(
const uint8_t value) {
8826 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8835escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const pm_location_t *error_location,
const uint8_t flags) {
8837 for (
size_t index = 0; index < length; index++) {
8838 if (index != 0) value <<= 4;
8839 value |= escape_hexadecimal_digit(
string[index]);
8844 if (value >= 0xD800 && value <= 0xDFFF) {
8845 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8848 }
else if (error_location != NULL) {
8849 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
8851 pm_parser_err(parser, U32(
string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
8863escape_byte(uint8_t value,
const uint8_t flags) {
8864 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8865 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8873escape_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) {
8877 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8878 if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
8879 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8883 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
8887 parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
8890 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8891 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8895 pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
8898 pm_buffer_append_byte(buffer, 0xEF);
8899 pm_buffer_append_byte(buffer, 0xBF);
8900 pm_buffer_append_byte(buffer, 0xBD);
8911 if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
8912 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8916 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
8920 parser->explicit_encoding = parser->encoding;
8923 pm_buffer_append_byte(buffer,
byte);
8943 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8944 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
8947 escape_write_byte_encoded(parser, buffer, flags,
byte);
8956 if (parser->encoding_changed) {
8957 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8959 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
8963 if (*parser->current.end ==
'\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
8964 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
8965 }
else if (width > 1) {
8967 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
8968 pm_buffer_append_bytes(b, parser->current.end, width);
8969 parser->current.end += width;
8973 parser->current.end++;
8974 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8984escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
8985#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
8987 PM_PARSER_WARN_TOKEN_FORMAT(
8990 PM_WARN_INVALID_CHARACTER,
9004 uint8_t peeked = peek(parser);
9007 parser->current.end++;
9008 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9012 parser->current.end++;
9013 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9017 parser->current.end++;
9018 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9022 parser->current.end++;
9023 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9027 parser->current.end++;
9028 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9032 parser->current.end++;
9033 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9037 parser->current.end++;
9038 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9042 parser->current.end++;
9043 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9047 parser->current.end++;
9048 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9052 parser->current.end++;
9053 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9057 parser->current.end++;
9058 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9061 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9062 uint8_t value = (uint8_t) (*parser->current.end -
'0');
9063 parser->current.end++;
9065 if (pm_char_is_octal_digit(peek(parser))) {
9066 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9067 parser->current.end++;
9069 if (pm_char_is_octal_digit(peek(parser))) {
9070 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9071 parser->current.end++;
9075 value = escape_byte(value, flags);
9076 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9080 const uint8_t *start = parser->current.end - 1;
9082 parser->current.end++;
9083 uint8_t
byte = peek(parser);
9085 if (pm_char_is_hexadecimal_digit(
byte)) {
9086 uint8_t value = escape_hexadecimal_digit(
byte);
9087 parser->current.end++;
9089 byte = peek(parser);
9090 if (pm_char_is_hexadecimal_digit(
byte)) {
9091 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9092 parser->current.end++;
9095 value = escape_byte(value, flags);
9096 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9097 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9098 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9100 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9104 escape_write_byte_encoded(parser, buffer, flags, value);
9106 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9112 const uint8_t *start = parser->current.end - 1;
9113 parser->current.end++;
9115 if (parser->current.end == parser->end) {
9116 const uint8_t *start = parser->current.end - 2;
9117 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9118 }
else if (peek(parser) ==
'{') {
9119 const uint8_t *unicode_codepoints_start = parser->current.end - 2;
9120 parser->current.end++;
9124 if ((whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end)) > 0) {
9125 parser->current.end += whitespace;
9126 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9131 parser->current.end += 2;
9137 const uint8_t *extra_codepoints_start = NULL;
9138 int codepoints_count = 0;
9140 while ((parser->current.end < parser->end) && (*parser->current.end !=
'}')) {
9141 const uint8_t *unicode_start = parser->current.end;
9142 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
9144 if (hexadecimal_length > 6) {
9146 pm_parser_err(parser, U32(unicode_start - parser->start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9147 }
else if (hexadecimal_length == 0) {
9150 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9155 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9157 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
9158 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9164 parser->current.end += hexadecimal_length;
9166 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9167 extra_codepoints_start = unicode_start;
9170 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
9171 escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
9173 parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
9178 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9179 pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9182 if (parser->current.end == parser->end) {
9183 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->current.end - start), start);
9184 }
else if (peek(parser) ==
'}') {
9185 parser->current.end++;
9187 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9192 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9194 pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9198 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9199 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->current.end - unicode_codepoints_start));
9202 size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
9205 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9206 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9208 const uint8_t *start = parser->current.end - 2;
9209 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9211 }
else if (length == 4) {
9212 uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
9214 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9215 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end + 4 - start));
9218 escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
9219 parser->current.end += 4;
9221 parser->current.end += length;
9223 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9227 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9229 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9237 parser->current.end++;
9238 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9239 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9242 if (parser->current.end == parser->end) {
9243 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9247 uint8_t peeked = peek(parser);
9250 parser->current.end++;
9251 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9255 parser->current.end++;
9257 if (match(parser,
'u') || match(parser,
'U')) {
9258 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9262 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9265 parser->current.end++;
9266 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9267 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9270 parser->current.end++;
9271 escape_read_warn(parser, flags, 0,
"\\t");
9272 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9275 if (!char_is_ascii_printable(peeked)) {
9276 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9280 if (peeked ==
'\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
9281 parser->current.end++;
9282 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9288 parser->current.end++;
9289 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9290 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9293 if (peek(parser) !=
'-') {
9294 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9295 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9299 parser->current.end++;
9300 if (parser->current.end == parser->end) {
9301 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9305 uint8_t peeked = peek(parser);
9308 parser->current.end++;
9309 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9313 parser->current.end++;
9315 if (match(parser,
'u') || match(parser,
'U')) {
9316 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9320 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9323 parser->current.end++;
9324 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9325 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9328 parser->current.end++;
9329 escape_read_warn(parser, flags, 0,
"\\t");
9330 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9333 if (!char_is_ascii_printable(peeked)) {
9334 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9335 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9339 if (peeked ==
'\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
9340 parser->current.end++;
9341 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9347 parser->current.end++;
9348 if (flags & PM_ESCAPE_FLAG_META) {
9349 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9352 if (peek(parser) !=
'-') {
9353 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9354 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9358 parser->current.end++;
9359 if (parser->current.end == parser->end) {
9360 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9364 uint8_t peeked = peek(parser);
9367 parser->current.end++;
9369 if (match(parser,
'u') || match(parser,
'U')) {
9370 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9374 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9377 parser->current.end++;
9378 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9379 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9382 parser->current.end++;
9383 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9384 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9387 if (!char_is_ascii_printable(peeked)) {
9388 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9389 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9393 if (peeked ==
'\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
9394 parser->current.end++;
9395 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9400 if (peek_offset(parser, 1) ==
'\n') {
9401 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
9402 parser->current.end += 2;
9403 escape_write_byte_encoded(parser, buffer, flags, escape_byte(
'\n', flags));
9409 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9410 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9411 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9414 if (parser->current.end < parser->end) {
9415 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9417 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9449static pm_token_type_t
9451 if (lex_state_end_p(parser)) {
9452 lex_state_set(parser, PM_LEX_STATE_BEG);
9453 return PM_TOKEN_QUESTION_MARK;
9456 if (parser->current.end >= parser->end) {
9457 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9458 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9459 return PM_TOKEN_CHARACTER_LITERAL;
9462 if (pm_char_is_whitespace(*parser->current.end)) {
9463 lex_state_set(parser, PM_LEX_STATE_BEG);
9464 return PM_TOKEN_QUESTION_MARK;
9467 lex_state_set(parser, PM_LEX_STATE_BEG);
9469 if (match(parser,
'\\')) {
9470 lex_state_set(parser, PM_LEX_STATE_END);
9473 pm_buffer_init(&buffer, 3);
9475 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9478 void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length,
PRISM_ALIGNOF(uint8_t));
9479 pm_string_constant_init(&parser->current_string, (
const char *) arena_data, buffer.length);
9480 pm_buffer_cleanup(&buffer);
9482 return PM_TOKEN_CHARACTER_LITERAL;
9484 size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9489 !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) ==
'_') ||
9491 (parser->current.end + encoding_width >= parser->end) ||
9492 !char_is_identifier(parser, parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
9495 lex_state_set(parser, PM_LEX_STATE_END);
9496 parser->current.end += encoding_width;
9497 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9498 return PM_TOKEN_CHARACTER_LITERAL;
9502 return PM_TOKEN_QUESTION_MARK;
9509static pm_token_type_t
9511 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9512 const uint8_t *end = parser->end;
9515 if ((width = char_is_identifier_start(parser, parser->current.end, end - parser->current.end)) > 0) {
9516 parser->current.end += width;
9518 while ((width = char_is_identifier(parser, parser->current.end, end - parser->current.end)) > 0) {
9519 parser->current.end += width;
9521 }
else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
9522 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9523 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
9524 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9527 size_t width = parser->encoding->char_width(parser->current.end, end - parser->current.end);
9528 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, (
int) ((parser->current.end + width) - parser->current.start), (
const char *) parser->current.start);
9530 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9531 pm_parser_err_token(parser, &parser->current, diag_id);
9536 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
9537 lex_mode_pop(parser);
9548 if (parser->lex_callback.callback) {
9549 parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
9562 .location = TOK2LOC(parser, &parser->current)
9573static pm_token_type_t
9576 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9578 if (newline == NULL) {
9579 parser->current.end = parser->end;
9581 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9582 parser->current.end = newline + 1;
9585 parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
9586 parser_lex_callback(parser);
9589 const uint8_t *comment_start = parser->current.start;
9590 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9594 while (parser->current.end + 4 <= parser->end) {
9595 parser->current.start = parser->current.end;
9600 (memcmp(parser->current.end,
"=end", 4) == 0) &&
9602 (parser->current.end + 4 == parser->end) ||
9603 pm_char_is_whitespace(parser->current.end[4]) ||
9604 (parser->current.end[4] ==
'\0') ||
9605 (parser->current.end[4] ==
'\004') ||
9606 (parser->current.end[4] ==
'\032')
9609 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9611 if (newline == NULL) {
9612 parser->current.end = parser->end;
9614 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9615 parser->current.end = newline + 1;
9618 parser->current.type = PM_TOKEN_EMBDOC_END;
9619 parser_lex_callback(parser);
9621 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9622 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9624 return PM_TOKEN_EMBDOC_END;
9629 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9631 if (newline == NULL) {
9632 parser->current.end = parser->end;
9634 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9635 parser->current.end = newline + 1;
9638 parser->current.type = PM_TOKEN_EMBDOC_LINE;
9639 parser_lex_callback(parser);
9642 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9644 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9645 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9647 return PM_TOKEN_EOF;
9657 parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
9658 parser_lex_callback(parser);
9672 assert(parser->heredoc_end <= parser->end);
9673 parser->next_start = parser->heredoc_end;
9674 parser->heredoc_end = NULL;
9682 const uint8_t *cursor = parser->current.end;
9684 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9685 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9748 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9762 if (parser->encoding_changed) {
9763 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9765 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9770 return (width == 0 ? 1 : width);
9778 size_t width = parser_char_width(parser);
9779 pm_buffer_append_bytes(&token_buffer->
buffer, parser->current.end, width);
9780 parser->current.end += width;
9785 size_t width = parser_char_width(parser);
9786 const uint8_t *start = parser->current.end;
9787 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, width);
9788 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, width);
9789 parser->current.end += width;
9801 size_t len = pm_buffer_length(&token_buffer->
buffer);
9802 void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->
buffer),
len,
PRISM_ALIGNOF(uint8_t));
9803 pm_string_constant_init(&parser->current_string, (
const char *) arena_data,
len);
9804 pm_buffer_cleanup(&token_buffer->
buffer);
9809 pm_token_buffer_copy(parser, &token_buffer->
base);
9824 if (token_buffer->
cursor == NULL) {
9825 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9827 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->current.end - token_buffer->
cursor));
9828 pm_token_buffer_copy(parser, token_buffer);
9835 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9837 const uint8_t *cursor = token_buffer->
base.
cursor;
9838 size_t length = (size_t) (parser->current.end - cursor);
9839 pm_buffer_append_bytes(&token_buffer->
base.
buffer, cursor, length);
9840 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, cursor, length);
9841 pm_regexp_token_buffer_copy(parser, token_buffer);
9845#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9857 const uint8_t *start;
9858 if (token_buffer->
cursor == NULL) {
9859 pm_buffer_init(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9860 start = parser->current.start;
9862 start = token_buffer->
cursor;
9865 const uint8_t *end = parser->current.end - 1;
9866 assert(end >= start);
9867 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9869 token_buffer->
cursor = end;
9874 const uint8_t *start;
9876 pm_buffer_init(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9877 pm_buffer_init(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9878 start = parser->current.start;
9883 const uint8_t *end = parser->current.end - 1;
9884 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9885 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9890#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9897pm_heredoc_strspn_inline_whitespace(
pm_parser_t *parser,
const uint8_t **cursor, pm_heredoc_indent_t indent) {
9898 size_t whitespace = 0;
9901 case PM_HEREDOC_INDENT_NONE:
9906 case PM_HEREDOC_INDENT_DASH:
9908 *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
9910 case PM_HEREDOC_INDENT_TILDE:
9913 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
9914 if (**cursor ==
'\t') {
9915 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
9934 size_t eol_length = match_eol(parser);
9937 if (parser->heredoc_end) {
9941 parser_flush_heredoc_end(parser);
9944 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
9947 uint8_t delimiter = *parser->current.end;
9951 if (eol_length == 2) {
9952 delimiter = *(parser->current.end + 1);
9955 parser->current.end += eol_length;
9959 return *parser->current.end++;
9966#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
9976 assert(parser->current.end <= parser->end);
9977 parser->previous = parser->current;
9980 bool previous_command_start = parser->command_start;
9981 parser->command_start =
false;
9985 bool lexed_comment =
false;
9989 unsigned int semantic_token_seen = parser->semantic_token_seen;
9990 parser->semantic_token_seen =
true;
9998 switch (parser->lex_modes.current->mode) {
9999 case PM_LEX_DEFAULT:
10000 case PM_LEX_EMBEXPR:
10001 case PM_LEX_EMBVAR:
10010 if (parser->next_start != NULL) {
10011 parser->current.end = parser->next_start;
10012 parser->next_start = NULL;
10017 bool space_seen =
false;
10022 bool chomping =
true;
10023 while (parser->current.end < parser->end && chomping) {
10025 static const uint8_t inline_whitespace[256] = {
10026 [
' '] = 1, [
'\t'] = 1, [
'\f'] = 1, [
'\v'] = 1
10028 const uint8_t *scan = parser->current.end;
10029 while (scan < parser->end && inline_whitespace[*scan]) scan++;
10030 if (scan > parser->current.end) {
10031 parser->current.end = scan;
10037 switch (*parser->current.end) {
10039 if (match_eol_offset(parser, 1)) {
10042 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10043 parser->current.end++;
10048 size_t eol_length = match_eol_offset(parser, 1);
10050 if (parser->heredoc_end) {
10051 parser->current.end = parser->heredoc_end;
10052 parser->heredoc_end = NULL;
10054 parser->current.end += eol_length + 1;
10055 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10058 }
else if (pm_char_is_inline_whitespace(*parser->current.end)) {
10059 parser->current.end += 2;
10073 parser->current.start = parser->current.end;
10077 if (parser->current.end >= parser->end) {
10081 if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
10082 lex_mode_pop(parser);
10083 goto switch_lex_modes;
10091 if (parser->current.start > parser->start && (*(parser->current.start - 1) ==
'\n')) {
10092 parser->current.start -= 1;
10099 switch (*parser->current.end++) {
10103 parser->current.end--;
10107 const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
10108 parser->current.end = ending == NULL ? parser->end : ending;
10113 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10114 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
10116 if (ending) parser->current.end++;
10117 parser->current.type = PM_TOKEN_COMMENT;
10118 parser_lex_callback(parser);
10122 if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
10123 ptrdiff_t length = parser->current.end - parser->current.start;
10129 if (length >= 10 && !parser->encoding_locked) {
10130 parser_lex_magic_comment_encoding(parser);
10134 lexed_comment =
true;
10139 parser->semantic_token_seen = semantic_token_seen & 0x1;
10140 size_t eol_length = match_eol_at(parser, parser->current.end - 1);
10152 if (!lexed_comment) {
10153 parser->current.end += eol_length - 1;
10156 if (parser->heredoc_end == NULL) {
10157 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10161 if (parser->heredoc_end) {
10162 parser_flush_heredoc_end(parser);
10167 switch (lex_state_ignored_p(parser)) {
10168 case PM_IGNORED_NEWLINE_NONE:
10170 case PM_IGNORED_NEWLINE_PATTERN:
10171 if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
10172 if (!lexed_comment) parser_lex_ignored_newline(parser);
10173 lex_state_set(parser, PM_LEX_STATE_BEG);
10174 parser->command_start =
true;
10175 parser->current.type = PM_TOKEN_NEWLINE;
10179 case PM_IGNORED_NEWLINE_ALL:
10180 if (!lexed_comment) parser_lex_ignored_newline(parser);
10181 lexed_comment =
false;
10182 goto lex_next_token;
10189 const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
10190 next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
10192 if (next_content < parser->end) {
10198 if (next_content[0] ==
'#') {
10200 const uint8_t *following = next_newline(next_content, parser->end - next_content);
10202 while (following && (following + 1 < parser->end)) {
10204 following += pm_strspn_inline_whitespace(following, parser->end - following);
10208 if (peek_at(parser, following) !=
'#')
break;
10212 following = next_newline(following, parser->end - following);
10217 if (lex_state_ignored_p(parser)) {
10218 if (!lexed_comment) parser_lex_ignored_newline(parser);
10219 lexed_comment =
false;
10220 goto lex_next_token;
10226 (peek_at(parser, following) ==
'.') ||
10227 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10229 if (!lexed_comment) parser_lex_ignored_newline(parser);
10230 lexed_comment =
false;
10231 goto lex_next_token;
10239 (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
10241 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10242 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10244 peek_at(parser, following) ==
'a' &&
10245 peek_at(parser, following + 1) ==
'n' &&
10246 peek_at(parser, following + 2) ==
'd' &&
10247 peek_at(parser, next_content + 3) !=
'!' &&
10248 peek_at(parser, next_content + 3) !=
'?' &&
10249 !char_is_identifier(parser, following + 3, parser->end - (following + 3))
10252 peek_at(parser, following) ==
'o' &&
10253 peek_at(parser, following + 1) ==
'r' &&
10254 peek_at(parser, next_content + 2) !=
'!' &&
10255 peek_at(parser, next_content + 2) !=
'?' &&
10256 !char_is_identifier(parser, following + 2, parser->end - (following + 2))
10260 if (!lexed_comment) parser_lex_ignored_newline(parser);
10261 lexed_comment =
false;
10262 goto lex_next_token;
10268 if (next_content[0] ==
'.') {
10272 if (peek_at(parser, next_content + 1) ==
'.') {
10273 if (!lexed_comment) parser_lex_ignored_newline(parser);
10274 lex_state_set(parser, PM_LEX_STATE_BEG);
10275 parser->command_start =
true;
10276 parser->current.type = PM_TOKEN_NEWLINE;
10280 if (!lexed_comment) parser_lex_ignored_newline(parser);
10281 lex_state_set(parser, PM_LEX_STATE_DOT);
10282 parser->current.start = next_content;
10283 parser->current.end = next_content + 1;
10284 parser->next_start = NULL;
10290 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10291 if (!lexed_comment) parser_lex_ignored_newline(parser);
10292 lex_state_set(parser, PM_LEX_STATE_DOT);
10293 parser->current.start = next_content;
10294 parser->current.end = next_content + 2;
10295 parser->next_start = NULL;
10296 LEX(PM_TOKEN_AMPERSAND_DOT);
10299 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
10302 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10303 if (!lexed_comment) parser_lex_ignored_newline(parser);
10304 lex_state_set(parser, PM_LEX_STATE_BEG);
10305 parser->current.start = next_content;
10306 parser->current.end = next_content + 2;
10307 parser->next_start = NULL;
10308 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10313 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10314 if (!lexed_comment) parser_lex_ignored_newline(parser);
10315 lex_state_set(parser, PM_LEX_STATE_BEG);
10316 parser->current.start = next_content;
10317 parser->current.end = next_content + 2;
10318 parser->next_start = NULL;
10319 LEX(PM_TOKEN_PIPE_PIPE);
10325 peek_at(parser, next_content) ==
'a' &&
10326 peek_at(parser, next_content + 1) ==
'n' &&
10327 peek_at(parser, next_content + 2) ==
'd' &&
10328 peek_at(parser, next_content + 3) !=
'!' &&
10329 peek_at(parser, next_content + 3) !=
'?' &&
10330 !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
10332 if (!lexed_comment) parser_lex_ignored_newline(parser);
10333 lex_state_set(parser, PM_LEX_STATE_BEG);
10334 parser->current.start = next_content;
10335 parser->current.end = next_content + 3;
10336 parser->next_start = NULL;
10337 parser->command_start =
true;
10338 LEX(PM_TOKEN_KEYWORD_AND);
10344 peek_at(parser, next_content) ==
'o' &&
10345 peek_at(parser, next_content + 1) ==
'r' &&
10346 peek_at(parser, next_content + 2) !=
'!' &&
10347 peek_at(parser, next_content + 2) !=
'?' &&
10348 !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
10350 if (!lexed_comment) parser_lex_ignored_newline(parser);
10351 lex_state_set(parser, PM_LEX_STATE_BEG);
10352 parser->current.start = next_content;
10353 parser->current.end = next_content + 2;
10354 parser->next_start = NULL;
10355 parser->command_start =
true;
10356 LEX(PM_TOKEN_KEYWORD_OR);
10363 lex_state_set(parser, PM_LEX_STATE_BEG);
10364 parser->command_start =
true;
10365 parser->current.type = PM_TOKEN_NEWLINE;
10366 if (!lexed_comment) parser_lex_callback(parser);
10372 if ((parser->previous.
type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
10373 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
10376 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10377 LEX(PM_TOKEN_COMMA);
10381 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10383 if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10384 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10387 parser->enclosure_nesting++;
10388 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10389 pm_do_loop_stack_push(parser,
false);
10395 parser->enclosure_nesting--;
10396 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10397 pm_do_loop_stack_pop(parser);
10398 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10402 lex_state_set(parser, PM_LEX_STATE_BEG);
10403 parser->command_start =
true;
10404 LEX(PM_TOKEN_SEMICOLON);
10408 parser->enclosure_nesting++;
10409 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10411 if (lex_state_operator_p(parser)) {
10412 if (match(parser,
']')) {
10413 parser->enclosure_nesting--;
10414 lex_state_set(parser, PM_LEX_STATE_ARG);
10415 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10418 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10422 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10423 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10426 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10427 pm_do_loop_stack_push(parser,
false);
10432 parser->enclosure_nesting--;
10433 lex_state_set(parser, PM_LEX_STATE_END);
10434 pm_do_loop_stack_pop(parser);
10435 LEX(PM_TOKEN_BRACKET_RIGHT);
10439 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10441 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
10443 parser->command_start =
true;
10444 lex_state_set(parser, PM_LEX_STATE_BEG);
10445 type = PM_TOKEN_LAMBDA_BEGIN;
10446 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10448 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10449 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10451 parser->command_start =
true;
10452 lex_state_set(parser, PM_LEX_STATE_BEG);
10453 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10455 parser->command_start =
true;
10456 lex_state_set(parser, PM_LEX_STATE_BEG);
10459 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10462 parser->enclosure_nesting++;
10463 parser->brace_nesting++;
10464 pm_do_loop_stack_push(parser,
false);
10471 parser->enclosure_nesting--;
10472 pm_do_loop_stack_pop(parser);
10474 if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
10475 lex_mode_pop(parser);
10476 LEX(PM_TOKEN_EMBEXPR_END);
10479 parser->brace_nesting--;
10480 lex_state_set(parser, PM_LEX_STATE_END);
10481 LEX(PM_TOKEN_BRACE_RIGHT);
10485 if (match(parser,
'*')) {
10486 if (match(parser,
'=')) {
10487 lex_state_set(parser, PM_LEX_STATE_BEG);
10488 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10491 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10493 if (lex_state_spcarg_p(parser, space_seen)) {
10494 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10495 type = PM_TOKEN_USTAR_STAR;
10496 }
else if (lex_state_beg_p(parser)) {
10497 type = PM_TOKEN_USTAR_STAR;
10498 }
else if (ambiguous_operator_p(parser, space_seen)) {
10499 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10502 if (lex_state_operator_p(parser)) {
10503 lex_state_set(parser, PM_LEX_STATE_ARG);
10505 lex_state_set(parser, PM_LEX_STATE_BEG);
10511 if (match(parser,
'=')) {
10512 lex_state_set(parser, PM_LEX_STATE_BEG);
10513 LEX(PM_TOKEN_STAR_EQUAL);
10516 pm_token_type_t
type = PM_TOKEN_STAR;
10518 if (lex_state_spcarg_p(parser, space_seen)) {
10519 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10520 type = PM_TOKEN_USTAR;
10521 }
else if (lex_state_beg_p(parser)) {
10522 type = PM_TOKEN_USTAR;
10523 }
else if (ambiguous_operator_p(parser, space_seen)) {
10524 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10527 if (lex_state_operator_p(parser)) {
10528 lex_state_set(parser, PM_LEX_STATE_ARG);
10530 lex_state_set(parser, PM_LEX_STATE_BEG);
10538 if (lex_state_operator_p(parser)) {
10539 lex_state_set(parser, PM_LEX_STATE_ARG);
10540 if (match(parser,
'@')) {
10541 LEX(PM_TOKEN_BANG);
10544 lex_state_set(parser, PM_LEX_STATE_BEG);
10547 if (match(parser,
'=')) {
10548 LEX(PM_TOKEN_BANG_EQUAL);
10551 if (match(parser,
'~')) {
10552 LEX(PM_TOKEN_BANG_TILDE);
10555 LEX(PM_TOKEN_BANG);
10560 current_token_starts_line(parser) &&
10561 (parser->current.end + 5 <= parser->end) &&
10562 memcmp(parser->current.end,
"begin", 5) == 0 &&
10563 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10565 pm_token_type_t
type = lex_embdoc(parser);
10566 if (
type == PM_TOKEN_EOF) {
10570 goto lex_next_token;
10573 if (lex_state_operator_p(parser)) {
10574 lex_state_set(parser, PM_LEX_STATE_ARG);
10576 lex_state_set(parser, PM_LEX_STATE_BEG);
10579 if (match(parser,
'>')) {
10580 LEX(PM_TOKEN_EQUAL_GREATER);
10583 if (match(parser,
'~')) {
10584 LEX(PM_TOKEN_EQUAL_TILDE);
10587 if (match(parser,
'=')) {
10588 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10591 LEX(PM_TOKEN_EQUAL);
10595 if (match(parser,
'<')) {
10597 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10598 !lex_state_end_p(parser) &&
10599 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10601 const uint8_t *end = parser->current.end;
10603 pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
10604 pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
10606 if (match(parser,
'-')) {
10607 indent = PM_HEREDOC_INDENT_DASH;
10609 else if (match(parser,
'~')) {
10610 indent = PM_HEREDOC_INDENT_TILDE;
10613 if (match(parser,
'`')) {
10614 quote = PM_HEREDOC_QUOTE_BACKTICK;
10616 else if (match(parser,
'"')) {
10617 quote = PM_HEREDOC_QUOTE_DOUBLE;
10619 else if (match(parser,
'\'')) {
10620 quote = PM_HEREDOC_QUOTE_SINGLE;
10623 const uint8_t *ident_start = parser->current.end;
10626 if (parser->current.end >= parser->end) {
10627 parser->current.end = end;
10628 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) == 0) {
10629 parser->current.end = end;
10631 if (quote == PM_HEREDOC_QUOTE_NONE) {
10632 parser->current.end += width;
10634 while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end))) {
10635 parser->current.end += width;
10640 while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
10641 if (*parser->current.end ==
'\r' || *parser->current.end ==
'\n')
break;
10642 parser->current.end++;
10646 size_t ident_length = (size_t) (parser->current.end - ident_start);
10647 bool ident_error =
false;
10649 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10650 pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10651 ident_error =
true;
10654 parser->explicit_encoding = NULL;
10656 .mode = PM_LEX_HEREDOC,
10659 .ident_start = ident_start,
10660 .ident_length = ident_length,
10664 .next_start = parser->current.end,
10665 .common_whitespace = NULL,
10666 .line_continuation =
false
10670 if (parser->heredoc_end == NULL) {
10671 const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
10673 if (body_start == NULL) {
10678 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10679 body_start = parser->end;
10683 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
10687 parser->next_start = body_start;
10689 parser->next_start = parser->heredoc_end;
10692 LEX(PM_TOKEN_HEREDOC_START);
10696 if (match(parser,
'=')) {
10697 lex_state_set(parser, PM_LEX_STATE_BEG);
10698 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10701 if (ambiguous_operator_p(parser, space_seen)) {
10702 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10705 if (lex_state_operator_p(parser)) {
10706 lex_state_set(parser, PM_LEX_STATE_ARG);
10708 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10709 lex_state_set(parser, PM_LEX_STATE_BEG);
10712 LEX(PM_TOKEN_LESS_LESS);
10715 if (lex_state_operator_p(parser)) {
10716 lex_state_set(parser, PM_LEX_STATE_ARG);
10718 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10719 lex_state_set(parser, PM_LEX_STATE_BEG);
10722 if (match(parser,
'=')) {
10723 if (match(parser,
'>')) {
10724 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10727 LEX(PM_TOKEN_LESS_EQUAL);
10730 LEX(PM_TOKEN_LESS);
10734 if (match(parser,
'>')) {
10735 if (lex_state_operator_p(parser)) {
10736 lex_state_set(parser, PM_LEX_STATE_ARG);
10738 lex_state_set(parser, PM_LEX_STATE_BEG);
10740 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10743 if (lex_state_operator_p(parser)) {
10744 lex_state_set(parser, PM_LEX_STATE_ARG);
10746 lex_state_set(parser, PM_LEX_STATE_BEG);
10749 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10753 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10754 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10755 LEX(PM_TOKEN_STRING_BEGIN);
10760 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10761 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10762 LEX(PM_TOKEN_BACKTICK);
10765 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10766 if (previous_command_start) {
10767 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10769 lex_state_set(parser, PM_LEX_STATE_ARG);
10772 LEX(PM_TOKEN_BACKTICK);
10775 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10776 LEX(PM_TOKEN_BACKTICK);
10781 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10782 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10783 LEX(PM_TOKEN_STRING_BEGIN);
10788 LEX(lex_question_mark(parser));
10792 if (match(parser,
'&')) {
10793 lex_state_set(parser, PM_LEX_STATE_BEG);
10795 if (match(parser,
'=')) {
10796 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10799 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10802 if (match(parser,
'=')) {
10803 lex_state_set(parser, PM_LEX_STATE_BEG);
10804 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10807 if (match(parser,
'.')) {
10808 lex_state_set(parser, PM_LEX_STATE_DOT);
10809 LEX(PM_TOKEN_AMPERSAND_DOT);
10812 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10813 if (lex_state_spcarg_p(parser, space_seen)) {
10814 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10815 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10817 const uint8_t delim = peek_offset(parser, 1);
10819 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->current.end + 1, parser->end - (parser->current.end + 1))) {
10820 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10824 type = PM_TOKEN_UAMPERSAND;
10825 }
else if (lex_state_beg_p(parser)) {
10826 type = PM_TOKEN_UAMPERSAND;
10827 }
else if (ambiguous_operator_p(parser, space_seen)) {
10828 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10831 if (lex_state_operator_p(parser)) {
10832 lex_state_set(parser, PM_LEX_STATE_ARG);
10834 lex_state_set(parser, PM_LEX_STATE_BEG);
10842 if (match(parser,
'|')) {
10843 if (match(parser,
'=')) {
10844 lex_state_set(parser, PM_LEX_STATE_BEG);
10845 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10848 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10849 parser->current.end--;
10850 LEX(PM_TOKEN_PIPE);
10853 lex_state_set(parser, PM_LEX_STATE_BEG);
10854 LEX(PM_TOKEN_PIPE_PIPE);
10857 if (match(parser,
'=')) {
10858 lex_state_set(parser, PM_LEX_STATE_BEG);
10859 LEX(PM_TOKEN_PIPE_EQUAL);
10862 if (lex_state_operator_p(parser)) {
10863 lex_state_set(parser, PM_LEX_STATE_ARG);
10865 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10868 LEX(PM_TOKEN_PIPE);
10872 if (lex_state_operator_p(parser)) {
10873 lex_state_set(parser, PM_LEX_STATE_ARG);
10875 if (match(parser,
'@')) {
10876 LEX(PM_TOKEN_UPLUS);
10879 LEX(PM_TOKEN_PLUS);
10882 if (match(parser,
'=')) {
10883 lex_state_set(parser, PM_LEX_STATE_BEG);
10884 LEX(PM_TOKEN_PLUS_EQUAL);
10888 lex_state_beg_p(parser) ||
10889 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
10891 lex_state_set(parser, PM_LEX_STATE_BEG);
10893 if (pm_char_is_decimal_digit(peek(parser))) {
10894 parser->current.end++;
10895 pm_token_type_t
type = lex_numeric(parser);
10896 lex_state_set(parser, PM_LEX_STATE_END);
10900 LEX(PM_TOKEN_UPLUS);
10903 if (ambiguous_operator_p(parser, space_seen)) {
10904 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
10907 lex_state_set(parser, PM_LEX_STATE_BEG);
10908 LEX(PM_TOKEN_PLUS);
10913 if (lex_state_operator_p(parser)) {
10914 lex_state_set(parser, PM_LEX_STATE_ARG);
10916 if (match(parser,
'@')) {
10917 LEX(PM_TOKEN_UMINUS);
10920 LEX(PM_TOKEN_MINUS);
10923 if (match(parser,
'=')) {
10924 lex_state_set(parser, PM_LEX_STATE_BEG);
10925 LEX(PM_TOKEN_MINUS_EQUAL);
10928 if (match(parser,
'>')) {
10929 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10930 LEX(PM_TOKEN_MINUS_GREATER);
10933 bool spcarg = lex_state_spcarg_p(parser, space_seen);
10934 bool is_beg = lex_state_beg_p(parser);
10935 if (!is_beg && spcarg) {
10936 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
10939 if (is_beg || spcarg) {
10940 lex_state_set(parser, PM_LEX_STATE_BEG);
10941 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
10944 if (ambiguous_operator_p(parser, space_seen)) {
10945 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
10948 lex_state_set(parser, PM_LEX_STATE_BEG);
10949 LEX(PM_TOKEN_MINUS);
10954 bool beg_p = lex_state_beg_p(parser);
10956 if (match(parser,
'.')) {
10957 if (match(parser,
'.')) {
10959 if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) {
10960 if (lex_state_p(parser, PM_LEX_STATE_END)) {
10961 lex_state_set(parser, PM_LEX_STATE_BEG);
10963 lex_state_set(parser, PM_LEX_STATE_ENDARG);
10965 LEX(PM_TOKEN_UDOT_DOT_DOT);
10968 if (parser->enclosure_nesting == 0 && parser_end_of_line_p(parser)) {
10969 pm_parser_warn_token(parser, &parser->current, PM_WARN_DOT_DOT_DOT_EOL);
10972 lex_state_set(parser, PM_LEX_STATE_BEG);
10973 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
10976 lex_state_set(parser, PM_LEX_STATE_BEG);
10977 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
10980 lex_state_set(parser, PM_LEX_STATE_DOT);
10995 pm_token_type_t
type = lex_numeric(parser);
10996 lex_state_set(parser, PM_LEX_STATE_END);
11002 if (match(parser,
':')) {
11003 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)) {
11004 lex_state_set(parser, PM_LEX_STATE_BEG);
11005 LEX(PM_TOKEN_UCOLON_COLON);
11008 lex_state_set(parser, PM_LEX_STATE_DOT);
11009 LEX(PM_TOKEN_COLON_COLON);
11012 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11013 lex_state_set(parser, PM_LEX_STATE_BEG);
11014 LEX(PM_TOKEN_COLON);
11017 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11018 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->current.end);
11019 parser->current.end++;
11022 lex_state_set(parser, PM_LEX_STATE_FNAME);
11023 LEX(PM_TOKEN_SYMBOL_BEGIN);
11027 if (lex_state_beg_p(parser)) {
11028 lex_mode_push_regexp(parser,
'\0',
'/');
11029 LEX(PM_TOKEN_REGEXP_BEGIN);
11032 if (match(parser,
'=')) {
11033 lex_state_set(parser, PM_LEX_STATE_BEG);
11034 LEX(PM_TOKEN_SLASH_EQUAL);
11037 if (lex_state_spcarg_p(parser, space_seen)) {
11038 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
11039 lex_mode_push_regexp(parser,
'\0',
'/');
11040 LEX(PM_TOKEN_REGEXP_BEGIN);
11043 if (ambiguous_operator_p(parser, space_seen)) {
11044 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
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);
11053 LEX(PM_TOKEN_SLASH);
11057 if (lex_state_operator_p(parser)) {
11058 lex_state_set(parser, PM_LEX_STATE_ARG);
11060 lex_state_set(parser, PM_LEX_STATE_BEG);
11062 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11066 if (lex_state_operator_p(parser)) {
11067 (void) match(parser,
'@');
11068 lex_state_set(parser, PM_LEX_STATE_ARG);
11070 lex_state_set(parser, PM_LEX_STATE_BEG);
11073 LEX(PM_TOKEN_TILDE);
11081 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
11082 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11083 LEX(PM_TOKEN_PERCENT);
11086 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11087 lex_state_set(parser, PM_LEX_STATE_BEG);
11088 LEX(PM_TOKEN_PERCENT_EQUAL);
11090 lex_state_beg_p(parser) ||
11091 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11092 lex_state_spcarg_p(parser, space_seen)
11094 if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) {
11095 if (*parser->current.end >= 0x80) {
11096 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11099 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11100 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11101 LEX(PM_TOKEN_STRING_BEGIN);
11106 uint8_t delimiter = peek_offset(parser, 1);
11107 if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) {
11108 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11109 goto lex_next_token;
11112 switch (peek(parser)) {
11114 parser->current.end++;
11116 if (parser->current.end < parser->end) {
11117 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11119 lex_mode_push_list_eof(parser);
11122 LEX(PM_TOKEN_PERCENT_LOWER_I);
11125 parser->current.end++;
11127 if (parser->current.end < parser->end) {
11128 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11130 lex_mode_push_list_eof(parser);
11133 LEX(PM_TOKEN_PERCENT_UPPER_I);
11136 parser->current.end++;
11138 if (parser->current.end < parser->end) {
11139 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11140 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11142 lex_mode_push_regexp(parser,
'\0',
'\0');
11145 LEX(PM_TOKEN_REGEXP_BEGIN);
11148 parser->current.end++;
11150 if (parser->current.end < parser->end) {
11151 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11152 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11154 lex_mode_push_string_eof(parser);
11157 LEX(PM_TOKEN_STRING_BEGIN);
11160 parser->current.end++;
11162 if (parser->current.end < parser->end) {
11163 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11164 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11166 lex_mode_push_string_eof(parser);
11169 LEX(PM_TOKEN_STRING_BEGIN);
11172 parser->current.end++;
11174 if (parser->current.end < parser->end) {
11175 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11176 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11177 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11179 lex_mode_push_string_eof(parser);
11182 LEX(PM_TOKEN_SYMBOL_BEGIN);
11185 parser->current.end++;
11187 if (parser->current.end < parser->end) {
11188 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11190 lex_mode_push_list_eof(parser);
11193 LEX(PM_TOKEN_PERCENT_LOWER_W);
11196 parser->current.end++;
11198 if (parser->current.end < parser->end) {
11199 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11201 lex_mode_push_list_eof(parser);
11204 LEX(PM_TOKEN_PERCENT_UPPER_W);
11207 parser->current.end++;
11209 if (parser->current.end < parser->end) {
11210 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11211 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11213 lex_mode_push_string_eof(parser);
11216 LEX(PM_TOKEN_PERCENT_LOWER_X);
11223 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11224 goto lex_next_token;
11228 if (ambiguous_operator_p(parser, space_seen)) {
11229 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11232 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11233 LEX(PM_TOKEN_PERCENT);
11238 pm_token_type_t
type = lex_global_variable(parser);
11242 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
11243 lex_mode_pop(parser);
11246 lex_state_set(parser, PM_LEX_STATE_END);
11252 lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11253 LEX(lex_at_variable(parser));
11256 if (*parser->current.start !=
'_') {
11257 size_t width = char_is_identifier_start(parser, parser->current.start, parser->end - parser->current.start);
11264 if (*parser->current.start >= 0x80) {
11265 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
11266 }
else if (*parser->current.start ==
'\\') {
11267 switch (peek_at(parser, parser->current.start + 1)) {
11269 parser->current.end++;
11270 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11273 parser->current.end++;
11274 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11277 parser->current.end++;
11278 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11281 parser->current.end++;
11282 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11285 if (peek_at(parser, parser->current.start + 2) !=
'\n') {
11286 parser->current.end++;
11287 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11292 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11295 }
else if (char_is_ascii_printable(*parser->current.start)) {
11296 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
11298 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
11301 goto lex_next_token;
11304 parser->current.end = parser->current.start + width;
11307 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11314 ((parser->current.end - parser->current.start) == 7) &&
11315 current_token_starts_line(parser) &&
11316 (memcmp(parser->current.start,
"__END__", 7) == 0) &&
11317 (parser->current.end == parser->end || match_eol(parser))
11322 const uint8_t *cursor = parser->current.end;
11323 while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
11324 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
11327 parser->current.end = parser->end;
11328 parser->current.type = PM_TOKEN___END__;
11329 parser_lex_callback(parser);
11331 parser->data_loc.
start = PM_TOKEN_START(parser, &parser->current);
11332 parser->data_loc.
length = PM_TOKEN_LENGTH(&parser->current);
11337 pm_lex_state_t last_state = parser->lex_state;
11339 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11340 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11341 if (previous_command_start) {
11342 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11344 lex_state_set(parser, PM_LEX_STATE_ARG);
11346 }
else if (parser->lex_state == PM_LEX_STATE_FNAME) {
11347 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11349 lex_state_set(parser, PM_LEX_STATE_END);
11354 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11355 (
type == PM_TOKEN_IDENTIFIER) &&
11356 ((pm_parser_local_depth(parser, &parser->current) != -1) ||
11357 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
11359 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11366 case PM_LEX_LIST: {
11367 if (parser->next_start != NULL) {
11368 parser->current.end = parser->next_start;
11369 parser->next_start = NULL;
11373 parser->current.start = parser->current.end;
11379 if (parser->heredoc_end) {
11380 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11381 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11385 whitespace = pm_strspn_whitespace_newlines(parser->current.end, parser->end - parser->current.end, &parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11388 if (whitespace > 0) {
11389 parser->current.end += whitespace;
11390 if (peek_offset(parser, -1) ==
'\n') {
11392 parser_flush_heredoc_end(parser);
11394 LEX(PM_TOKEN_WORDS_SEP);
11399 if (parser->current.end >= parser->end) {
11406 const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
11407 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11413 while (breakpoint != NULL) {
11416 if (pm_char_is_whitespace(*breakpoint)) {
11417 parser->current.end = breakpoint;
11418 pm_token_buffer_flush(parser, &token_buffer);
11419 LEX(PM_TOKEN_STRING_CONTENT);
11424 if (*breakpoint == lex_mode->as.list.terminator) {
11427 if (lex_mode->as.list.nesting > 0) {
11428 parser->current.end = breakpoint + 1;
11429 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11430 lex_mode->as.list.nesting--;
11436 if (breakpoint > parser->current.start) {
11437 parser->current.end = breakpoint;
11438 pm_token_buffer_flush(parser, &token_buffer);
11439 LEX(PM_TOKEN_STRING_CONTENT);
11444 parser->current.end = breakpoint + 1;
11445 lex_mode_pop(parser);
11446 lex_state_set(parser, PM_LEX_STATE_END);
11447 LEX(PM_TOKEN_STRING_END);
11451 if (*breakpoint ==
'\0') {
11452 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1),
true);
11459 if (*breakpoint ==
'\\') {
11460 parser->current.end = breakpoint + 1;
11464 if (parser->current.end == parser->end) {
11469 pm_token_buffer_escape(parser, &token_buffer);
11470 uint8_t peeked = peek(parser);
11478 pm_token_buffer_push_byte(&token_buffer, peeked);
11479 parser->current.end++;
11482 parser->current.end++;
11483 if (peek(parser) !=
'\n') {
11484 pm_token_buffer_push_byte(&token_buffer,
'\r');
11489 pm_token_buffer_push_byte(&token_buffer,
'\n');
11491 if (parser->heredoc_end) {
11495 parser_flush_heredoc_end(parser);
11496 pm_token_buffer_copy(parser, &token_buffer);
11497 LEX(PM_TOKEN_STRING_CONTENT);
11500 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11503 parser->current.end++;
11506 if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
11507 pm_token_buffer_push_byte(&token_buffer, peeked);
11508 parser->current.end++;
11509 }
else if (lex_mode->as.list.interpolation) {
11510 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11512 pm_token_buffer_push_byte(&token_buffer,
'\\');
11513 pm_token_buffer_push_escaped(&token_buffer, parser);
11519 token_buffer.
cursor = parser->current.end;
11520 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11525 if (*breakpoint ==
'#') {
11526 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11533 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11537 if (
type == PM_TOKEN_STRING_CONTENT) {
11538 pm_token_buffer_flush(parser, &token_buffer);
11546 assert(*breakpoint == lex_mode->as.list.incrementor);
11547 parser->current.end = breakpoint + 1;
11548 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11549 lex_mode->as.list.nesting++;
11553 if (parser->current.end > parser->current.start) {
11554 pm_token_buffer_flush(parser, &token_buffer);
11555 LEX(PM_TOKEN_STRING_CONTENT);
11560 parser->current.end = parser->end;
11561 pm_token_buffer_flush(parser, &token_buffer);
11562 LEX(PM_TOKEN_STRING_CONTENT);
11564 case PM_LEX_REGEXP: {
11566 if (parser->next_start == NULL) {
11567 parser->current.start = parser->current.end;
11569 parser->current.start = parser->next_start;
11570 parser->current.end = parser->next_start;
11571 parser->next_start = NULL;
11576 if (parser->current.end >= parser->end) {
11586 const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
11587 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11590 while (breakpoint != NULL) {
11591 uint8_t term = lex_mode->as.regexp.terminator;
11592 bool is_terminator = (*breakpoint == term);
11597 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11598 if (term ==
'\n') {
11599 is_terminator =
true;
11605 if (term ==
'\r') {
11606 is_terminator =
false;
11612 if (is_terminator) {
11613 if (lex_mode->as.regexp.nesting > 0) {
11614 parser->current.end = breakpoint + 1;
11615 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11616 lex_mode->as.regexp.nesting--;
11623 if (breakpoint > parser->current.start) {
11624 parser->current.end = breakpoint;
11625 pm_regexp_token_buffer_flush(parser, &token_buffer);
11626 LEX(PM_TOKEN_STRING_CONTENT);
11630 size_t eol_length = match_eol_at(parser, breakpoint);
11632 parser->current.end = breakpoint + eol_length;
11637 if (parser->heredoc_end == NULL) {
11638 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11641 parser->current.end = breakpoint + 1;
11646 parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
11648 lex_mode_pop(parser);
11649 lex_state_set(parser, PM_LEX_STATE_END);
11650 LEX(PM_TOKEN_REGEXP_END);
11655 if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
11656 parser->current.end = breakpoint + 1;
11657 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11658 lex_mode->as.regexp.nesting++;
11662 switch (*breakpoint) {
11665 parser->current.end = breakpoint + 1;
11666 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11669 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11670 parser->current.end = breakpoint + 1;
11671 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11676 parser->current.end = breakpoint;
11677 pm_regexp_token_buffer_escape(parser, &token_buffer);
11684 if (parser->heredoc_end == NULL) {
11685 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
11686 parser->current.end = breakpoint + 1;
11687 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11691 parser->current.end = breakpoint + 1;
11692 parser_flush_heredoc_end(parser);
11693 pm_regexp_token_buffer_flush(parser, &token_buffer);
11694 LEX(PM_TOKEN_STRING_CONTENT);
11699 parser->current.end = breakpoint + 1;
11703 if (parser->current.end == parser->end) {
11708 pm_regexp_token_buffer_escape(parser, &token_buffer);
11709 uint8_t peeked = peek(parser);
11713 parser->current.end++;
11714 if (peek(parser) !=
'\n') {
11715 if (lex_mode->as.regexp.terminator !=
'\r') {
11716 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11718 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11719 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11724 if (parser->heredoc_end) {
11728 parser_flush_heredoc_end(parser);
11729 pm_regexp_token_buffer_copy(parser, &token_buffer);
11730 LEX(PM_TOKEN_STRING_CONTENT);
11733 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11736 parser->current.end++;
11746 if (lex_mode->as.regexp.terminator == peeked) {
11751 case '$':
case ')':
case '*':
case '+':
11752 case '.':
case '>':
case '?':
case ']':
11753 case '^':
case '|':
case '}':
11754 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11760 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11761 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11762 parser->current.end++;
11766 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11767 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11771 token_buffer.
base.
cursor = parser->current.end;
11772 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11778 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11785 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11789 if (
type == PM_TOKEN_STRING_CONTENT) {
11790 pm_regexp_token_buffer_flush(parser, &token_buffer);
11796 assert(
false &&
"unreachable");
11801 if (parser->current.end > parser->current.start) {
11802 pm_regexp_token_buffer_flush(parser, &token_buffer);
11803 LEX(PM_TOKEN_STRING_CONTENT);
11808 parser->current.end = parser->end;
11809 pm_regexp_token_buffer_flush(parser, &token_buffer);
11810 LEX(PM_TOKEN_STRING_CONTENT);
11812 case PM_LEX_STRING: {
11814 if (parser->next_start == NULL) {
11815 parser->current.start = parser->current.end;
11817 parser->current.start = parser->next_start;
11818 parser->current.end = parser->next_start;
11819 parser->next_start = NULL;
11824 if (parser->current.end >= parser->end) {
11831 const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
11832 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11838 while (breakpoint != NULL) {
11841 if (lex_mode->as.string.incrementor !=
'\0' && *breakpoint == lex_mode->as.string.incrementor) {
11842 lex_mode->as.string.nesting++;
11843 parser->current.end = breakpoint + 1;
11844 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11848 uint8_t term = lex_mode->as.string.terminator;
11849 bool is_terminator = (*breakpoint == term);
11854 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11855 if (term ==
'\n') {
11856 is_terminator =
true;
11862 if (term ==
'\r') {
11863 is_terminator =
false;
11870 if (is_terminator) {
11873 if (lex_mode->as.string.nesting > 0) {
11874 parser->current.end = breakpoint + 1;
11875 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11876 lex_mode->as.string.nesting--;
11882 if (breakpoint > parser->current.start) {
11883 parser->current.end = breakpoint;
11884 pm_token_buffer_flush(parser, &token_buffer);
11885 LEX(PM_TOKEN_STRING_CONTENT);
11890 size_t eol_length = match_eol_at(parser, breakpoint);
11892 parser->current.end = breakpoint + eol_length;
11897 if (parser->heredoc_end == NULL) {
11898 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11901 parser->current.end = breakpoint + 1;
11904 if (lex_mode->as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
11905 parser->current.end++;
11906 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
11907 lex_mode_pop(parser);
11908 LEX(PM_TOKEN_LABEL_END);
11914 if (term ==
'\n' && parser->heredoc_end) {
11915 parser_flush_heredoc_end(parser);
11918 lex_state_set(parser, PM_LEX_STATE_END);
11919 lex_mode_pop(parser);
11920 LEX(PM_TOKEN_STRING_END);
11923 switch (*breakpoint) {
11926 parser->current.end = breakpoint + 1;
11927 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11930 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11931 parser->current.end = breakpoint + 1;
11932 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11939 parser->current.end = breakpoint;
11940 pm_token_buffer_escape(parser, &token_buffer);
11941 token_buffer.
cursor = breakpoint;
11949 if (parser->heredoc_end == NULL) {
11950 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
11951 parser->current.end = breakpoint + 1;
11952 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11956 parser->current.end = breakpoint + 1;
11957 parser_flush_heredoc_end(parser);
11958 pm_token_buffer_flush(parser, &token_buffer);
11959 LEX(PM_TOKEN_STRING_CONTENT);
11962 parser->current.end = breakpoint + 1;
11966 if (parser->current.end == parser->end) {
11971 pm_token_buffer_escape(parser, &token_buffer);
11972 uint8_t peeked = peek(parser);
11976 pm_token_buffer_push_byte(&token_buffer,
'\\');
11977 parser->current.end++;
11980 parser->current.end++;
11981 if (peek(parser) !=
'\n') {
11982 if (!lex_mode->as.string.interpolation) {
11983 pm_token_buffer_push_byte(&token_buffer,
'\\');
11985 pm_token_buffer_push_byte(&token_buffer,
'\r');
11990 if (!lex_mode->as.string.interpolation) {
11991 pm_token_buffer_push_byte(&token_buffer,
'\\');
11992 pm_token_buffer_push_byte(&token_buffer,
'\n');
11995 if (parser->heredoc_end) {
11999 parser_flush_heredoc_end(parser);
12000 pm_token_buffer_copy(parser, &token_buffer);
12001 LEX(PM_TOKEN_STRING_CONTENT);
12004 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
12007 parser->current.end++;
12010 if (lex_mode->as.string.incrementor !=
'\0' && peeked == lex_mode->as.string.incrementor) {
12011 pm_token_buffer_push_byte(&token_buffer, peeked);
12012 parser->current.end++;
12013 }
else if (lex_mode->as.string.terminator !=
'\0' && peeked == lex_mode->as.string.terminator) {
12014 pm_token_buffer_push_byte(&token_buffer, peeked);
12015 parser->current.end++;
12016 }
else if (lex_mode->as.string.interpolation) {
12017 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12019 pm_token_buffer_push_byte(&token_buffer,
'\\');
12020 pm_token_buffer_push_escaped(&token_buffer, parser);
12026 token_buffer.
cursor = parser->current.end;
12027 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12031 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12038 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12042 if (
type == PM_TOKEN_STRING_CONTENT) {
12043 pm_token_buffer_flush(parser, &token_buffer);
12049 assert(
false &&
"unreachable");
12053 if (parser->current.end > parser->current.start) {
12054 pm_token_buffer_flush(parser, &token_buffer);
12055 LEX(PM_TOKEN_STRING_CONTENT);
12060 parser->current.end = parser->end;
12061 pm_token_buffer_flush(parser, &token_buffer);
12062 LEX(PM_TOKEN_STRING_CONTENT);
12064 case PM_LEX_HEREDOC: {
12066 if (parser->next_start == NULL) {
12067 parser->current.start = parser->current.end;
12069 parser->current.start = parser->next_start;
12070 parser->current.end = parser->next_start;
12071 parser->heredoc_end = NULL;
12072 parser->next_start = NULL;
12080 bool line_continuation = lex_mode->as.heredoc.line_continuation;
12081 lex_mode->as.heredoc.line_continuation =
false;
12087 if (parser->current.end >= parser->end) {
12088 pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
12089 parser->next_start = lex_mode->as.heredoc.next_start;
12090 parser->heredoc_end = parser->current.end;
12091 lex_state_set(parser, PM_LEX_STATE_END);
12092 lex_mode_pop(parser);
12093 LEX(PM_TOKEN_HEREDOC_END);
12096 const uint8_t *ident_start = heredoc_lex_mode->ident_start;
12097 size_t ident_length = heredoc_lex_mode->ident_length;
12101 if (current_token_starts_line(parser)) {
12102 const uint8_t *start = parser->current.start;
12104 if (!line_continuation && (start + ident_length <= parser->end)) {
12105 const uint8_t *newline = next_newline(start, parser->end - start);
12106 const uint8_t *ident_end = newline;
12107 const uint8_t *terminator_end = newline;
12109 if (newline == NULL) {
12110 terminator_end = parser->end;
12111 ident_end = parser->end;
12114 if (newline[-1] ==
'\r') {
12119 const uint8_t *terminator_start = ident_end - ident_length;
12120 const uint8_t *cursor = start;
12122 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12123 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12129 (cursor == terminator_start) &&
12130 (memcmp(terminator_start, ident_start, ident_length) == 0)
12132 if (newline != NULL) {
12133 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
12136 parser->current.end = terminator_end;
12137 if (*lex_mode->as.heredoc.next_start ==
'\\') {
12138 parser->next_start = NULL;
12140 parser->next_start = lex_mode->as.heredoc.next_start;
12141 parser->heredoc_end = parser->current.end;
12144 lex_state_set(parser, PM_LEX_STATE_END);
12145 lex_mode_pop(parser);
12146 LEX(PM_TOKEN_HEREDOC_END);
12150 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
12152 heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
12153 lex_mode->as.heredoc.common_whitespace != NULL &&
12154 (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
12155 peek_at(parser, start) !=
'\n'
12157 *lex_mode->as.heredoc.common_whitespace = whitespace;
12164 uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] =
"\r\n\\#";
12166 pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
12167 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12168 breakpoints[3] =
'\0';
12171 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12173 bool was_line_continuation =
false;
12175 while (breakpoint != NULL) {
12176 switch (*breakpoint) {
12179 parser->current.end = breakpoint + 1;
12180 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12183 parser->current.end = breakpoint + 1;
12185 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12186 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12193 pm_token_buffer_escape(parser, &token_buffer);
12194 token_buffer.
cursor = breakpoint;
12198 if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
12199 parser_flush_heredoc_end(parser);
12200 parser->current.end = breakpoint + 1;
12201 pm_token_buffer_flush(parser, &token_buffer);
12202 LEX(PM_TOKEN_STRING_CONTENT);
12205 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12209 const uint8_t *start = breakpoint + 1;
12211 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12214 const uint8_t *newline = next_newline(start, parser->end - start);
12216 if (newline == NULL) {
12217 newline = parser->end;
12218 }
else if (newline[-1] ==
'\r') {
12223 const uint8_t *terminator_start = newline - ident_length;
12227 const uint8_t *cursor = start;
12229 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12230 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12236 cursor == terminator_start &&
12237 (memcmp(terminator_start, ident_start, ident_length) == 0)
12239 parser->current.end = breakpoint + 1;
12240 pm_token_buffer_flush(parser, &token_buffer);
12241 LEX(PM_TOKEN_STRING_CONTENT);
12245 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
12252 if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12253 if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12254 *lex_mode->as.heredoc.common_whitespace = whitespace;
12257 parser->current.end = breakpoint + 1;
12258 pm_token_buffer_flush(parser, &token_buffer);
12259 LEX(PM_TOKEN_STRING_CONTENT);
12264 parser->current.end = breakpoint + 1;
12265 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12275 parser->current.end = breakpoint + 1;
12279 if (parser->current.end == parser->end) {
12284 pm_token_buffer_escape(parser, &token_buffer);
12285 uint8_t peeked = peek(parser);
12287 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12290 parser->current.end++;
12291 if (peek(parser) !=
'\n') {
12292 pm_token_buffer_push_byte(&token_buffer,
'\\');
12293 pm_token_buffer_push_byte(&token_buffer,
'\r');
12298 pm_token_buffer_push_byte(&token_buffer,
'\\');
12299 pm_token_buffer_push_byte(&token_buffer,
'\n');
12300 token_buffer.
cursor = parser->current.end + 1;
12301 breakpoint = parser->current.end;
12304 pm_token_buffer_push_byte(&token_buffer,
'\\');
12305 pm_token_buffer_push_escaped(&token_buffer, parser);
12311 parser->current.end++;
12312 if (peek(parser) !=
'\n') {
12313 pm_token_buffer_push_byte(&token_buffer,
'\r');
12321 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12322 const uint8_t *end = parser->current.end;
12324 if (parser->heredoc_end == NULL) {
12325 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
12330 parser->current.end = breakpoint;
12331 pm_token_buffer_flush(parser, &token_buffer);
12335 parser->current.end = end + 1;
12336 lex_mode->as.heredoc.line_continuation =
true;
12337 LEX(PM_TOKEN_STRING_CONTENT);
12340 was_line_continuation =
true;
12341 token_buffer.
cursor = parser->current.end + 1;
12342 breakpoint = parser->current.end;
12345 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12350 token_buffer.
cursor = parser->current.end;
12351 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12355 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12363 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12367 if (
type == PM_TOKEN_STRING_CONTENT) {
12368 pm_token_buffer_flush(parser, &token_buffer);
12374 assert(
false &&
"unreachable");
12377 was_line_continuation =
false;
12380 if (parser->current.end > parser->current.start) {
12381 parser->current.end = parser->end;
12382 pm_token_buffer_flush(parser, &token_buffer);
12383 LEX(PM_TOKEN_STRING_CONTENT);
12388 parser->current.end = parser->end;
12389 pm_token_buffer_flush(parser, &token_buffer);
12390 LEX(PM_TOKEN_STRING_CONTENT);
12394 assert(
false &&
"unreachable");
12412 PM_BINDING_POWER_UNSET = 0,
12413 PM_BINDING_POWER_STATEMENT = 2,
12414 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12415 PM_BINDING_POWER_MODIFIER = 6,
12416 PM_BINDING_POWER_COMPOSITION = 8,
12417 PM_BINDING_POWER_NOT = 10,
12418 PM_BINDING_POWER_MATCH = 12,
12419 PM_BINDING_POWER_DEFINED = 14,
12420 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12421 PM_BINDING_POWER_ASSIGNMENT = 18,
12422 PM_BINDING_POWER_TERNARY = 20,
12423 PM_BINDING_POWER_RANGE = 22,
12424 PM_BINDING_POWER_LOGICAL_OR = 24,
12425 PM_BINDING_POWER_LOGICAL_AND = 26,
12426 PM_BINDING_POWER_EQUALITY = 28,
12427 PM_BINDING_POWER_COMPARISON = 30,
12428 PM_BINDING_POWER_BITWISE_OR = 32,
12429 PM_BINDING_POWER_BITWISE_AND = 34,
12430 PM_BINDING_POWER_SHIFT = 36,
12431 PM_BINDING_POWER_TERM = 38,
12432 PM_BINDING_POWER_FACTOR = 40,
12433 PM_BINDING_POWER_UMINUS = 42,
12434 PM_BINDING_POWER_EXPONENT = 44,
12435 PM_BINDING_POWER_UNARY = 46,
12436 PM_BINDING_POWER_INDEX = 48,
12437 PM_BINDING_POWER_CALL = 50,
12438 PM_BINDING_POWER_MAX = 52
12439} pm_binding_power_t;
12462#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12463#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12464#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12465#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12466#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12470 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12473 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12474 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12475 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12476 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12479 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12480 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12483 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12484 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12487 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12488 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12489 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12490 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12491 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12492 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12493 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12494 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12495 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12496 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12497 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12498 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12499 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12500 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12503 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12506 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12507 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12508 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12509 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12512 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12515 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12518 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12519 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12520 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12521 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12522 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12523 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12526 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12527 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12528 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12529 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12532 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12533 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12536 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12539 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12540 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12543 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12544 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12547 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12548 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12549 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12550 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12553 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12554 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12557 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12558 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12561 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12562 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12563 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12566 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12569 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12570 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12571 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12574#undef BINDING_POWER_ASSIGNMENT
12575#undef LEFT_ASSOCIATIVE
12576#undef RIGHT_ASSOCIATIVE
12577#undef RIGHT_ASSOCIATIVE_UNARY
12584 return parser->current.type ==
type;
12591match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12592 return match1(parser, type1) || match1(parser, type2);
12599match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12600 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12607match4(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4) {
12608 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12615match6(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6) {
12616 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
12623match7(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7) {
12624 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
12631match8(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3, pm_token_type_t type4, pm_token_type_t type5, pm_token_type_t type6, pm_token_type_t type7, pm_token_type_t type8) {
12632 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);
12643 if (match1(parser,
type)) {
12644 parser_lex(parser);
12655accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12656 if (match2(parser, type1, type2)) {
12657 parser_lex(parser);
12675expect1(
pm_parser_t *parser, pm_token_type_t
type, pm_diagnostic_id_t diag_id) {
12676 if (accept1(parser,
type))
return;
12678 const uint8_t *location = parser->previous.
end;
12679 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12681 parser->previous.
start = location;
12682 parser->previous.
type = 0;
12690expect2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
12691 if (accept2(parser, type1, type2))
return;
12693 const uint8_t *location = parser->previous.
end;
12694 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12696 parser->previous.
start = location;
12697 parser->previous.
type = 0;
12705expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12706 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12707 parser_lex(parser);
12709 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12710 parser->previous.
start = parser->previous.
end;
12711 parser->previous.
type = 0;
12723 if (accept1(parser,
type))
return;
12725 const uint8_t *start = opening->
start;
12726 pm_parser_err(parser, U32(start - parser->start), U32(opening->
end - start), diag_id);
12728 parser->previous.
start = parser->previous.
end;
12729 parser->previous.
type = 0;
12733#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
12734#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
12735#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
12736#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
12739parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
12746parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
12747 pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
12748 pm_assert_value_expression(parser, node);
12771token_begins_expression_p(pm_token_type_t
type) {
12773 case PM_TOKEN_EQUAL_GREATER:
12774 case PM_TOKEN_KEYWORD_IN:
12778 case PM_TOKEN_BRACE_RIGHT:
12779 case PM_TOKEN_BRACKET_RIGHT:
12780 case PM_TOKEN_COLON:
12781 case PM_TOKEN_COMMA:
12782 case PM_TOKEN_EMBEXPR_END:
12784 case PM_TOKEN_LAMBDA_BEGIN:
12785 case PM_TOKEN_KEYWORD_DO:
12786 case PM_TOKEN_KEYWORD_DO_BLOCK:
12787 case PM_TOKEN_KEYWORD_DO_LOOP:
12788 case PM_TOKEN_KEYWORD_END:
12789 case PM_TOKEN_KEYWORD_ELSE:
12790 case PM_TOKEN_KEYWORD_ELSIF:
12791 case PM_TOKEN_KEYWORD_ENSURE:
12792 case PM_TOKEN_KEYWORD_THEN:
12793 case PM_TOKEN_KEYWORD_RESCUE:
12794 case PM_TOKEN_KEYWORD_WHEN:
12795 case PM_TOKEN_NEWLINE:
12796 case PM_TOKEN_PARENTHESIS_RIGHT:
12797 case PM_TOKEN_SEMICOLON:
12803 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12805 case PM_TOKEN_UAMPERSAND:
12809 case PM_TOKEN_UCOLON_COLON:
12810 case PM_TOKEN_UMINUS:
12811 case PM_TOKEN_UMINUS_NUM:
12812 case PM_TOKEN_UPLUS:
12813 case PM_TOKEN_BANG:
12814 case PM_TOKEN_TILDE:
12815 case PM_TOKEN_UDOT_DOT:
12816 case PM_TOKEN_UDOT_DOT_DOT:
12823 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
12832parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
12833 if (accept1(parser, PM_TOKEN_USTAR)) {
12835 pm_node_t *expression = parse_value_expression(parser, binding_power, (uint8_t) (flags & PM_PARSE_ACCEPTS_DO_BLOCK), PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
12836 return UP(pm_splat_node_create(parser, &
operator, expression));
12839 return parse_value_expression(parser, binding_power, flags, diag_id, depth);
12843pm_node_unreference_each(
const pm_node_t *node,
void *data) {
12844 switch (PM_NODE_TYPE(node)) {
12849 case PM_BREAK_NODE:
12851 case PM_REDO_NODE: {
12855 while (index < parser->current_block_exits->size) {
12856 pm_node_t *block_exit = parser->current_block_exits->
nodes[index];
12858 if (block_exit == node) {
12859 if (index + 1 < parser->current_block_exits->
size) {
12861 &parser->current_block_exits->
nodes[index],
12862 &parser->current_block_exits->
nodes[index + 1],
12863 (parser->current_block_exits->
size - index - 1) *
sizeof(
pm_node_t *)
12866 parser->current_block_exits->
size--;
12881 case PM_LOCAL_VARIABLE_READ_NODE:
12882 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12884 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
12886 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
12887 if (implicit_parameters->
nodes[index] == node) {
12891 if (index != implicit_parameters->
size - 1) {
12892 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
12895 implicit_parameters->
size--;
12914 pm_visit_node(node, pm_node_unreference_each, parser);
12927 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *name_field);
12928 size_t length = constant->length;
12929 uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
12931 memcpy(name, constant->start, length);
12932 name[length] =
'=';
12934 *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
12945 switch (PM_NODE_TYPE(target)) {
12946 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12947 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12948 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12949 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12950 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12951 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12952 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
12956 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
12972 switch (PM_NODE_TYPE(target)) {
12973 case PM_ERROR_RECOVERY_NODE:
12975 case PM_SOURCE_ENCODING_NODE:
12976 case PM_FALSE_NODE:
12977 case PM_SOURCE_FILE_NODE:
12978 case PM_SOURCE_LINE_NODE:
12981 case PM_TRUE_NODE: {
12984 return parse_unwriteable_target(parser, target);
12986 case PM_CLASS_VARIABLE_READ_NODE:
12988 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
12990 case PM_CONSTANT_PATH_NODE:
12991 if (context_def_p(parser)) {
12992 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12996 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
12999 case PM_CONSTANT_READ_NODE:
13000 if (context_def_p(parser)) {
13001 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13005 target->
type = PM_CONSTANT_TARGET_NODE;
13008 case PM_BACK_REFERENCE_READ_NODE:
13009 case PM_NUMBERED_REFERENCE_READ_NODE:
13010 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13011 return UP(pm_error_recovery_node_create_unexpected(parser, target));
13012 case PM_GLOBAL_VARIABLE_READ_NODE:
13014 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13016 case PM_LOCAL_VARIABLE_READ_NODE: {
13017 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13018 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
13019 pm_node_unreference(parser, target);
13023 uint32_t name = cast->
name;
13024 uint32_t depth = cast->
depth;
13025 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13028 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13032 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13034 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
13036 pm_node_unreference(parser, target);
13040 case PM_INSTANCE_VARIABLE_READ_NODE:
13042 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13044 case PM_MULTI_TARGET_NODE:
13045 if (splat_parent) {
13048 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13052 case PM_SPLAT_NODE: {
13061 case PM_CALL_NODE: {
13073 (call->
block == NULL)
13086 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
13088 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
13092 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13093 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13096 parse_write_name(parser, &call->
name);
13097 return UP(pm_call_target_node_create(parser, call));
13104 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13105 return UP(pm_index_target_node_create(parser, call));
13113 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13124 pm_node_t *result = parse_target(parser, target, multiple,
false);
13129 !match1(parser, PM_TOKEN_EQUAL) &&
13130 !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
13131 !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13133 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13145 pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
13147 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13148 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
13159 switch (PM_NODE_TYPE(target)) {
13160 case PM_ERROR_RECOVERY_NODE:
13162 case PM_CLASS_VARIABLE_READ_NODE: {
13166 case PM_CONSTANT_PATH_NODE: {
13169 if (context_def_p(parser)) {
13170 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13173 return parse_shareable_constant_write(parser, node);
13175 case PM_CONSTANT_READ_NODE: {
13178 if (context_def_p(parser)) {
13179 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13182 return parse_shareable_constant_write(parser, node);
13184 case PM_BACK_REFERENCE_READ_NODE:
13185 case PM_NUMBERED_REFERENCE_READ_NODE:
13186 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13188 case PM_GLOBAL_VARIABLE_READ_NODE: {
13192 case PM_LOCAL_VARIABLE_READ_NODE: {
13197 uint32_t depth = local_read->
depth;
13198 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13200 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13201 pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13202 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
13203 pm_node_unreference(parser, target);
13206 pm_locals_unread(&scope->locals, name);
13208 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
13210 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13212 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
13214 pm_node_unreference(parser, target);
13218 case PM_INSTANCE_VARIABLE_READ_NODE: {
13222 case PM_MULTI_TARGET_NODE:
13224 case PM_SPLAT_NODE: {
13232 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
13234 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
13236 case PM_CALL_NODE: {
13248 (call->
block == NULL)
13262 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
13263 pm_parser_local_add_location(parser, &message_loc, 0);
13265 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, parser->start + PM_LOCATION_START(&message_loc), parser->start + PM_LOCATION_END(&message_loc));
13266 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
13285 pm_arguments_node_arguments_append(parser->arena, arguments, value);
13286 PM_NODE_LENGTH_SET_NODE(call, arguments);
13287 call->
equal_loc = TOK2LOC(parser,
operator);
13289 parse_write_name(parser, &call->
name);
13290 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13299 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13301 call->
arguments = pm_arguments_node_create(parser);
13304 pm_arguments_node_arguments_append(parser->arena, call->
arguments, value);
13305 PM_NODE_LENGTH_SET_NODE(target, value);
13308 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13309 call->
equal_loc = TOK2LOC(parser,
operator);
13313 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13328 pm_node_unreference(parser, value);
13335 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13348 switch (PM_NODE_TYPE(target)) {
13349 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13350 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13351 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13352 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13353 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13354 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13355 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13376parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13377 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13380 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13382 while (accept1(parser, PM_TOKEN_COMMA)) {
13383 if (accept1(parser, PM_TOKEN_USTAR)) {
13388 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13391 pm_token_t star_operator = parser->previous;
13394 if (token_begins_expression_p(parser->current.type)) {
13395 name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13396 name = parse_target(parser, name,
true,
true);
13399 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13400 pm_multi_target_node_targets_append(parser, result, splat);
13402 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13403 context_push(parser, PM_CONTEXT_MULTI_TARGET);
13404 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13405 target = parse_target(parser, target,
true,
false);
13407 pm_multi_target_node_targets_append(parser, result, target);
13408 context_pop(parser);
13409 }
else if (token_begins_expression_p(parser->current.type)) {
13410 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13411 target = parse_target(parser, target,
true,
false);
13413 pm_multi_target_node_targets_append(parser, result, target);
13414 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13417 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
13418 pm_multi_target_node_targets_append(parser, result, rest);
13431parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13432 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13437 if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
13438 accept1(parser, PM_TOKEN_NEWLINE);
13442 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13443 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13453parse_statements(
pm_parser_t *parser, pm_context_t context, uint16_t depth) {
13456 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13459 if (context_terminator(context, &parser->current))
return NULL;
13465 context_push(parser, context);
13468 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13469 pm_statements_node_body_append(parser, statements, node,
true);
13473 if (parser->recovering) {
13476 if (context_terminator(context, &parser->current)) parser->recovering =
false;
13482 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13485 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13486 if (context_terminator(context, &parser->current))
break;
13496 if (context_terminator(context, &parser->current))
break;
13508 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
13509 parser_lex(parser);
13515 if (match1(parser, PM_TOKEN_EOF)) {
13516 parser->recovering =
true;
13520 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13521 if (context_terminator(context, &parser->current))
break;
13522 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13526 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
13527 parser->previous.
start = parser->previous.
end;
13528 parser->previous.
type = 0;
13532 context_pop(parser);
13534 bool last_value =
true;
13536 case PM_CONTEXT_BEGIN_ENSURE:
13537 case PM_CONTEXT_DEF_ENSURE:
13538 last_value =
false;
13543 pm_void_statements_check(parser, statements, last_value);
13554 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, literals, node,
true);
13556 if (duplicated != NULL) {
13558 pm_static_literal_inspect(&buffer, &parser->line_offsets, parser->start, parser->start_line, parser->encoding->name, duplicated);
13560 pm_diagnostic_list_append_format(
13561 &parser->metadata_arena,
13562 &parser->warning_list,
13565 PM_WARN_DUPLICATED_HASH_KEY,
13566 (
int) pm_buffer_length(&buffer),
13567 pm_buffer_value(&buffer),
13568 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line
13571 pm_buffer_cleanup(&buffer);
13583 if ((previous = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, literals, node,
false)) != NULL) {
13584 pm_diagnostic_list_append_format(
13585 &parser->metadata_arena,
13586 &parser->warning_list,
13587 PM_NODE_START(node),
13588 PM_NODE_LENGTH(node),
13589 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13590 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line,
13591 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).
line
13601 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13602 bool contains_keyword_splat =
false;
13607 switch (parser->current.type) {
13608 case PM_TOKEN_USTAR_STAR: {
13609 parser_lex(parser);
13613 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
13618 parser->current_hash_keys = literals;
13619 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13620 }
else if (token_begins_expression_p(parser->current.type)) {
13621 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13623 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13626 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13627 contains_keyword_splat =
true;
13630 case PM_TOKEN_LABEL: {
13632 parser_lex(parser);
13634 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13635 pm_hash_key_static_literals_add(parser, literals, key);
13639 if (token_begins_expression_p(parser->current.type)) {
13640 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13642 if (parser->encoding->isupper_char(label.
start, (label.
end - 1) - label.
start)) {
13643 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13644 value = UP(pm_constant_read_node_create(parser, &constant));
13649 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13650 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13652 depth = pm_parser_local_depth(parser, &identifier);
13656 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13658 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13663 value = UP(pm_implicit_node_create(parser, value));
13666 element = UP(pm_assoc_node_create(parser, key, NULL, value));
13670 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
13674 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13675 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13678 pm_hash_key_static_literals_add(parser, literals, key);
13681 if (!pm_symbol_node_label_p(parser, key)) {
13682 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13683 operator = parser->previous;
13686 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13687 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
13692 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13693 pm_hash_node_elements_append(parser->arena, (
pm_hash_node_t *) node, element);
13699 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13703 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13707 if (token_begins_expression_p(parser->current.type))
continue;
13713 return contains_keyword_splat;
13718 if (pm_symbol_node_label_p(parser, argument)) {
13722 switch (PM_NODE_TYPE(argument)) {
13723 case PM_CALL_NODE: {
13726 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13729 if (cast->
block != NULL) {
13737 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
13746 arguments->
arguments = pm_arguments_node_create(parser);
13749 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, argument);
13756parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
13757 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
13762 match2(parser, terminator, PM_TOKEN_EOF) ||
13763 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
13764 context_terminator(parser->current_context->context, &parser->current)
13769 bool parsed_first_argument =
false;
13770 bool parsed_bare_hash =
false;
13771 bool parsed_block_argument =
false;
13772 bool parsed_forwarding_arguments =
false;
13774 while (!match1(parser, PM_TOKEN_EOF)) {
13775 if (parsed_forwarding_arguments) {
13776 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
13781 switch (parser->current.type) {
13782 case PM_TOKEN_USTAR_STAR:
13783 case PM_TOKEN_LABEL: {
13784 if (parsed_bare_hash) {
13785 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
13789 argument = UP(hash);
13792 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
13794 parse_arguments_append(parser, arguments, argument);
13796 pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13797 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13798 pm_node_flag_set(UP(arguments->
arguments), node_flags);
13800 pm_static_literals_free(&hash_keys);
13801 parsed_bare_hash =
true;
13805 case PM_TOKEN_UAMPERSAND: {
13806 parser_lex(parser);
13810 if (token_begins_expression_p(parser->current.type)) {
13811 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13813 pm_parser_scope_forwarding_block_check(parser, &
operator);
13816 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
13817 if (parsed_block_argument) {
13818 parse_arguments_append(parser, arguments, argument);
13820 arguments->
block = argument;
13823 if (match1(parser, PM_TOKEN_COMMA)) {
13824 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
13827 parsed_block_argument =
true;
13830 case PM_TOKEN_USTAR: {
13831 parser_lex(parser);
13834 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
13835 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
13836 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
13837 if (parsed_bare_hash) {
13838 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13841 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
13843 if (parsed_bare_hash) {
13844 pm_parser_err(parser, PM_TOKEN_START(parser, &
operator), PM_NODE_END(expression) - PM_TOKEN_START(parser, &
operator), PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13847 argument = UP(pm_splat_node_create(parser, &
operator, expression));
13850 parse_arguments_append(parser, arguments, argument);
13853 case PM_TOKEN_UDOT_DOT_DOT: {
13854 if (accepts_forwarding) {
13855 parser_lex(parser);
13857 if (token_begins_expression_p(parser->current.type)) {
13862 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
13867 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
13869 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
13872 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
13874 pm_parser_scope_forwarding_all_check(parser, &parser->previous);
13875 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
13876 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
13879 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->previous));
13880 parse_arguments_append(parser, arguments, argument);
13881 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
13883 parsed_forwarding_arguments =
true;
13890 if (argument == NULL) {
13891 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (!parsed_first_argument ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0u) | PM_PARSE_ACCEPTS_LABEL), PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13894 bool contains_keywords =
false;
13895 bool contains_keyword_splat =
false;
13897 if (argument_allowed_for_bare_hash(parser, argument)) {
13898 if (parsed_bare_hash) {
13899 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
13903 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
13904 operator = parser->previous;
13908 contains_keywords =
true;
13912 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
13915 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13916 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
13918 pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
13919 argument = UP(bare_hash);
13922 if (accept1(parser, PM_TOKEN_COMMA) && (
13923 token_begins_expression_p(parser->current.type) ||
13924 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
13926 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
13929 pm_static_literals_free(&hash_keys);
13930 parsed_bare_hash =
true;
13933 parse_arguments_append(parser, arguments, argument);
13935 pm_node_flags_t node_flags = 0;
13936 if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13937 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13938 pm_node_flag_set(UP(arguments->
arguments), node_flags);
13944 parsed_first_argument =
true;
13947 if (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_NODE) || parser->recovering)
break;
13952 bool accepted_newline =
false;
13953 if (terminator != PM_TOKEN_EOF) {
13954 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
13957 if (parser->previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
13961 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
13964 if (accepted_newline) {
13965 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13971 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
13974 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13986 if (match1(parser, terminator))
break;
14001parse_required_destructured_parameter(
pm_parser_t *parser) {
14002 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14005 pm_multi_target_node_opening_set(parser, node, &parser->previous);
14014 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14015 param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14016 pm_multi_target_node_targets_append(parser, node, param);
14017 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14021 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14022 param = UP(parse_required_destructured_parameter(parser));
14023 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14027 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14029 value = UP(pm_required_parameter_node_create(parser, &name));
14030 if (pm_parser_parameter_name_check(parser, &name)) {
14031 pm_node_flag_set_repeated_parameter(value);
14033 pm_parser_local_add_token(parser, &name, 1);
14036 param = UP(pm_splat_node_create(parser, &star, value));
14038 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14041 param = UP(pm_required_parameter_node_create(parser, &name));
14042 if (pm_parser_parameter_name_check(parser, &name)) {
14043 pm_node_flag_set_repeated_parameter(param);
14045 pm_parser_local_add_token(parser, &name, 1);
14048 pm_multi_target_node_targets_append(parser, node, param);
14049 }
while (accept1(parser, PM_TOKEN_COMMA));
14051 accept1(parser, PM_TOKEN_NEWLINE);
14052 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14053 pm_multi_target_node_closing_set(parser, node, &parser->previous);
14063 PM_PARAMETERS_NO_CHANGE = 0,
14064 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14065 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14066 PM_PARAMETERS_ORDER_KEYWORDS,
14067 PM_PARAMETERS_ORDER_REST,
14068 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14069 PM_PARAMETERS_ORDER_OPTIONAL,
14070 PM_PARAMETERS_ORDER_NAMED,
14071 PM_PARAMETERS_ORDER_NONE,
14072} pm_parameters_order_t;
14077static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14078 [0] = PM_PARAMETERS_NO_CHANGE,
14079 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14080 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14081 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14082 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14083 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
14084 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14085 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14086 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14087 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14088 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14089 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14101 pm_parameters_order_t state = parameters_ordering[token->type];
14102 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14106 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14107 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14109 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14113 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14114 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14116 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14117 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14119 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14121 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14125 if (state < *current) *current = state;
14130parse_parameters_handle_trailing_comma(
14133 pm_parameters_order_t order,
14135 bool allows_trailing_comma
14137 if (!allows_trailing_comma) {
14138 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14143 if (order >= PM_PARAMETERS_ORDER_NAMED) {
14145 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14147 if (params->
rest == NULL) {
14148 pm_parameters_node_rest_set(params, param);
14150 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14151 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14155 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14160 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
14161 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14172 pm_binding_power_t binding_power,
14173 bool uses_parentheses,
14174 bool allows_trailing_comma,
14175 bool allows_forwarding_parameters,
14176 bool accepts_blocks_in_defaults,
14178 pm_diagnostic_id_t diag_id_forwarding,
14181 pm_do_loop_stack_push(parser,
false);
14184 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14187 bool parsing =
true;
14189 switch (parser->current.type) {
14190 case PM_TOKEN_PARENTHESIS_LEFT: {
14191 update_parameter_state(parser, &parser->current, &order);
14192 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
14194 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14195 pm_parameters_node_requireds_append(parser->arena, params, param);
14197 pm_parameters_node_posts_append(parser->arena, params, param);
14201 case PM_TOKEN_UAMPERSAND:
14202 case PM_TOKEN_AMPERSAND: {
14203 update_parameter_state(parser, &parser->current, &order);
14204 parser_lex(parser);
14209 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14210 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->previous);
14214 bool repeated =
false;
14215 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14216 name = parser->previous;
14217 repeated = pm_parser_parameter_name_check(parser, &name);
14218 pm_parser_local_add_token(parser, &name, 1);
14220 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
14223 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
14225 pm_node_flag_set_repeated_parameter(param);
14229 if (params->
block == NULL) {
14230 pm_parameters_node_block_set(params, param);
14232 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
14233 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14238 case PM_TOKEN_UDOT_DOT_DOT: {
14239 if (!allows_forwarding_parameters) {
14240 pm_parser_err_current(parser, diag_id_forwarding);
14243 bool succeeded = update_parameter_state(parser, &parser->current, &order);
14244 parser_lex(parser);
14246 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
14253 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, keyword_rest)));
14254 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14258 pm_parameters_node_keyword_rest_set(params, UP(param));
14261 case PM_TOKEN_CLASS_VARIABLE:
14262 case PM_TOKEN_IDENTIFIER:
14263 case PM_TOKEN_CONSTANT:
14264 case PM_TOKEN_INSTANCE_VARIABLE:
14265 case PM_TOKEN_GLOBAL_VARIABLE:
14266 case PM_TOKEN_METHOD_NAME: {
14267 parser_lex(parser);
14268 switch (parser->previous.
type) {
14269 case PM_TOKEN_CONSTANT:
14270 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14272 case PM_TOKEN_INSTANCE_VARIABLE:
14273 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14275 case PM_TOKEN_GLOBAL_VARIABLE:
14276 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14278 case PM_TOKEN_CLASS_VARIABLE:
14279 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14281 case PM_TOKEN_METHOD_NAME:
14282 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14287 if (parser->current.type == PM_TOKEN_EQUAL) {
14288 update_parameter_state(parser, &parser->current, &order);
14290 update_parameter_state(parser, &parser->previous, &order);
14294 bool repeated = pm_parser_parameter_name_check(parser, &name);
14295 pm_parser_local_add_token(parser, &name, 1);
14297 if (match1(parser, PM_TOKEN_EQUAL)) {
14299 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14300 parser_lex(parser);
14303 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14305 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14306 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14307 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14312 pm_node_flag_set_repeated_parameter(UP(param));
14314 pm_parameters_node_optionals_append(parser->arena, params, param);
14319 if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14320 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
14323 context_pop(parser);
14328 if (parser->recovering) {
14332 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14335 pm_node_flag_set_repeated_parameter(UP(param));
14337 pm_parameters_node_requireds_append(parser->arena, params, UP(param));
14341 pm_node_flag_set_repeated_parameter(UP(param));
14343 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14348 case PM_TOKEN_LABEL: {
14349 if (!uses_parentheses && !in_block) parser->in_keyword_arg =
true;
14350 update_parameter_state(parser, &parser->current, &order);
14352 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14353 parser_lex(parser);
14359 if (parser->encoding_changed ? parser->encoding->isupper_char(local.
start, local.
end - local.
start) : pm_encoding_utf_8_isupper_char(local.start, local.end - local.start)) {
14360 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14361 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14362 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14365 bool repeated = pm_parser_parameter_name_check(parser, &local);
14366 pm_parser_local_add_token(parser, &local, 1);
14368 switch (parser->current.type) {
14369 case PM_TOKEN_COMMA:
14370 case PM_TOKEN_PARENTHESIS_RIGHT:
14371 case PM_TOKEN_PIPE: {
14372 context_pop(parser);
14374 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14376 pm_node_flag_set_repeated_parameter(param);
14379 pm_parameters_node_keywords_append(parser->arena, params, param);
14382 case PM_TOKEN_SEMICOLON:
14383 case PM_TOKEN_NEWLINE: {
14384 context_pop(parser);
14386 if (uses_parentheses) {
14391 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14393 pm_node_flag_set_repeated_parameter(param);
14396 pm_parameters_node_keywords_append(parser->arena, params, param);
14402 if (token_begins_expression_p(parser->current.type)) {
14404 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14406 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14407 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14408 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14410 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14411 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
14414 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14417 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14421 pm_node_flag_set_repeated_parameter(param);
14424 context_pop(parser);
14425 pm_parameters_node_keywords_append(parser->arena, params, param);
14430 if (parser->recovering) {
14437 parser->in_keyword_arg =
false;
14440 case PM_TOKEN_USTAR:
14441 case PM_TOKEN_STAR: {
14442 update_parameter_state(parser, &parser->current, &order);
14443 parser_lex(parser);
14447 bool repeated =
false;
14449 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14450 name = parser->previous;
14451 repeated = pm_parser_parameter_name_check(parser, &name);
14452 pm_parser_local_add_token(parser, &name, 1);
14454 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
14457 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14459 pm_node_flag_set_repeated_parameter(param);
14462 if (params->
rest == NULL) {
14463 pm_parameters_node_rest_set(params, param);
14465 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14466 pm_parameters_node_posts_append(parser->arena, params, param);
14471 case PM_TOKEN_STAR_STAR:
14472 case PM_TOKEN_USTAR_STAR: {
14473 pm_parameters_order_t previous_order = order;
14474 update_parameter_state(parser, &parser->current, &order);
14475 parser_lex(parser);
14480 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14481 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14482 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14485 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
14489 bool repeated =
false;
14490 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14491 name = parser->previous;
14492 repeated = pm_parser_parameter_name_check(parser, &name);
14493 pm_parser_local_add_token(parser, &name, 1);
14495 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
14498 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14500 pm_node_flag_set_repeated_parameter(param);
14505 pm_parameters_node_keyword_rest_set(params, param);
14507 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14508 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14514 if (parser->previous.
type == PM_TOKEN_COMMA) {
14515 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
14525 if (!parsing)
break;
14527 bool accepted_newline =
false;
14528 if (uses_parentheses) {
14529 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14532 if (accept1(parser, PM_TOKEN_COMMA)) {
14535 if (accepted_newline) {
14536 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14544 pm_do_loop_stack_pop(parser);
14547 if (PM_NODE_START(params) == PM_NODE_END(params)) {
14560 if (parser->heredoc_end == NULL) {
14564 return parser->line_offsets.
size - 1;
14570 return (
size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
14579token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14580 const uint8_t *cursor = parser->start + parser->line_offsets.
offsets[newline_index];
14581 const uint8_t *end = token->start;
14585 newline_index == 0 &&
14586 parser->start[0] == 0xef &&
14587 parser->start[1] == 0xbb &&
14588 parser->start[2] == 0xbf
14591 int64_t column = 0;
14592 for (; cursor < end; cursor++) {
14595 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14602 if (break_on_non_space)
return -1;
14615parser_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) {
14617 if (!parser->warn_mismatched_indentation)
return;
14620 size_t closing_newline_index = token_newline_index(parser);
14621 if (opening_newline_index == closing_newline_index)
return;
14626 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14627 if (!if_after_else && (opening_column == -1))
return;
14631 pm_token_t *closing_token = &parser->current;
14634 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14635 if ((closing_column == -1) || (opening_column == closing_column))
return;
14639 if (allow_indent && (closing_column > opening_column))
return;
14642 PM_PARSER_WARN_FORMAT(
14644 PM_TOKEN_START(parser, closing_token),
14645 PM_TOKEN_LENGTH(closing_token),
14646 PM_WARN_INDENTATION_MISMATCH,
14647 (
int) (closing_token->
end - closing_token->
start),
14648 (
const char *) closing_token->
start,
14649 (
int) (opening_token->
end - opening_token->
start),
14650 (
const char *) opening_token->
start,
14651 ((int32_t) opening_newline_index) + parser->start_line
14656 PM_RESCUES_BEGIN = 1,
14663} pm_rescues_type_t;
14673 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
14674 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14675 parser_lex(parser);
14677 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
14679 switch (parser->current.type) {
14680 case PM_TOKEN_EQUAL_GREATER: {
14684 parser_lex(parser);
14685 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
14687 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14688 reference = parse_target(parser, reference,
false,
false);
14690 pm_rescue_node_reference_set(rescue, reference);
14693 case PM_TOKEN_NEWLINE:
14694 case PM_TOKEN_SEMICOLON:
14695 case PM_TOKEN_KEYWORD_THEN:
14700 if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
14705 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
14706 pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
14710 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
14714 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14715 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
14717 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14718 reference = parse_target(parser, reference,
false,
false);
14720 pm_rescue_node_reference_set(rescue, reference);
14723 }
while (accept1(parser, PM_TOKEN_COMMA));
14728 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14729 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
14733 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
14737 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
14738 pm_accepts_block_stack_push(parser,
true);
14739 pm_context_t context;
14742 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_RESCUE;
break;
14743 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_RESCUE;
break;
14744 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_RESCUE;
break;
14745 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_RESCUE;
break;
14746 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE;
break;
14747 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE;
break;
14748 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE;
break;
14749 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
14753 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
14755 pm_accepts_block_stack_pop(parser);
14756 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14759 if (current == NULL) {
14760 pm_begin_node_rescue_clause_set(parent_node, rescue);
14762 pm_rescue_node_subsequent_set(current, rescue);
14771 if (current != NULL) {
14774 while (clause != NULL) {
14775 PM_NODE_LENGTH_SET_NODE(clause, current);
14781 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
14782 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14783 opening_newline_index = token_newline_index(parser);
14785 else_keyword = parser->current;
14786 opening = &else_keyword;
14788 parser_lex(parser);
14789 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14792 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
14793 pm_accepts_block_stack_push(parser,
true);
14794 pm_context_t context;
14797 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ELSE;
break;
14798 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ELSE;
break;
14799 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ELSE;
break;
14800 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ELSE;
break;
14801 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE;
break;
14802 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE;
break;
14803 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE;
break;
14804 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_ELSE;
break;
14807 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14808 pm_accepts_block_stack_pop(parser);
14810 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14813 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
14814 pm_begin_node_else_clause_set(parent_node, else_clause);
14818 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
14821 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
14822 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14823 pm_token_t ensure_keyword = parser->current;
14825 parser_lex(parser);
14826 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14829 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14830 pm_accepts_block_stack_push(parser,
true);
14831 pm_context_t context;
14834 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ENSURE;
break;
14835 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ENSURE;
break;
14836 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ENSURE;
break;
14837 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ENSURE;
break;
14838 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE;
break;
14839 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE;
break;
14840 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE;
break;
14841 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
14844 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14845 pm_accepts_block_stack_pop(parser);
14847 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14850 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
14851 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
14854 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
14855 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14856 pm_begin_node_end_keyword_set(parser, parent_node, &parser->current);
14859 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
14869 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
14870 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
14873 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
14882parse_block_parameters(
14884 bool allows_trailing_comma,
14886 bool is_lambda_literal,
14887 bool accepts_blocks_in_defaults,
14891 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
14892 if (!is_lambda_literal) {
14893 context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
14895 parameters = parse_parameters(
14897 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
14899 allows_trailing_comma,
14901 accepts_blocks_in_defaults,
14903 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
14904 (uint16_t) (depth + 1)
14906 if (!is_lambda_literal) {
14907 context_pop(parser);
14912 if (opening != NULL) {
14913 accept1(parser, PM_TOKEN_NEWLINE);
14915 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
14917 switch (parser->current.type) {
14918 case PM_TOKEN_CONSTANT:
14919 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14920 parser_lex(parser);
14922 case PM_TOKEN_INSTANCE_VARIABLE:
14923 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14924 parser_lex(parser);
14926 case PM_TOKEN_GLOBAL_VARIABLE:
14927 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14928 parser_lex(parser);
14930 case PM_TOKEN_CLASS_VARIABLE:
14931 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14932 parser_lex(parser);
14935 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
14939 bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
14940 pm_parser_local_add_token(parser, &parser->previous, 1);
14943 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
14945 pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
14946 }
while (accept1(parser, PM_TOKEN_COMMA));
14950 return block_parameters;
14958outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
14959 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
14960 if (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
14971static const char *
const pm_numbered_parameter_names[] = {
14972 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
14982 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
14986 if (parameters != NULL) {
14988 if (implicit_parameters->
size > 0) {
14991 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14992 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
14993 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14994 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
14996 assert(
false &&
"unreachable");
15005 if (implicit_parameters->
size == 0) {
15012 uint8_t numbered_parameter = 0;
15013 bool it_parameter =
false;
15015 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15018 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15019 if (it_parameter) {
15020 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15021 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15022 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15023 }
else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
15024 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15025 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
15026 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->
location.
start + 1] -
'0'));
15028 assert(
false &&
"unreachable");
15030 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15031 if (numbered_parameter > 0) {
15032 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15034 it_parameter =
true;
15039 if (numbered_parameter > 0) {
15042 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15043 scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15045 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
15048 if (it_parameter) {
15049 return UP(pm_it_parameters_node_create(parser, opening, closing));
15059parse_block(
pm_parser_t *parser, uint16_t depth) {
15061 accept1(parser, PM_TOKEN_NEWLINE);
15063 pm_accepts_block_stack_push(parser,
true);
15064 pm_parser_scope_push(parser,
false);
15068 if (accept1(parser, PM_TOKEN_PIPE)) {
15069 pm_token_t block_parameters_opening = parser->previous;
15070 if (match1(parser, PM_TOKEN_PIPE)) {
15071 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15072 parser->command_start =
true;
15073 parser_lex(parser);
15075 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15076 accept1(parser, PM_TOKEN_NEWLINE);
15077 parser->command_start =
true;
15078 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15081 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
15084 accept1(parser, PM_TOKEN_NEWLINE);
15087 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
15088 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15089 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
15092 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
15094 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15095 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15096 pm_accepts_block_stack_push(parser,
true);
15097 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)));
15098 pm_accepts_block_stack_pop(parser);
15101 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15102 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15103 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
15107 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
15111 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
15112 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
15114 pm_parser_scope_pop(parser);
15115 pm_accepts_block_stack_pop(parser);
15117 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
15126parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block, uint8_t flags, uint16_t depth) {
15131 !token_begins_expression_p(parser->current.type) &&
15132 !match6(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_KEYWORD_DO_BLOCK, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)
15137 bool found =
false;
15138 bool parsed_command_args =
false;
15140 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15142 arguments->
opening_loc = TOK2LOC(parser, &parser->previous);
15144 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15145 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15147 pm_accepts_block_stack_push(parser,
true);
15148 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
15150 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15151 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
15152 parser->previous.
start = parser->previous.
end;
15153 parser->previous.
type = 0;
15156 pm_accepts_block_stack_pop(parser);
15157 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15159 }
else if ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
15161 parsed_command_args =
true;
15162 pm_accepts_block_stack_push(parser,
false);
15167 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
15172 if (parser->previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15173 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15176 pm_accepts_block_stack_pop(parser);
15182 if (accepts_block) {
15185 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
15187 block = parse_block(parser, (uint16_t) (depth + 1));
15188 pm_arguments_validate_block(parser, arguments, block);
15189 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15191 block = parse_block(parser, (uint16_t) (depth + 1));
15192 }
else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
15194 block = parse_block(parser, (uint16_t) (depth + 1));
15197 if (block != NULL) {
15199 arguments->
block = UP(block);
15201 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
15203 if (arguments->
block != NULL) {
15205 arguments->
arguments = pm_arguments_node_create(parser);
15207 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, arguments->
block);
15209 arguments->
block = UP(block);
15223 bool in_sclass =
false;
15224 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15225 switch (context_node->context) {
15226 case PM_CONTEXT_BEGIN_ELSE:
15227 case PM_CONTEXT_BEGIN_ENSURE:
15228 case PM_CONTEXT_BEGIN_RESCUE:
15229 case PM_CONTEXT_BEGIN:
15230 case PM_CONTEXT_CASE_IN:
15231 case PM_CONTEXT_CASE_WHEN:
15232 case PM_CONTEXT_DEFAULT_PARAMS:
15233 case PM_CONTEXT_DEFINED:
15234 case PM_CONTEXT_ELSE:
15235 case PM_CONTEXT_ELSIF:
15236 case PM_CONTEXT_EMBEXPR:
15237 case PM_CONTEXT_FOR_INDEX:
15238 case PM_CONTEXT_FOR:
15239 case PM_CONTEXT_IF:
15240 case PM_CONTEXT_LOOP_PREDICATE:
15241 case PM_CONTEXT_MAIN:
15242 case PM_CONTEXT_MULTI_TARGET:
15243 case PM_CONTEXT_PARENS:
15244 case PM_CONTEXT_POSTEXE:
15245 case PM_CONTEXT_PREDICATE:
15246 case PM_CONTEXT_PREEXE:
15247 case PM_CONTEXT_RESCUE_MODIFIER:
15248 case PM_CONTEXT_TERNARY:
15249 case PM_CONTEXT_UNLESS:
15250 case PM_CONTEXT_UNTIL:
15251 case PM_CONTEXT_WHILE:
15255 case PM_CONTEXT_SCLASS_ELSE:
15256 case PM_CONTEXT_SCLASS_ENSURE:
15257 case PM_CONTEXT_SCLASS_RESCUE:
15258 case PM_CONTEXT_SCLASS:
15261 case PM_CONTEXT_CLASS_ELSE:
15262 case PM_CONTEXT_CLASS_ENSURE:
15263 case PM_CONTEXT_CLASS_RESCUE:
15264 case PM_CONTEXT_CLASS:
15265 case PM_CONTEXT_MODULE_ELSE:
15266 case PM_CONTEXT_MODULE_ENSURE:
15267 case PM_CONTEXT_MODULE_RESCUE:
15268 case PM_CONTEXT_MODULE:
15270 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15272 case PM_CONTEXT_BLOCK_BRACES:
15273 case PM_CONTEXT_BLOCK_ELSE:
15274 case PM_CONTEXT_BLOCK_ENSURE:
15275 case PM_CONTEXT_BLOCK_KEYWORDS:
15276 case PM_CONTEXT_BLOCK_RESCUE:
15277 case PM_CONTEXT_BLOCK_PARAMETERS:
15278 case PM_CONTEXT_DEF_ELSE:
15279 case PM_CONTEXT_DEF_ENSURE:
15280 case PM_CONTEXT_DEF_PARAMS:
15281 case PM_CONTEXT_DEF_RESCUE:
15282 case PM_CONTEXT_DEF:
15283 case PM_CONTEXT_LAMBDA_BRACES:
15284 case PM_CONTEXT_LAMBDA_DO_END:
15285 case PM_CONTEXT_LAMBDA_ELSE:
15286 case PM_CONTEXT_LAMBDA_ENSURE:
15287 case PM_CONTEXT_LAMBDA_RESCUE:
15291 case PM_CONTEXT_NONE:
15293 assert(
false &&
"unreachable");
15297 if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
15298 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15308 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15309 switch (context_node->context) {
15310 case PM_CONTEXT_BLOCK_BRACES:
15311 case PM_CONTEXT_BLOCK_KEYWORDS:
15312 case PM_CONTEXT_BLOCK_ELSE:
15313 case PM_CONTEXT_BLOCK_ENSURE:
15314 case PM_CONTEXT_BLOCK_PARAMETERS:
15315 case PM_CONTEXT_BLOCK_RESCUE:
15316 case PM_CONTEXT_DEFINED:
15317 case PM_CONTEXT_FOR:
15318 case PM_CONTEXT_LAMBDA_BRACES:
15319 case PM_CONTEXT_LAMBDA_DO_END:
15320 case PM_CONTEXT_LAMBDA_ELSE:
15321 case PM_CONTEXT_LAMBDA_ENSURE:
15322 case PM_CONTEXT_LAMBDA_RESCUE:
15323 case PM_CONTEXT_LOOP_PREDICATE:
15324 case PM_CONTEXT_UNTIL:
15325 case PM_CONTEXT_WHILE:
15329 case PM_CONTEXT_POSTEXE:
15331 if (context_node->context == PM_CONTEXT_POSTEXE) {
15332 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
15335 if (PM_NODE_TYPE_P(node, PM_NEXT_NODE)) {
15340 case PM_CONTEXT_DEF:
15341 case PM_CONTEXT_DEF_PARAMS:
15342 case PM_CONTEXT_DEF_ELSE:
15343 case PM_CONTEXT_DEF_ENSURE:
15344 case PM_CONTEXT_DEF_RESCUE:
15345 case PM_CONTEXT_MAIN:
15346 case PM_CONTEXT_PREEXE:
15347 case PM_CONTEXT_SCLASS:
15348 case PM_CONTEXT_SCLASS_ELSE:
15349 case PM_CONTEXT_SCLASS_ENSURE:
15350 case PM_CONTEXT_SCLASS_RESCUE:
15360 assert(parser->current_block_exits != NULL);
15361 pm_node_list_append(parser->arena, parser->current_block_exits, node);
15363 case PM_CONTEXT_BEGIN_ELSE:
15364 case PM_CONTEXT_BEGIN_ENSURE:
15365 case PM_CONTEXT_BEGIN_RESCUE:
15366 case PM_CONTEXT_BEGIN:
15367 case PM_CONTEXT_CASE_IN:
15368 case PM_CONTEXT_CASE_WHEN:
15369 case PM_CONTEXT_CLASS_ELSE:
15370 case PM_CONTEXT_CLASS_ENSURE:
15371 case PM_CONTEXT_CLASS_RESCUE:
15372 case PM_CONTEXT_CLASS:
15373 case PM_CONTEXT_DEFAULT_PARAMS:
15374 case PM_CONTEXT_ELSE:
15375 case PM_CONTEXT_ELSIF:
15376 case PM_CONTEXT_EMBEXPR:
15377 case PM_CONTEXT_FOR_INDEX:
15378 case PM_CONTEXT_IF:
15379 case PM_CONTEXT_MODULE_ELSE:
15380 case PM_CONTEXT_MODULE_ENSURE:
15381 case PM_CONTEXT_MODULE_RESCUE:
15382 case PM_CONTEXT_MODULE:
15383 case PM_CONTEXT_MULTI_TARGET:
15384 case PM_CONTEXT_PARENS:
15385 case PM_CONTEXT_PREDICATE:
15386 case PM_CONTEXT_RESCUE_MODIFIER:
15387 case PM_CONTEXT_TERNARY:
15388 case PM_CONTEXT_UNLESS:
15392 case PM_CONTEXT_NONE:
15394 assert(
false &&
"unreachable");
15406 pm_node_list_t *previous_block_exits = parser->current_block_exits;
15407 parser->current_block_exits = current_block_exits;
15408 return previous_block_exits;
15422 switch (PM_NODE_TYPE(block_exit)) {
15423 case PM_BREAK_NODE:
type =
"break";
break;
15424 case PM_NEXT_NODE:
type =
"next";
break;
15425 case PM_REDO_NODE:
type =
"redo";
break;
15426 default: assert(
false &&
"unreachable");
type =
"";
break;
15429 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15432 parser->current_block_exits = previous_block_exits;
15441 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15445 parser->current_block_exits = previous_block_exits;
15446 }
else if (previous_block_exits != NULL) {
15452 pm_node_list_concat(parser->arena, previous_block_exits, parser->current_block_exits);
15453 parser->current_block_exits = previous_block_exits;
15458 flush_block_exits(parser, previous_block_exits);
15463parse_predicate(
pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context,
pm_token_t *then_keyword, uint16_t depth) {
15464 context_push(parser, PM_CONTEXT_PREDICATE);
15465 pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
15466 pm_node_t *predicate = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, error_id, (uint16_t) (depth + 1));
15469 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15471 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15472 predicate_closed =
true;
15473 *then_keyword = parser->previous;
15476 if (!predicate_closed) {
15477 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15480 context_pop(parser);
15485parse_conditional(
pm_parser_t *parser, pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15487 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15492 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15495 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15496 pm_accepts_block_stack_push(parser,
true);
15497 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15498 pm_accepts_block_stack_pop(parser);
15499 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15505 case PM_CONTEXT_IF:
15506 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15508 case PM_CONTEXT_UNLESS:
15509 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
15512 assert(
false &&
"unreachable");
15520 if (context == PM_CONTEXT_IF) {
15521 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15522 if (parser_end_of_line_p(parser)) {
15523 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
15526 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15528 parser_lex(parser);
15530 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15531 pm_accepts_block_stack_push(parser,
true);
15533 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
15534 pm_accepts_block_stack_pop(parser);
15535 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15537 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15543 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15544 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15545 opening_newline_index = token_newline_index(parser);
15547 parser_lex(parser);
15550 pm_accepts_block_stack_push(parser,
true);
15551 pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
15552 pm_accepts_block_stack_pop(parser);
15554 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15555 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15556 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
15558 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
15561 case PM_CONTEXT_IF:
15562 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
15564 case PM_CONTEXT_UNLESS:
15568 assert(
false &&
"unreachable");
15572 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15573 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
15578 case PM_CONTEXT_IF: {
15580 bool recursing =
true;
15582 while (recursing) {
15583 switch (PM_NODE_TYPE(current)) {
15585 pm_if_node_end_keyword_loc_set(parser, (
pm_if_node_t *) current, &parser->previous);
15587 recursing = current != NULL;
15590 pm_else_node_end_keyword_loc_set(parser, (
pm_else_node_t *) current, &parser->previous);
15601 case PM_CONTEXT_UNLESS:
15602 pm_unless_node_end_keyword_loc_set(parser, (
pm_unless_node_t *) parent, &parser->previous);
15605 assert(
false &&
"unreachable");
15609 pop_block_exits(parser, previous_block_exits);
15617#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15618 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15619 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15620 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_BLOCK: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15621 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15622 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15623 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15624 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15625 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15626 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15627 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15633#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15634 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15635 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15636 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15637 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15638 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15639 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15640 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15647#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15648 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15649 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15650 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15651 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15652 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15653 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15654 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15655 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15661#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15662 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15663 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15664 case PM_TOKEN_CLASS_VARIABLE
15670#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15671 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15672 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15673 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15677PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15684parse_unescaped_encoding(
const pm_parser_t *parser) {
15685 if (parser->explicit_encoding != NULL) {
15686 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
15689 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15690 }
else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
15695 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15706parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15707 switch (parser->current.type) {
15714 case PM_TOKEN_STRING_CONTENT: {
15715 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
15716 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15718 parser_lex(parser);
15727 case PM_TOKEN_EMBEXPR_BEGIN: {
15730 parser->explicit_encoding = NULL;
15732 pm_lex_state_t state = parser->lex_state;
15733 int brace_nesting = parser->brace_nesting;
15735 parser->brace_nesting = 0;
15736 lex_state_set(parser, PM_LEX_STATE_BEG);
15737 parser_lex(parser);
15742 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
15743 pm_accepts_block_stack_push(parser,
true);
15744 statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
15745 pm_accepts_block_stack_pop(parser);
15748 parser->brace_nesting = brace_nesting;
15749 lex_state_set(parser, state);
15750 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15755 if (statements != NULL && statements->
body.
size == 1) {
15756 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15759 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
15768 case PM_TOKEN_EMBVAR: {
15771 parser->explicit_encoding = NULL;
15773 lex_state_set(parser, PM_LEX_STATE_BEG);
15774 parser_lex(parser);
15779 switch (parser->current.type) {
15782 case PM_TOKEN_BACK_REFERENCE:
15783 parser_lex(parser);
15784 variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
15788 case PM_TOKEN_NUMBERED_REFERENCE:
15789 parser_lex(parser);
15790 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
15794 case PM_TOKEN_GLOBAL_VARIABLE:
15795 parser_lex(parser);
15796 variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
15800 case PM_TOKEN_INSTANCE_VARIABLE:
15801 parser_lex(parser);
15802 variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
15806 case PM_TOKEN_CLASS_VARIABLE:
15807 parser_lex(parser);
15808 variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
15814 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15815 variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
15819 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15822 parser_lex(parser);
15823 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15833static const uint8_t *
15834parse_operator_symbol_name(
const pm_token_t *name) {
15835 switch (name->
type) {
15836 case PM_TOKEN_TILDE:
15837 case PM_TOKEN_BANG:
15838 if (name->
end[-1] ==
'@')
return name->
end - 1;
15847 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
15848 const uint8_t *end = parse_operator_symbol_name(&parser->current);
15850 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15851 parser_lex(parser);
15853 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, end);
15854 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15866 const pm_token_t opening = parser->previous;
15868 if (lex_mode->mode != PM_LEX_STRING) {
15869 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15871 switch (parser->current.type) {
15872 case PM_CASE_OPERATOR:
15873 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15874 case PM_TOKEN_IDENTIFIER:
15875 case PM_TOKEN_CONSTANT:
15876 case PM_TOKEN_INSTANCE_VARIABLE:
15877 case PM_TOKEN_METHOD_NAME:
15878 case PM_TOKEN_CLASS_VARIABLE:
15879 case PM_TOKEN_GLOBAL_VARIABLE:
15880 case PM_TOKEN_NUMBERED_REFERENCE:
15881 case PM_TOKEN_BACK_REFERENCE:
15882 case PM_CASE_KEYWORD:
15883 parser_lex(parser);
15886 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15890 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
15891 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
15892 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->
unescaped,
false));
15897 if (lex_mode->as.string.interpolation) {
15899 if (match1(parser, PM_TOKEN_STRING_END)) {
15900 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15901 parser_lex(parser);
15903 .
type = PM_TOKEN_STRING_CONTENT,
15904 .start = parser->previous.
start,
15905 .end = parser->previous.
start
15908 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
15912 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15916 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15917 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15918 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15920 return UP(pm_string_node_to_symbol_node(parser, (
pm_string_node_t *) part, &opening, &parser->previous));
15924 if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
15926 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15927 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15928 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
15932 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15933 if (match1(parser, PM_TOKEN_EOF)) {
15934 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15936 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15939 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
15946 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15947 content = parser->current;
15948 unescaped = parser->current_string;
15949 parser_lex(parser);
15960 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15962 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
15963 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
15965 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
15966 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
15968 if (next_state != PM_LEX_STATE_NONE) {
15969 lex_state_set(parser, next_state);
15972 parser_lex(parser);
15973 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15975 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
15979 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.
end, .end = parser->previous.
end };
15980 pm_string_shared_init(&unescaped, content.
start, content.
end);
15983 if (next_state != PM_LEX_STATE_NONE) {
15984 lex_state_set(parser, next_state);
15987 if (match1(parser, PM_TOKEN_EOF)) {
15988 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15990 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15993 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
16001parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16002 switch (parser->current.type) {
16003 case PM_CASE_OPERATOR:
16004 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
16005 case PM_CASE_KEYWORD:
16006 case PM_TOKEN_CONSTANT:
16007 case PM_TOKEN_IDENTIFIER:
16008 case PM_TOKEN_METHOD_NAME: {
16009 parser_lex(parser);
16011 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16012 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16013 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->
unescaped,
false));
16017 case PM_TOKEN_SYMBOL_BEGIN: {
16019 parser_lex(parser);
16021 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16024 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16025 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16036parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16037 switch (parser->current.type) {
16038 case PM_CASE_OPERATOR:
16039 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16040 case PM_CASE_KEYWORD:
16041 case PM_TOKEN_CONSTANT:
16042 case PM_TOKEN_IDENTIFIER:
16043 case PM_TOKEN_METHOD_NAME: {
16044 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16045 parser_lex(parser);
16047 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16048 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16049 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->
unescaped,
false));
16053 case PM_TOKEN_SYMBOL_BEGIN: {
16055 parser_lex(parser);
16057 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16059 case PM_TOKEN_BACK_REFERENCE:
16060 parser_lex(parser);
16061 return UP(pm_back_reference_read_node_create(parser, &parser->previous));
16062 case PM_TOKEN_NUMBERED_REFERENCE:
16063 parser_lex(parser);
16064 return UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16065 case PM_TOKEN_GLOBAL_VARIABLE:
16066 parser_lex(parser);
16067 return UP(pm_global_variable_read_node_create(parser, &parser->previous));
16069 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16070 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16080 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
16082 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
16084 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16085 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth,
false));
16088 pm_scope_t *current_scope = parser->current_scope;
16089 if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16090 if (is_numbered_param) {
16095 uint8_t maximum = (uint8_t) (parser->previous.
start[1] -
'0');
16096 for (uint8_t number = 1; number <= maximum; number++) {
16097 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16100 if (!match1(parser, PM_TOKEN_EQUAL)) {
16101 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
16104 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0,
false));
16105 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16108 }
else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.
start, parser->previous.
end)) {
16109 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16110 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16124 pm_node_flags_t flags = 0;
16126 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.
end[-1] !=
'!') && (parser->previous.
end[-1] !=
'?')) {
16127 pm_node_t *node = parse_variable(parser);
16128 if (node != NULL)
return node;
16129 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16132 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
16133 pm_node_flag_set(UP(node), flags);
16144parse_method_definition_name(
pm_parser_t *parser) {
16145 switch (parser->current.type) {
16146 case PM_CASE_KEYWORD:
16147 case PM_TOKEN_CONSTANT:
16148 case PM_TOKEN_METHOD_NAME:
16149 parser_lex(parser);
16150 return parser->previous;
16151 case PM_TOKEN_IDENTIFIER:
16152 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
16153 parser_lex(parser);
16154 return parser->previous;
16155 case PM_CASE_OPERATOR:
16156 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16157 parser_lex(parser);
16158 return parser->previous;
16160 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
16161 return (
pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end };
16172 if (string->
type != PM_STRING_OWNED) {
16173 size_t length = pm_string_length(
string);
16174 writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(
string), length,
PRISM_ALIGNOF(uint8_t));
16175 pm_string_constant_init(
string, (
const char *) writable, length);
16177 writable = (uint8_t *) string->
source;
16183 size_t dest_length = pm_string_length(
string);
16184 const uint8_t *source_cursor = writable;
16185 const uint8_t *source_end = source_cursor + dest_length;
16190 size_t trimmed_whitespace = 0;
16196 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16197 if (*source_cursor ==
'\t') {
16198 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16199 if (trimmed_whitespace > common_whitespace)
break;
16201 trimmed_whitespace++;
16208 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
16209 string->length = dest_length;
16219 const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->
content_loc);
16220 return pm_memchr(cursor,
'\\', string_node->
content_loc.
length, parser->encoding_changed, parser->encoding) == NULL;
16232 bool dedent_next =
true;
16236 size_t write_index = 0;
16243 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16244 nodes->
nodes[write_index++] = node;
16245 dedent_next =
false;
16251 parse_heredoc_dedent_string(parser->arena, &string_node->
unescaped, common_whitespace);
16254 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16256 nodes->
nodes[write_index++] = node;
16260 dedent_next =
true;
16263 nodes->
size = write_index;
16270parse_strings_empty_content(
const uint8_t *location) {
16271 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16279 assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
16280 bool concating =
false;
16282 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16288 assert(lex_mode->mode == PM_LEX_STRING);
16289 bool lex_interpolation = lex_mode->as.string.interpolation;
16290 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
16293 parser_lex(parser);
16295 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16296 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16300 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
16301 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->previous);
16305 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16309 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
16310 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
start);
16313 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16314 }
else if (!lex_interpolation) {
16320 if (match1(parser, PM_TOKEN_EOF)) {
16321 unescaped = PM_STRING_EMPTY;
16322 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
16324 unescaped = parser->current_string;
16325 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16326 content = parser->previous;
16340 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16342 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16343 pm_node_list_append(parser->arena, &parts, part);
16346 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16347 pm_node_list_append(parser->arena, &parts, part);
16348 parser_lex(parser);
16349 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16351 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16352 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16353 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16354 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16355 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16356 }
else if (match1(parser, PM_TOKEN_EOF)) {
16357 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16358 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16359 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16360 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16362 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.
type));
16363 parser->previous.
start = parser->previous.
end;
16364 parser->previous.
type = 0;
16365 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16367 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16374 parser_lex(parser);
16376 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16377 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16378 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16384 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16385 const uint8_t *location = parser->previous.
end;
16386 if (location > parser->start && location[-1] ==
'\n') location--;
16387 pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
16389 parser->previous.
start = parser->previous.
end;
16390 parser->previous.
type = 0;
16392 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16393 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16394 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16399 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
16400 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16401 pm_node_list_append(parser->arena, &parts, part);
16403 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16404 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16405 pm_node_list_append(parser->arena, &parts, part);
16409 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16410 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16411 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16412 }
else if (match1(parser, PM_TOKEN_EOF)) {
16413 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16414 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16416 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16417 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16427 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16428 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16429 pm_node_list_append(parser->arena, &parts, part);
16433 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16434 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16435 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16436 }
else if (match1(parser, PM_TOKEN_EOF)) {
16437 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16438 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16440 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16441 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16445 if (current == NULL) {
16449 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16460 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16461 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16467 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16468 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16473 pm_interpolated_string_node_append(parser, container, current);
16474 current = UP(container);
16484#define PM_PARSE_PATTERN_SINGLE 0
16485#define PM_PARSE_PATTERN_TOP 1
16486#define PM_PARSE_PATTERN_MULTI 2
16499 if (peek_at(parser, parser->start + location->
start) ==
'_')
return;
16501 if (pm_constant_id_list_includes(captures, capture)) {
16502 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16504 pm_constant_id_list_append(parser->arena, captures, capture);
16515 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16517 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16518 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
16524 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16532 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16533 opening = parser->previous;
16534 accept1(parser, PM_TOKEN_NEWLINE);
16536 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16537 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16538 accept1(parser, PM_TOKEN_NEWLINE);
16539 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16542 closing = parser->previous;
16544 parser_lex(parser);
16545 opening = parser->previous;
16546 accept1(parser, PM_TOKEN_NEWLINE);
16548 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16549 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16550 accept1(parser, PM_TOKEN_NEWLINE);
16551 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16554 closing = parser->previous;
16560 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16567 switch (PM_NODE_TYPE(inner)) {
16568 case PM_ARRAY_PATTERN_NODE: {
16572 PM_NODE_START_SET_NODE(pattern_node, node);
16573 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16576 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16577 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16579 return UP(pattern_node);
16584 case PM_FIND_PATTERN_NODE: {
16588 PM_NODE_START_SET_NODE(pattern_node, node);
16589 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16592 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16593 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16595 return UP(pattern_node);
16600 case PM_HASH_PATTERN_NODE: {
16604 PM_NODE_START_SET_NODE(pattern_node, node);
16605 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16608 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16609 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16611 return UP(pattern_node);
16623 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16624 pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
16625 return UP(pattern_node);
16633 assert(parser->previous.
type == PM_TOKEN_USTAR);
16640 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16641 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
16644 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16645 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
16648 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
16649 name = UP(pm_local_variable_target_node_create(
16651 &TOK2LOC(parser, &parser->previous),
16653 (uint32_t) (depth == -1 ? 0 : depth)
16658 return pm_splat_node_create(parser, &
operator, name);
16666 assert(parser->current.type == PM_TOKEN_USTAR_STAR);
16667 parser_lex(parser);
16672 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16673 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
16676 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16677 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
16680 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16681 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
16684 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
16685 value = UP(pm_local_variable_target_node_create(
16687 &TOK2LOC(parser, &parser->previous),
16689 (uint32_t) (depth == -1 ? 0 : depth)
16693 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16701pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16702 ptrdiff_t length = end - start;
16703 if (length == 0)
return false;
16706 size_t width = char_is_identifier_start(parser, start, end - start);
16707 if (width == 0)
return false;
16710 if (parser->encoding_changed) {
16711 if (parser->encoding->isupper_char(start, length))
return false;
16713 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16718 const uint8_t *cursor = start + width;
16719 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16720 return cursor == end;
16730 const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
16731 const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
16733 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
16736 if (pm_slice_is_valid_local(parser, start, end)) {
16737 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16739 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
16741 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
16742 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
16747 pm_parser_local_add(parser, constant_id, start, end, 0);
16750 parse_pattern_capture(parser, captures, constant_id, value_loc);
16755 (uint32_t) (depth == -1 ? 0 : depth)
16758 return UP(pm_implicit_node_create(parser, UP(target)));
16767 if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, keys, node,
true) != NULL) {
16768 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16781 switch (PM_NODE_TYPE(first_node)) {
16782 case PM_ASSOC_SPLAT_NODE:
16783 case PM_NO_KEYWORDS_PARAMETER_NODE:
16786 case PM_INTERPOLATED_SYMBOL_NODE:
16787 case PM_SYMBOL_NODE: {
16788 if (pm_symbol_node_label_p(parser, first_node)) {
16789 if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
16790 pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16792 parse_pattern_hash_key(parser, &keys, first_node);
16797 if (match8(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
16798 if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
16799 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
16801 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
16806 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16809 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
16810 pm_node_list_append(parser->arena, &assocs, assoc);
16819 pm_diagnostic_id_t diag_id = PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE) ? PM_ERR_PATTERN_HASH_KEY_INTERPOLATED : PM_ERR_PATTERN_HASH_KEY_LABEL;
16820 pm_parser_err_node(parser, first_node, diag_id);
16822 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
16823 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
16825 pm_node_list_append(parser->arena, &assocs, assoc);
16831 while (accept1(parser, PM_TOKEN_COMMA)) {
16833 if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
16835 if (rest != NULL) {
16836 pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16842 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16843 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16845 if (rest == NULL) {
16848 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16849 pm_node_list_append(parser->arena, &assocs, assoc);
16854 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16855 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16857 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16858 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16859 }
else if (!pm_symbol_node_label_p(parser, key)) {
16860 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16862 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
16863 key = UP(pm_symbol_node_label_create(parser, &parser->previous));
16865 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16867 pm_token_t label = { .
type = PM_TOKEN_LABEL, .start = parser->previous.
end, .end = parser->previous.
end };
16868 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
16871 parse_pattern_hash_key(parser, &keys, key);
16874 if (match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
16875 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16876 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
16878 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
16881 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16884 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
16886 if (rest != NULL) {
16887 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16890 pm_node_list_append(parser->arena, &assocs, assoc);
16897 pm_static_literals_free(&keys);
16906 switch (parser->current.type) {
16907 case PM_TOKEN_IDENTIFIER:
16908 case PM_TOKEN_METHOD_NAME: {
16909 parser_lex(parser);
16910 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
16913 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16914 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
16917 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
16918 return UP(pm_local_variable_target_node_create(
16920 &TOK2LOC(parser, &parser->previous),
16922 (uint32_t) (depth == -1 ? 0 : depth)
16925 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16927 parser_lex(parser);
16929 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16932 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
16937 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16939 accept1(parser, PM_TOKEN_NEWLINE);
16940 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16943 switch (PM_NODE_TYPE(inner)) {
16944 case PM_ARRAY_PATTERN_NODE: {
16947 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
16948 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16950 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16951 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16953 return UP(pattern_node);
16958 case PM_FIND_PATTERN_NODE: {
16961 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
16962 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16964 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16965 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16967 return UP(pattern_node);
16977 pm_array_pattern_node_requireds_append(parser->arena, node, inner);
16980 case PM_TOKEN_BRACE_LEFT: {
16981 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
16982 parser->pattern_matching_newlines =
false;
16986 parser_lex(parser);
16988 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16991 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
16995 switch (parser->current.type) {
16996 case PM_TOKEN_LABEL:
16997 parser_lex(parser);
16998 first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
17000 case PM_TOKEN_USTAR_STAR:
17001 first_node = parse_pattern_keyword_rest(parser, captures);
17003 case PM_TOKEN_STRING_BEGIN:
17004 first_node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_LABEL, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
17007 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
17008 parser_lex(parser);
17010 first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
17015 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17017 accept1(parser, PM_TOKEN_NEWLINE);
17018 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
17021 PM_NODE_START_SET_TOKEN(parser, node, &opening);
17022 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
17028 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17031 case PM_TOKEN_UDOT_DOT:
17032 case PM_TOKEN_UDOT_DOT_DOT: {
17034 parser_lex(parser);
17038 switch (parser->current.type) {
17039 case PM_CASE_PRIMITIVE: {
17040 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17041 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17044 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17045 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17046 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17050 case PM_CASE_PRIMITIVE: {
17051 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_LABEL | PM_PARSE_ACCEPTS_DO_BLOCK, diag_id, (uint16_t) (depth + 1));
17054 if (pm_symbol_node_label_p(parser, node))
return node;
17057 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17058 pm_parser_err_node(parser, node, diag_id);
17059 return UP(pm_error_recovery_node_create_unexpected(parser, node));
17063 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17069 switch (parser->current.type) {
17070 case PM_CASE_PRIMITIVE: {
17071 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
17072 return UP(pm_range_node_create(parser, node, &
operator, right));
17075 return UP(pm_range_node_create(parser, node, &
operator, NULL));
17081 case PM_TOKEN_CARET: {
17082 parser_lex(parser);
17087 switch (parser->current.type) {
17088 case PM_TOKEN_IDENTIFIER: {
17089 parser_lex(parser);
17090 pm_node_t *variable = UP(parse_variable(parser));
17092 if (variable == NULL) {
17093 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
17094 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
17097 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17099 case PM_TOKEN_INSTANCE_VARIABLE: {
17100 parser_lex(parser);
17101 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
17103 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17105 case PM_TOKEN_CLASS_VARIABLE: {
17106 parser_lex(parser);
17107 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
17109 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17111 case PM_TOKEN_GLOBAL_VARIABLE: {
17112 parser_lex(parser);
17113 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
17115 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17117 case PM_TOKEN_NUMBERED_REFERENCE: {
17118 parser_lex(parser);
17119 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
17121 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17123 case PM_TOKEN_BACK_REFERENCE: {
17124 parser_lex(parser);
17125 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
17127 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17129 case PM_TOKEN_PARENTHESIS_LEFT: {
17130 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17131 parser->pattern_matching_newlines =
false;
17134 parser_lex(parser);
17136 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_DO_BLOCK | PM_PARSE_ACCEPTS_COMMAND_CALL, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
17137 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17139 accept1(parser, PM_TOKEN_NEWLINE);
17140 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
17141 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->previous));
17146 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17147 pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17148 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17152 case PM_TOKEN_UCOLON_COLON: {
17154 parser_lex(parser);
17156 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17159 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
17161 case PM_TOKEN_CONSTANT: {
17163 parser_lex(parser);
17165 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
17166 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17169 pm_parser_err_current(parser, diag_id);
17170 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17175parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
17176 switch (PM_NODE_TYPE(node)) {
17177 case PM_LOCAL_VARIABLE_TARGET_NODE: {
17179 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17193 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
17203 bool alternation =
false;
17205 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
17206 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
17207 parse_pattern_alternation_error(parser, node);
17210 switch (parser->current.type) {
17211 case PM_TOKEN_IDENTIFIER:
17212 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17213 case PM_TOKEN_BRACE_LEFT:
17214 case PM_TOKEN_CARET:
17215 case PM_TOKEN_CONSTANT:
17216 case PM_TOKEN_UCOLON_COLON:
17217 case PM_TOKEN_UDOT_DOT:
17218 case PM_TOKEN_UDOT_DOT_DOT:
17219 case PM_CASE_PRIMITIVE: {
17220 if (!alternation) {
17221 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17224 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17226 if (captures->
size) parse_pattern_alternation_error(parser, right);
17227 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17232 case PM_TOKEN_PARENTHESIS_LEFT:
17233 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17236 parser_lex(parser);
17238 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17239 accept1(parser, PM_TOKEN_NEWLINE);
17240 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17241 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
17243 if (!alternation) {
17246 if (captures->
size) parse_pattern_alternation_error(parser, right);
17247 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17253 pm_parser_err_current(parser, diag_id);
17254 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17256 if (!alternation) {
17259 if (captures->
size) parse_pattern_alternation_error(parser, right);
17260 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
17270 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17272 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17274 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17277 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17278 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17281 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
17284 &TOK2LOC(parser, &parser->previous),
17286 (uint32_t) (depth == -1 ? 0 : depth)
17289 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17302 bool leading_rest =
false;
17303 bool trailing_rest =
false;
17305 switch (parser->current.type) {
17306 case PM_TOKEN_LABEL: {
17307 parser_lex(parser);
17308 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17309 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17311 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17312 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17317 case PM_TOKEN_USTAR_STAR: {
17318 node = parse_pattern_keyword_rest(parser, captures);
17319 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17321 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17322 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17327 case PM_TOKEN_STRING_BEGIN: {
17330 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17332 if (pm_symbol_node_label_p(parser, node)) {
17333 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17335 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17336 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17342 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17345 case PM_TOKEN_USTAR: {
17346 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17347 parser_lex(parser);
17348 node = UP(parse_pattern_rest(parser, captures));
17349 leading_rest =
true;
17355 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17361 if (pm_symbol_node_label_p(parser, node)) {
17362 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17365 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17370 pm_node_list_append(parser->arena, &nodes, node);
17373 while (accept1(parser, PM_TOKEN_COMMA)) {
17375 if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_AND, PM_TOKEN_KEYWORD_OR)) {
17376 node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
17377 pm_node_list_append(parser->arena, &nodes, node);
17378 trailing_rest =
true;
17382 if (accept1(parser, PM_TOKEN_USTAR)) {
17383 node = UP(parse_pattern_rest(parser, captures));
17388 if (trailing_rest) {
17389 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17392 trailing_rest =
true;
17394 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17397 pm_node_list_append(parser->arena, &nodes, node);
17404 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17405 node = UP(pm_find_pattern_node_create(parser, &nodes));
17407 if (nodes.
size == 2) {
17408 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17411 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17413 if (leading_rest && trailing_rest) {
17414 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17419 }
else if (leading_rest) {
17422 node = UP(pm_array_pattern_node_rest_create(parser, node));
17434parse_negative_numeric(
pm_node_t *node) {
17435 switch (PM_NODE_TYPE(node)) {
17436 case PM_INTEGER_NODE: {
17443 case PM_FLOAT_NODE: {
17450 case PM_RATIONAL_NODE: {
17457 case PM_IMAGINARY_NODE:
17463 assert(
false &&
"unreachable");
17474pm_parser_err_prefix(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
17476 case PM_ERR_HASH_KEY: {
17477 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.
type));
17480 case PM_ERR_HASH_VALUE:
17481 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17482 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17485 case PM_ERR_UNARY_RECEIVER: {
17486 const char *human = (parser->current.type == PM_TOKEN_EOF ?
"end-of-input" : pm_token_str(parser->current.type));
17487 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.
start[0]);
17490 case PM_ERR_UNARY_DISALLOWED:
17491 case PM_ERR_EXPECT_ARGUMENT: {
17492 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17496 pm_parser_err_previous(parser, diag_id);
17506#define CONTEXT_NONE 0
17507#define CONTEXT_THROUGH_ENSURE 1
17508#define CONTEXT_THROUGH_ELSE 2
17511 int context = CONTEXT_NONE;
17513 while (context_node != NULL) {
17514 switch (context_node->context) {
17515 case PM_CONTEXT_BEGIN_RESCUE:
17516 case PM_CONTEXT_BLOCK_RESCUE:
17517 case PM_CONTEXT_CLASS_RESCUE:
17518 case PM_CONTEXT_DEF_RESCUE:
17519 case PM_CONTEXT_LAMBDA_RESCUE:
17520 case PM_CONTEXT_MODULE_RESCUE:
17521 case PM_CONTEXT_SCLASS_RESCUE:
17522 case PM_CONTEXT_DEFINED:
17523 case PM_CONTEXT_RESCUE_MODIFIER:
17526 case PM_CONTEXT_CLASS:
17527 case PM_CONTEXT_DEF:
17528 case PM_CONTEXT_DEF_PARAMS:
17529 case PM_CONTEXT_MAIN:
17530 case PM_CONTEXT_MODULE:
17531 case PM_CONTEXT_PREEXE:
17532 case PM_CONTEXT_SCLASS:
17535 if (context == CONTEXT_NONE) {
17536 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17537 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17538 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17539 }
else if (context == CONTEXT_THROUGH_ELSE) {
17540 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17543 case PM_CONTEXT_BEGIN_ELSE:
17544 case PM_CONTEXT_BLOCK_ELSE:
17545 case PM_CONTEXT_CLASS_ELSE:
17546 case PM_CONTEXT_DEF_ELSE:
17547 case PM_CONTEXT_LAMBDA_ELSE:
17548 case PM_CONTEXT_MODULE_ELSE:
17549 case PM_CONTEXT_SCLASS_ELSE:
17552 context = CONTEXT_THROUGH_ELSE;
17554 case PM_CONTEXT_BEGIN_ENSURE:
17555 case PM_CONTEXT_BLOCK_ENSURE:
17556 case PM_CONTEXT_CLASS_ENSURE:
17557 case PM_CONTEXT_DEF_ENSURE:
17558 case PM_CONTEXT_LAMBDA_ENSURE:
17559 case PM_CONTEXT_MODULE_ENSURE:
17560 case PM_CONTEXT_SCLASS_ENSURE:
17563 context = CONTEXT_THROUGH_ENSURE;
17565 case PM_CONTEXT_NONE:
17567 assert(
false &&
"unreachable");
17569 case PM_CONTEXT_BEGIN:
17570 case PM_CONTEXT_BLOCK_BRACES:
17571 case PM_CONTEXT_BLOCK_KEYWORDS:
17572 case PM_CONTEXT_BLOCK_PARAMETERS:
17573 case PM_CONTEXT_CASE_IN:
17574 case PM_CONTEXT_CASE_WHEN:
17575 case PM_CONTEXT_DEFAULT_PARAMS:
17576 case PM_CONTEXT_ELSE:
17577 case PM_CONTEXT_ELSIF:
17578 case PM_CONTEXT_EMBEXPR:
17579 case PM_CONTEXT_FOR_INDEX:
17580 case PM_CONTEXT_FOR:
17581 case PM_CONTEXT_IF:
17582 case PM_CONTEXT_LAMBDA_BRACES:
17583 case PM_CONTEXT_LAMBDA_DO_END:
17584 case PM_CONTEXT_LOOP_PREDICATE:
17585 case PM_CONTEXT_MULTI_TARGET:
17586 case PM_CONTEXT_PARENS:
17587 case PM_CONTEXT_POSTEXE:
17588 case PM_CONTEXT_PREDICATE:
17589 case PM_CONTEXT_TERNARY:
17590 case PM_CONTEXT_UNLESS:
17591 case PM_CONTEXT_UNTIL:
17592 case PM_CONTEXT_WHILE:
17598 context_node = context_node->prev;
17602#undef CONTEXT_ENSURE
17613 while (context_node != NULL) {
17614 switch (context_node->context) {
17615 case PM_CONTEXT_DEF:
17616 case PM_CONTEXT_DEF_PARAMS:
17617 case PM_CONTEXT_DEFINED:
17618 case PM_CONTEXT_DEF_ENSURE:
17619 case PM_CONTEXT_DEF_RESCUE:
17620 case PM_CONTEXT_DEF_ELSE:
17624 case PM_CONTEXT_CLASS:
17625 case PM_CONTEXT_CLASS_ENSURE:
17626 case PM_CONTEXT_CLASS_RESCUE:
17627 case PM_CONTEXT_CLASS_ELSE:
17628 case PM_CONTEXT_MAIN:
17629 case PM_CONTEXT_MODULE:
17630 case PM_CONTEXT_MODULE_ENSURE:
17631 case PM_CONTEXT_MODULE_RESCUE:
17632 case PM_CONTEXT_MODULE_ELSE:
17633 case PM_CONTEXT_SCLASS:
17634 case PM_CONTEXT_SCLASS_RESCUE:
17635 case PM_CONTEXT_SCLASS_ENSURE:
17636 case PM_CONTEXT_SCLASS_ELSE:
17639 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17641 case PM_CONTEXT_NONE:
17643 assert(
false &&
"unreachable");
17645 case PM_CONTEXT_BEGIN:
17646 case PM_CONTEXT_BEGIN_ELSE:
17647 case PM_CONTEXT_BEGIN_ENSURE:
17648 case PM_CONTEXT_BEGIN_RESCUE:
17649 case PM_CONTEXT_BLOCK_BRACES:
17650 case PM_CONTEXT_BLOCK_KEYWORDS:
17651 case PM_CONTEXT_BLOCK_ELSE:
17652 case PM_CONTEXT_BLOCK_ENSURE:
17653 case PM_CONTEXT_BLOCK_PARAMETERS:
17654 case PM_CONTEXT_BLOCK_RESCUE:
17655 case PM_CONTEXT_CASE_IN:
17656 case PM_CONTEXT_CASE_WHEN:
17657 case PM_CONTEXT_DEFAULT_PARAMS:
17658 case PM_CONTEXT_ELSE:
17659 case PM_CONTEXT_ELSIF:
17660 case PM_CONTEXT_EMBEXPR:
17661 case PM_CONTEXT_FOR_INDEX:
17662 case PM_CONTEXT_FOR:
17663 case PM_CONTEXT_IF:
17664 case PM_CONTEXT_LAMBDA_BRACES:
17665 case PM_CONTEXT_LAMBDA_DO_END:
17666 case PM_CONTEXT_LAMBDA_ELSE:
17667 case PM_CONTEXT_LAMBDA_ENSURE:
17668 case PM_CONTEXT_LAMBDA_RESCUE:
17669 case PM_CONTEXT_LOOP_PREDICATE:
17670 case PM_CONTEXT_MULTI_TARGET:
17671 case PM_CONTEXT_PARENS:
17672 case PM_CONTEXT_POSTEXE:
17673 case PM_CONTEXT_PREDICATE:
17674 case PM_CONTEXT_PREEXE:
17675 case PM_CONTEXT_RESCUE_MODIFIER:
17676 case PM_CONTEXT_TERNARY:
17677 case PM_CONTEXT_UNLESS:
17678 case PM_CONTEXT_UNTIL:
17679 case PM_CONTEXT_WHILE:
17685 context_node = context_node->prev;
17697 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
17708pm_command_call_value_p(
const pm_node_t *node) {
17709 switch (PM_NODE_TYPE(node)) {
17710 case PM_CALL_NODE: {
17715 if (pm_call_node_command_p(call) && !PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE) && (call->
receiver == NULL || call->
call_operator_loc.
length > 0)) {
17722 return pm_command_call_value_p(call->
receiver);
17727 case PM_SUPER_NODE: {
17731 case PM_YIELD_NODE: {
17735 case PM_RESCUE_MODIFIER_NODE:
17737 case PM_DEF_NODE: {
17741 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
17744 return pm_command_call_value_p(body);
17760pm_block_call_p(
const pm_node_t *node) {
17761 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17766 if (call->
arguments != NULL && call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE)) {
17787parse_case(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
17788 size_t opening_newline_index = token_newline_index(parser);
17789 parser_lex(parser);
17795 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17797 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17798 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17800 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
17802 }
else if (!token_begins_expression_p(parser->current.type)) {
17805 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
17806 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17809 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
17810 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
17811 parser_lex(parser);
17812 pop_block_exits(parser, previous_block_exits);
17813 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
17814 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->previous));
17821 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
17822 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
17828 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
17829 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
17830 parser_lex(parser);
17833 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
17836 if (accept1(parser, PM_TOKEN_USTAR)) {
17838 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
17840 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
17841 pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
17843 if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE))
break;
17845 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
17846 pm_when_node_conditions_append(parser->arena, when_node, condition);
17850 if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE))
break;
17854 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
17855 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
17856 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
17857 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
17860 pm_when_clause_static_literals_add(parser, &literals, condition);
17862 }
while (accept1(parser, PM_TOKEN_COMMA));
17864 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17865 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
17866 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
17869 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
17870 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
17873 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
17874 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
17875 if (statements != NULL) {
17876 pm_when_node_statements_set(when_node, statements);
17880 pm_case_node_condition_append(parser->arena, case_node, UP(when_node));
17886 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
17889 pm_static_literals_free(&literals);
17890 node = UP(case_node);
17892 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
17896 if (predicate == NULL) {
17897 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
17902 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
17903 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
17905 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17906 parser->pattern_matching_newlines =
true;
17908 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
17909 parser->command_start =
false;
17910 parser_lex(parser);
17915 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));
17917 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17922 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
17924 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
17925 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
17926 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
17928 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
17929 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
17936 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17937 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
17938 then_keyword = parser->previous;
17941 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
17942 then_keyword = parser->previous;
17948 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
17951 statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
17956 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
17957 pm_case_match_node_condition_append(parser->arena, case_node, condition);
17963 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
17966 node = UP(case_node);
17969 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
17970 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
17974 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
17975 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
17977 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
17980 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
17981 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
17987 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
17988 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
17990 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
17991 pm_case_node_end_keyword_loc_set(parser, (
pm_case_node_t *) node, &parser->previous);
17993 pm_case_match_node_end_keyword_loc_set(parser, (
pm_case_match_node_t *) node, &parser->previous);
17996 pop_block_exits(parser, previous_block_exits);
18005parse_class(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18006 size_t opening_newline_index = token_newline_index(parser);
18007 parser_lex(parser);
18009 pm_token_t class_keyword = parser->previous;
18010 pm_do_loop_stack_push(parser,
false);
18013 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18015 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18017 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, (uint16_t) (depth + 1));
18019 pm_parser_scope_push(parser,
true);
18020 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18021 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
18025 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18026 pm_accepts_block_stack_push(parser,
true);
18027 statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18028 pm_accepts_block_stack_pop(parser);
18031 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18032 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18033 statements = UP(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)));
18035 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18038 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18041 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18043 pm_parser_scope_pop(parser);
18044 pm_do_loop_stack_pop(parser);
18046 flush_block_exits(parser, previous_block_exits);
18047 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->previous));
18050 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
18052 if (name.
type != PM_TOKEN_CONSTANT) {
18053 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18059 if (match1(parser, PM_TOKEN_LESS)) {
18060 inheritance_operator = parser->current;
18061 lex_state_set(parser, PM_LEX_STATE_BEG);
18063 parser->command_start =
true;
18064 parser_lex(parser);
18066 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
18071 pm_parser_scope_push(parser,
true);
18073 if (inheritance_operator.
start != NULL) {
18074 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18076 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18080 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18081 pm_accepts_block_stack_push(parser,
true);
18082 statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18083 pm_accepts_block_stack_pop(parser);
18086 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18087 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18088 statements = UP(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)));
18090 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18093 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18095 if (context_def_p(parser)) {
18096 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18100 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18102 pm_parser_scope_pop(parser);
18103 pm_do_loop_stack_pop(parser);
18105 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18106 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18107 if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18108 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18112 pop_block_exits(parser, previous_block_exits);
18113 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
18120parse_def(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
18122 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18125 size_t opening_newline_index = token_newline_index(parser);
18133 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18134 parser_lex(parser);
18138 bool valid_name =
true;
18140 switch (parser->current.type) {
18141 case PM_CASE_OPERATOR:
18142 pm_parser_scope_push(parser,
true);
18143 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18144 parser_lex(parser);
18146 name = parser->previous;
18148 case PM_TOKEN_IDENTIFIER: {
18149 parser_lex(parser);
18151 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18152 receiver = parse_variable_call(parser);
18154 pm_parser_scope_push(parser,
true);
18155 lex_state_set(parser, PM_LEX_STATE_FNAME);
18156 parser_lex(parser);
18158 operator = parser->previous;
18159 name = parse_method_definition_name(parser);
18161 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
18162 pm_parser_scope_push(parser,
true);
18164 name = parser->previous;
18169 case PM_TOKEN_INSTANCE_VARIABLE:
18170 case PM_TOKEN_CLASS_VARIABLE:
18171 case PM_TOKEN_GLOBAL_VARIABLE:
18172 valid_name =
false;
18174 case PM_TOKEN_CONSTANT:
18175 case PM_TOKEN_KEYWORD_NIL:
18176 case PM_TOKEN_KEYWORD_SELF:
18177 case PM_TOKEN_KEYWORD_TRUE:
18178 case PM_TOKEN_KEYWORD_FALSE:
18179 case PM_TOKEN_KEYWORD___FILE__:
18180 case PM_TOKEN_KEYWORD___LINE__:
18181 case PM_TOKEN_KEYWORD___ENCODING__: {
18182 pm_parser_scope_push(parser,
true);
18183 parser_lex(parser);
18187 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18188 lex_state_set(parser, PM_LEX_STATE_FNAME);
18189 parser_lex(parser);
18190 operator = parser->previous;
18192 switch (identifier.
type) {
18193 case PM_TOKEN_CONSTANT:
18194 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18196 case PM_TOKEN_INSTANCE_VARIABLE:
18197 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18199 case PM_TOKEN_CLASS_VARIABLE:
18200 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18202 case PM_TOKEN_GLOBAL_VARIABLE:
18203 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18205 case PM_TOKEN_KEYWORD_NIL:
18206 receiver = UP(pm_nil_node_create(parser, &identifier));
18208 case PM_TOKEN_KEYWORD_SELF:
18209 receiver = UP(pm_self_node_create(parser, &identifier));
18211 case PM_TOKEN_KEYWORD_TRUE:
18212 receiver = UP(pm_true_node_create(parser, &identifier));
18214 case PM_TOKEN_KEYWORD_FALSE:
18215 receiver = UP(pm_false_node_create(parser, &identifier));
18217 case PM_TOKEN_KEYWORD___FILE__:
18218 receiver = UP(pm_source_file_node_create(parser, &identifier));
18220 case PM_TOKEN_KEYWORD___LINE__:
18221 receiver = UP(pm_source_line_node_create(parser, &identifier));
18223 case PM_TOKEN_KEYWORD___ENCODING__:
18224 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18230 name = parse_method_definition_name(parser);
18233 PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.
type));
18240 case PM_TOKEN_PARENTHESIS_LEFT: {
18244 context_pop(parser);
18245 parser_lex(parser);
18248 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
18250 accept1(parser, PM_TOKEN_NEWLINE);
18251 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18254 lex_state_set(parser, PM_LEX_STATE_FNAME);
18255 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18257 operator = parser->previous;
18258 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18262 pm_parser_scope_push(parser,
true);
18263 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18264 name = parse_method_definition_name(parser);
18268 pm_parser_scope_push(parser,
true);
18269 name = parse_method_definition_name(parser);
18277 bool accept_endless_def =
true;
18278 switch (parser->current.type) {
18279 case PM_TOKEN_PARENTHESIS_LEFT: {
18280 parser_lex(parser);
18281 lparen = parser->previous;
18283 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18287 bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
18288 params = parse_parameters(
18290 PM_BINDING_POWER_DEFINED,
18292 allow_trailing_comma,
18296 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18297 (uint16_t) (depth + 1)
18301 lex_state_set(parser, PM_LEX_STATE_BEG);
18302 parser->command_start =
true;
18304 context_pop(parser);
18305 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18306 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
18307 parser->previous.
start = parser->previous.
end;
18308 parser->previous.
type = 0;
18311 rparen = parser->previous;
18314 case PM_CASE_PARAMETER: {
18317 if (parser->current.type == PM_TOKEN_LABEL) {
18318 lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
18321 params = parse_parameters(
18323 PM_BINDING_POWER_DEFINED,
18329 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18330 (uint16_t) (depth + 1)
18335 accept_endless_def =
false;
18337 context_pop(parser);
18342 context_pop(parser);
18351 if (accept1(parser, PM_TOKEN_EQUAL)) {
18352 if (token_is_setter_name(&name)) {
18353 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18355 if (!accept_endless_def) {
18356 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18359 parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
18360 parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
18362 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_START(parser, &def_keyword), PM_TOKENS_LENGTH(&def_keyword, &parser->previous), PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE,
"endless method definition");
18364 equal = parser->previous;
18366 context_push(parser, PM_CONTEXT_DEF);
18367 pm_do_loop_stack_push(parser,
false);
18368 statements = UP(pm_statements_node_create(parser));
18370 uint8_t allow_flags;
18371 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
18372 allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
18376 allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18385 pm_accepts_block_stack_push(parser,
true);
18386 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_flags | PM_PARSE_IN_ENDLESS_DEF, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
18387 pm_accepts_block_stack_pop(parser);
18394 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18395 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18396 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18399 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18400 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18402 pm_token_t rescue_keyword = parser->previous;
18406 pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_MATCH + 1, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
18407 context_pop(parser);
18409 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18415 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(statement)) {
18416 PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18419 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18420 pm_do_loop_stack_pop(parser);
18421 context_pop(parser);
18423 if (lparen.
start == NULL) {
18424 lex_state_set(parser, PM_LEX_STATE_BEG);
18425 parser->command_start =
true;
18426 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18428 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18431 pm_accepts_block_stack_push(parser,
true);
18432 pm_do_loop_stack_push(parser,
false);
18434 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18435 pm_accepts_block_stack_push(parser,
true);
18436 statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18437 pm_accepts_block_stack_pop(parser);
18440 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18441 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18442 statements = UP(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)));
18444 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18447 pm_accepts_block_stack_pop(parser);
18448 pm_do_loop_stack_pop(parser);
18450 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18451 end_keyword = parser->previous;
18455 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18456 pm_parser_scope_pop(parser);
18461 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
18463 flush_block_exits(parser, previous_block_exits);
18465 return UP(pm_def_node_create(
18474 NTOK2PTR(
operator),
18478 NTOK2PTR(end_keyword)
18486parse_module(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18488 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18490 size_t opening_newline_index = token_newline_index(parser);
18491 parser_lex(parser);
18492 pm_token_t module_keyword = parser->previous;
18494 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
18499 if (PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18500 pop_block_exits(parser, previous_block_exits);
18503 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
18506 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
18509 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18510 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
18516 name = parser->previous;
18517 if (name.
type != PM_TOKEN_CONSTANT) {
18518 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
18521 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE) && !PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18522 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18525 pm_parser_scope_push(parser,
true);
18526 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
18529 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18530 pm_accepts_block_stack_push(parser,
true);
18531 statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
18532 pm_accepts_block_stack_pop(parser);
18535 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18536 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18537 statements = UP(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)));
18539 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
18543 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18545 pm_parser_scope_pop(parser);
18546 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
18548 if (context_def_p(parser)) {
18549 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
18552 pop_block_exits(parser, previous_block_exits);
18554 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
18561parse_string_array(
pm_parser_t *parser, uint16_t depth) {
18562 parser_lex(parser);
18570 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
18571 switch (parser->current.type) {
18572 case PM_TOKEN_WORDS_SEP: {
18575 parser->explicit_encoding = NULL;
18577 if (current == NULL) {
18584 pm_array_node_elements_append(parser->arena, array, current);
18588 parser_lex(parser);
18591 case PM_TOKEN_STRING_CONTENT: {
18592 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
18593 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
18594 parser_lex(parser);
18596 if (current == NULL) {
18602 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
18607 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
18613 pm_interpolated_string_node_append(parser, interpolated, current);
18614 pm_interpolated_string_node_append(parser, interpolated,
string);
18615 current = UP(interpolated);
18617 assert(
false &&
"unreachable");
18622 case PM_TOKEN_EMBVAR: {
18623 if (current == NULL) {
18627 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
18628 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
18634 pm_interpolated_string_node_append(parser, interpolated, current);
18635 current = UP(interpolated);
18642 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
18646 case PM_TOKEN_EMBEXPR_BEGIN: {
18647 if (current == NULL) {
18651 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
18652 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
18658 pm_interpolated_string_node_append(parser, interpolated, current);
18659 current = UP(interpolated);
18660 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
18664 assert(
false &&
"unreachable");
18667 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
18672 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
18673 parser_lex(parser);
18680 pm_array_node_elements_append(parser->arena, array, current);
18684 if (match1(parser, PM_TOKEN_EOF)) {
18685 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
18686 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
18688 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
18691 pm_array_node_close_set(parser, array, &closing);
18699parse_symbol_array(
pm_parser_t *parser, uint16_t depth) {
18700 parser_lex(parser);
18708 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
18709 switch (parser->current.type) {
18710 case PM_TOKEN_WORDS_SEP: {
18711 if (current == NULL) {
18718 pm_array_node_elements_append(parser->arena, array, current);
18722 parser_lex(parser);
18725 case PM_TOKEN_STRING_CONTENT: {
18726 if (current == NULL) {
18731 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
18732 parser_lex(parser);
18733 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
18737 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
18738 parser_lex(parser);
18741 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
18748 .
type = PM_TOKEN_STRING_CONTENT,
18753 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
18754 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
18755 parser_lex(parser);
18758 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
18759 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
18761 current = UP(interpolated);
18763 assert(
false &&
"unreachable");
18768 case PM_TOKEN_EMBVAR: {
18769 bool start_location_set =
false;
18770 if (current == NULL) {
18774 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
18775 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
18782 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
18783 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
18784 PM_NODE_START_SET_NODE(interpolated, current);
18785 start_location_set =
true;
18786 current = UP(interpolated);
18793 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
18795 if (!start_location_set) {
18796 PM_NODE_START_SET_NODE(current, part);
18800 case PM_TOKEN_EMBEXPR_BEGIN: {
18801 bool start_location_set =
false;
18802 if (current == NULL) {
18806 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
18807 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
18814 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
18815 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
18816 PM_NODE_START_SET_NODE(interpolated, current);
18817 start_location_set =
true;
18818 current = UP(interpolated);
18819 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
18823 assert(
false &&
"unreachable");
18826 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
18828 if (!start_location_set) {
18829 PM_NODE_START_SET_NODE(current, part);
18834 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
18835 parser_lex(parser);
18842 pm_array_node_elements_append(parser->arena, array, current);
18846 if (match1(parser, PM_TOKEN_EOF)) {
18847 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
18848 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
18850 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
18852 pm_array_node_close_set(parser, array, &closing);
18862parse_parentheses(
pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
18864 pm_node_flags_t paren_flags = 0;
18867 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18869 parser_lex(parser);
18871 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18872 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18873 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18880 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
18881 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18882 pop_block_exits(parser, previous_block_exits);
18883 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
18888 pm_accepts_block_stack_push(parser,
true);
18889 context_push(parser, PM_CONTEXT_PARENS);
18890 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18891 context_pop(parser);
18896 bool terminator_found =
false;
18898 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18899 terminator_found =
true;
18900 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18901 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
18902 terminator_found =
true;
18905 if (terminator_found) {
18907 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18908 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18909 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18917 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18918 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
18919 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18922 parser_lex(parser);
18923 pm_accepts_block_stack_pop(parser);
18924 pop_block_exits(parser, previous_block_exits);
18926 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18932 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
18935 multi_target = pm_multi_target_node_create(parser);
18936 pm_multi_target_node_targets_append(parser, multi_target, statement);
18939 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
18940 multi_target->
rparen_loc = TOK2LOC(parser, &parser->previous);
18941 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
18942 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
18945 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18946 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18947 accept1(parser, PM_TOKEN_NEWLINE);
18949 result = UP(multi_target);
18952 if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
18954 }
else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) {
18957 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18960 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18961 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
18964 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18974 pm_statements_node_body_append(parser, statements, statement,
true);
18976 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
18982 context_push(parser, PM_CONTEXT_PARENS);
18983 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18986 pm_statements_node_body_append(parser, statements, statement,
true);
18990 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
18991 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18996 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
18997 pm_statements_node_body_append(parser, statements, node,
true);
19001 if (parser->recovering) {
19004 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering =
false;
19010 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE))
break;
19014 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19015 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
19016 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
19017 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19019 }
else if (!match1(parser, PM_TOKEN_EOF)) {
19022 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19026 context_pop(parser);
19027 pm_accepts_block_stack_pop(parser);
19028 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19037 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19039 pm_multi_target_node_targets_append(parser, multi_target, statement);
19041 statement = UP(multi_target);
19045 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
19046 const uint8_t *offset = parser->start + PM_NODE_END(statement);
19047 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
19048 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
19050 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
19053 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
19057 pop_block_exits(parser, previous_block_exits);
19058 pm_void_statements_check(parser, statements,
true);
19059 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19066parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
19067 switch (parser->current.type) {
19068 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
19069 parser_lex(parser);
19071 pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
19072 pm_accepts_block_stack_push(parser,
true);
19073 bool parsed_bare_hash =
false;
19075 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
19076 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
19080 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19086 if (accept1(parser, PM_TOKEN_COMMA)) {
19089 if (accepted_newline) {
19090 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
19095 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
19096 parser->previous.
start = parser->previous.
end;
19097 parser->previous.
type = 0;
19104 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
19108 if (accept1(parser, PM_TOKEN_USTAR)) {
19112 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
19113 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
19115 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19118 element = UP(pm_splat_node_create(parser, &
operator, expression));
19119 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
19120 if (parsed_bare_hash) {
19121 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
19124 element = UP(pm_keyword_hash_node_create(parser));
19127 if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_DO_BLOCK, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) {
19128 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19131 pm_static_literals_free(&hash_keys);
19132 parsed_bare_hash =
true;
19134 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_LABEL), PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
19136 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
19137 if (parsed_bare_hash) {
19138 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
19143 pm_hash_key_static_literals_add(parser, &hash_keys, element);
19146 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
19147 operator = parser->previous;
19150 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
19151 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(
operator), value));
19152 pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
19154 element = UP(hash);
19155 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19156 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19159 pm_static_literals_free(&hash_keys);
19160 parsed_bare_hash =
true;
19164 pm_array_node_elements_append(parser->arena, array, element);
19165 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
19168 accept1(parser, PM_TOKEN_NEWLINE);
19170 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19171 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
19172 parser->previous.
start = parser->previous.
end;
19173 parser->previous.
type = 0;
19176 pm_array_node_close_set(parser, array, &parser->previous);
19177 pm_accepts_block_stack_pop(parser);
19181 case PM_TOKEN_PARENTHESIS_LEFT:
19182 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
19183 return parse_parentheses(parser, binding_power, depth);
19184 case PM_TOKEN_BRACE_LEFT: {
19193 parser->current_hash_keys = NULL;
19195 pm_accepts_block_stack_push(parser,
true);
19196 parser_lex(parser);
19201 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
19202 if (current_hash_keys != NULL) {
19203 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
19206 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
19207 pm_static_literals_free(&hash_keys);
19210 accept1(parser, PM_TOKEN_NEWLINE);
19213 pm_accepts_block_stack_pop(parser);
19214 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
19215 pm_hash_node_closing_loc_set(parser, node, &parser->previous);
19219 case PM_TOKEN_CHARACTER_LITERAL: {
19220 pm_node_t *node = UP(pm_string_node_create_current_string(
19223 .type = PM_TOKEN_STRING_BEGIN,
19224 .start = parser->current.start,
19225 .end = parser->current.start + 1
19228 .type = PM_TOKEN_STRING_CONTENT,
19229 .start = parser->current.start + 1,
19230 .end = parser->current.end
19235 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19239 parser_lex(parser);
19243 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19244 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19249 case PM_TOKEN_CLASS_VARIABLE: {
19250 parser_lex(parser);
19251 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->previous));
19253 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19254 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19259 case PM_TOKEN_CONSTANT: {
19260 parser_lex(parser);
19266 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
19267 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
19268 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19269 match1(parser, PM_TOKEN_BRACE_LEFT)
19272 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19273 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
19276 pm_node_t *node = UP(pm_constant_read_node_create(parser, &parser->previous));
19278 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19281 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19286 case PM_TOKEN_UCOLON_COLON: {
19287 parser_lex(parser);
19290 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19291 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous));
19293 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19294 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19299 case PM_TOKEN_UDOT_DOT:
19300 case PM_TOKEN_UDOT_DOT_DOT: {
19302 parser_lex(parser);
19304 pm_node_t *right = parse_expression(parser, pm_binding_powers[
operator.
type].left, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
19310 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
19311 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
19314 return UP(pm_range_node_create(parser, NULL, &
operator, right));
19316 case PM_TOKEN_FLOAT:
19317 parser_lex(parser);
19318 return UP(pm_float_node_create(parser, &parser->previous));
19319 case PM_TOKEN_FLOAT_IMAGINARY:
19320 parser_lex(parser);
19321 return UP(pm_float_node_imaginary_create(parser, &parser->previous));
19322 case PM_TOKEN_FLOAT_RATIONAL:
19323 parser_lex(parser);
19324 return UP(pm_float_node_rational_create(parser, &parser->previous));
19325 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
19326 parser_lex(parser);
19327 return UP(pm_float_node_rational_imaginary_create(parser, &parser->previous));
19328 case PM_TOKEN_NUMBERED_REFERENCE: {
19329 parser_lex(parser);
19330 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
19332 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19333 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19338 case PM_TOKEN_GLOBAL_VARIABLE: {
19339 parser_lex(parser);
19340 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->previous));
19342 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19343 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19348 case PM_TOKEN_BACK_REFERENCE: {
19349 parser_lex(parser);
19350 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->previous));
19352 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19353 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19358 case PM_TOKEN_IDENTIFIER:
19359 case PM_TOKEN_METHOD_NAME: {
19360 parser_lex(parser);
19362 pm_node_t *node = parse_variable_call(parser);
19364 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
19372 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
19375 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
19384 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
19386 PM_NODE_LENGTH_SET_LOCATION(call, end);
19394 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
19395 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19396 match1(parser, PM_TOKEN_BRACE_LEFT)
19399 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19400 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
19402 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
19406 pm_node_unreference(parser, node);
19412 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
19414 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
19415 pm_node_unreference(parser, node);
19418 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
19426 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19427 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19432 case PM_TOKEN_HEREDOC_START: {
19435 assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
19438 size_t common_whitespace = (size_t) -1;
19439 parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
19441 parser_lex(parser);
19447 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19450 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19451 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
19453 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19454 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19456 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19459 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
19460 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
19467 node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19468 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19473 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19477 cast->
closing_loc = TOK2LOC(parser, &parser->current);
19480 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19482 cast->
base.
type = PM_X_STRING_NODE;
19485 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19486 parse_heredoc_dedent_string(parser->arena, &cast->
unescaped, common_whitespace);
19490 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19496 pm_node_list_append(parser->arena, &parts, part);
19498 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19499 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19500 pm_node_list_append(parser->arena, &parts, part);
19506 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19508 cast->
parts = parts;
19510 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19511 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
19518 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19519 pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
19527 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19529 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19535 parse_heredoc_dedent(parser, nodes, common_whitespace);
19539 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19540 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19545 case PM_TOKEN_INSTANCE_VARIABLE: {
19546 parser_lex(parser);
19547 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
19549 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19550 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19555 case PM_TOKEN_INTEGER: {
19556 pm_node_flags_t base = parser->integer.base;
19557 parser_lex(parser);
19558 return UP(pm_integer_node_create(parser, base, &parser->previous));
19560 case PM_TOKEN_INTEGER_IMAGINARY: {
19561 pm_node_flags_t base = parser->integer.base;
19562 parser_lex(parser);
19563 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
19565 case PM_TOKEN_INTEGER_RATIONAL: {
19566 pm_node_flags_t base = parser->integer.base;
19567 parser_lex(parser);
19568 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
19570 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
19571 pm_node_flags_t base = parser->integer.base;
19572 parser_lex(parser);
19573 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
19575 case PM_TOKEN_KEYWORD___ENCODING__:
19576 parser_lex(parser);
19577 return UP(pm_source_encoding_node_create(parser, &parser->previous));
19578 case PM_TOKEN_KEYWORD___FILE__:
19579 parser_lex(parser);
19580 return UP(pm_source_file_node_create(parser, &parser->previous));
19581 case PM_TOKEN_KEYWORD___LINE__:
19582 parser_lex(parser);
19583 return UP(pm_source_line_node_create(parser, &parser->previous));
19584 case PM_TOKEN_KEYWORD_ALIAS: {
19585 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19586 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
19589 parser_lex(parser);
19592 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
19593 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
19595 switch (PM_NODE_TYPE(new_name)) {
19596 case PM_BACK_REFERENCE_READ_NODE:
19597 case PM_NUMBERED_REFERENCE_READ_NODE:
19598 case PM_GLOBAL_VARIABLE_READ_NODE: {
19599 if (PM_NODE_TYPE_P(old_name, PM_BACK_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE) || PM_NODE_TYPE_P(old_name, PM_GLOBAL_VARIABLE_READ_NODE)) {
19600 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
19601 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
19603 }
else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
19604 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19605 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19608 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
19610 case PM_SYMBOL_NODE:
19611 case PM_INTERPOLATED_SYMBOL_NODE: {
19612 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
19613 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19614 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19619 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
19622 case PM_TOKEN_KEYWORD_CASE:
19623 return parse_case(parser, flags, depth);
19624 case PM_TOKEN_KEYWORD_BEGIN: {
19625 size_t opening_newline_index = token_newline_index(parser);
19626 parser_lex(parser);
19628 pm_token_t begin_keyword = parser->previous;
19629 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19632 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19635 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19636 pm_accepts_block_stack_push(parser,
true);
19637 begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19638 pm_accepts_block_stack_pop(parser);
19639 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19642 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19643 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19644 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
19646 PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->previous);
19647 pm_begin_node_end_keyword_set(parser, begin_node, &parser->previous);
19648 pop_block_exits(parser, previous_block_exits);
19649 return UP(begin_node);
19651 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
19653 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19655 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19656 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19659 parser_lex(parser);
19662 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
19664 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
19666 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
19667 pm_context_t context = parser->current_context->context;
19668 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
19669 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19672 flush_block_exits(parser, previous_block_exits);
19673 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
19675 case PM_TOKEN_KEYWORD_BREAK:
19676 case PM_TOKEN_KEYWORD_NEXT:
19677 case PM_TOKEN_KEYWORD_RETURN: {
19678 parser_lex(parser);
19684 token_begins_expression_p(parser->current.type) ||
19685 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
19687 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
19689 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19691 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
19694 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
19695 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.
type));
19702 if (arguments.
block != NULL) {
19703 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19704 pm_node_unreference(parser, arguments.
block);
19705 arguments.
block = NULL;
19709 switch (keyword.
type) {
19710 case PM_TOKEN_KEYWORD_BREAK: {
19712 if (!parser->partial_script) parse_block_exit(parser, node);
19715 case PM_TOKEN_KEYWORD_NEXT: {
19717 if (!parser->partial_script) parse_block_exit(parser, node);
19720 case PM_TOKEN_KEYWORD_RETURN: {
19722 parse_return(parser, node);
19726 assert(
false &&
"unreachable");
19727 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19730 case PM_TOKEN_KEYWORD_SUPER: {
19731 parser_lex(parser);
19735 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19740 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
19742 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
19745 return UP(pm_super_node_create(parser, &keyword, &arguments));
19747 case PM_TOKEN_KEYWORD_YIELD: {
19748 parser_lex(parser);
19752 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
19758 if (arguments.
block != NULL) {
19759 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19760 pm_node_unreference(parser, arguments.
block);
19761 arguments.
block = NULL;
19765 if (!parser->parsing_eval && !parser->partial_script) parse_yield(parser, node);
19769 case PM_TOKEN_KEYWORD_CLASS:
19770 return parse_class(parser, flags, depth);
19771 case PM_TOKEN_KEYWORD_DEF:
19772 return parse_def(parser, binding_power, flags, depth);
19773 case PM_TOKEN_KEYWORD_DEFINED: {
19774 parser_lex(parser);
19781 context_push(parser, PM_CONTEXT_DEFINED);
19782 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19784 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19785 lparen = parser->previous;
19787 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19788 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
19791 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19793 if (!parser->recovering) {
19794 accept1(parser, PM_TOKEN_NEWLINE);
19795 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19796 rparen = parser->previous;
19800 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19803 context_pop(parser);
19804 return UP(pm_defined_node_create(
19812 case PM_TOKEN_KEYWORD_END_UPCASE: {
19813 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19814 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19817 parser_lex(parser);
19820 if (context_def_p(parser)) {
19821 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19824 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19826 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
19828 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
19829 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
19831 case PM_TOKEN_KEYWORD_FALSE:
19832 parser_lex(parser);
19833 return UP(pm_false_node_create(parser, &parser->previous));
19834 case PM_TOKEN_KEYWORD_FOR: {
19835 size_t opening_newline_index = token_newline_index(parser);
19836 parser_lex(parser);
19841 context_push(parser, PM_CONTEXT_FOR_INDEX);
19844 if (accept1(parser, PM_TOKEN_USTAR)) {
19845 pm_token_t star_operator = parser->previous;
19848 if (token_begins_expression_p(parser->current.type)) {
19849 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19852 index = UP(pm_splat_node_create(parser, &star_operator, name));
19853 }
else if (token_begins_expression_p(parser->current.type)) {
19854 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19856 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19857 index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
19861 if (match1(parser, PM_TOKEN_COMMA)) {
19862 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19864 index = parse_target(parser, index,
false,
false);
19867 context_pop(parser);
19868 pm_do_loop_stack_push(parser,
true);
19870 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19873 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19874 pm_do_loop_stack_pop(parser);
19877 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19878 do_keyword = parser->previous;
19880 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19881 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
19886 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19887 statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19890 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19891 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19893 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous));
19895 case PM_TOKEN_KEYWORD_IF:
19896 if (parser_end_of_line_p(parser)) {
19897 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
19900 size_t opening_newline_index = token_newline_index(parser);
19901 bool if_after_else = parser->previous.
type == PM_TOKEN_KEYWORD_ELSE;
19902 parser_lex(parser);
19904 return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19905 case PM_TOKEN_KEYWORD_UNDEF: {
19906 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19907 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19910 parser_lex(parser);
19911 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
19912 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19914 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
19916 pm_undef_node_append(parser->arena, undef, name);
19918 while (match1(parser, PM_TOKEN_COMMA)) {
19919 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19920 parser_lex(parser);
19921 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19923 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
19927 pm_undef_node_append(parser->arena, undef, name);
19933 case PM_TOKEN_KEYWORD_NOT: {
19934 parser_lex(parser);
19947 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19948 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19949 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19951 accept1(parser, PM_TOKEN_NEWLINE);
19952 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19955 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
19958 accept1(parser, PM_TOKEN_NEWLINE);
19960 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19963 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19964 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
19966 arguments.
opening_loc = TOK2LOC(parser, &lparen);
19967 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19969 if (!parser->recovering) {
19970 accept1(parser, PM_TOKEN_NEWLINE);
19971 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19972 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
19976 receiver = parse_expression(parser, PM_BINDING_POWER_NOT, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19979 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19981 case PM_TOKEN_KEYWORD_UNLESS: {
19982 size_t opening_newline_index = token_newline_index(parser);
19983 parser_lex(parser);
19985 return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19987 case PM_TOKEN_KEYWORD_MODULE:
19988 return parse_module(parser, flags, depth);
19989 case PM_TOKEN_KEYWORD_NIL:
19990 parser_lex(parser);
19991 return UP(pm_nil_node_create(parser, &parser->previous));
19992 case PM_TOKEN_KEYWORD_REDO: {
19993 parser_lex(parser);
19995 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
19996 if (!parser->partial_script) parse_block_exit(parser, node);
20000 case PM_TOKEN_KEYWORD_RETRY: {
20001 parser_lex(parser);
20003 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
20004 parse_retry(parser, node);
20008 case PM_TOKEN_KEYWORD_SELF:
20009 parser_lex(parser);
20010 return UP(pm_self_node_create(parser, &parser->previous));
20011 case PM_TOKEN_KEYWORD_TRUE:
20012 parser_lex(parser);
20013 return UP(pm_true_node_create(parser, &parser->previous));
20014 case PM_TOKEN_KEYWORD_UNTIL: {
20015 size_t opening_newline_index = token_newline_index(parser);
20017 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20018 pm_do_loop_stack_push(parser,
true);
20020 parser_lex(parser);
20022 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
20024 pm_do_loop_stack_pop(parser);
20025 context_pop(parser);
20028 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20029 do_keyword = parser->previous;
20031 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20035 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20036 pm_accepts_block_stack_push(parser,
true);
20037 statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20038 pm_accepts_block_stack_pop(parser);
20039 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20042 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20043 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
20045 return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20047 case PM_TOKEN_KEYWORD_WHILE: {
20048 size_t opening_newline_index = token_newline_index(parser);
20050 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20051 pm_do_loop_stack_push(parser,
true);
20053 parser_lex(parser);
20055 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
20057 pm_do_loop_stack_pop(parser);
20058 context_pop(parser);
20061 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20062 do_keyword = parser->previous;
20064 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20068 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20069 pm_accepts_block_stack_push(parser,
true);
20070 statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20071 pm_accepts_block_stack_pop(parser);
20072 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20075 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20076 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
20078 return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20080 case PM_TOKEN_PERCENT_LOWER_I: {
20081 parser_lex(parser);
20086 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20087 accept1(parser, PM_TOKEN_WORDS_SEP);
20088 if (match1(parser, PM_TOKEN_STRING_END))
break;
20092 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20094 if (current == NULL) {
20095 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20096 parser_lex(parser);
20097 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20098 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20099 parser_lex(parser);
20101 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20104 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20105 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20106 parser_lex(parser);
20109 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20110 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20113 current = UP(interpolated);
20115 assert(
false &&
"unreachable");
20120 pm_array_node_elements_append(parser->arena, array, current);
20123 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20128 if (match1(parser, PM_TOKEN_EOF)) {
20129 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20130 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20132 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20134 pm_array_node_close_set(parser, array, &closing);
20138 case PM_TOKEN_PERCENT_UPPER_I:
20139 return parse_symbol_array(parser, depth);
20140 case PM_TOKEN_PERCENT_LOWER_W: {
20141 parser_lex(parser);
20146 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20147 accept1(parser, PM_TOKEN_WORDS_SEP);
20148 if (match1(parser, PM_TOKEN_STRING_END))
break;
20152 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20153 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20156 if (current == NULL) {
20158 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20160 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20162 pm_interpolated_string_node_append(parser, interpolated, current);
20163 pm_interpolated_string_node_append(parser, interpolated,
string);
20164 current = UP(interpolated);
20166 assert(
false &&
"unreachable");
20168 parser_lex(parser);
20172 pm_array_node_elements_append(parser->arena, array, current);
20175 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20180 if (match1(parser, PM_TOKEN_EOF)) {
20181 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20182 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20184 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20187 pm_array_node_close_set(parser, array, &closing);
20190 case PM_TOKEN_PERCENT_UPPER_W:
20191 return parse_string_array(parser, depth);
20192 case PM_TOKEN_REGEXP_BEGIN: {
20194 parser_lex(parser);
20196 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20201 .
type = PM_TOKEN_STRING_CONTENT,
20202 .start = parser->previous.
end,
20203 .end = parser->previous.
end
20206 parser_lex(parser);
20209 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20215 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20222 parser_lex(parser);
20227 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20234 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20235 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20243 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20245 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20246 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
20250 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20253 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20258 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20264 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20265 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20266 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20271 if (match1(parser, PM_TOKEN_EOF)) {
20272 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20273 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20275 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20278 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20279 return UP(interpolated);
20281 case PM_TOKEN_BACKTICK:
20282 case PM_TOKEN_PERCENT_LOWER_X: {
20283 parser_lex(parser);
20290 if (match1(parser, PM_TOKEN_STRING_END)) {
20295 .
type = PM_TOKEN_STRING_CONTENT,
20296 .start = parser->previous.
end,
20297 .end = parser->previous.
end
20300 parser_lex(parser);
20301 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
20306 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20313 parser_lex(parser);
20315 if (match1(parser, PM_TOKEN_STRING_END)) {
20316 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
20317 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20318 parser_lex(parser);
20324 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20326 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20327 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20329 pm_interpolated_xstring_node_append(parser->arena, node, part);
20334 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20338 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20339 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20340 pm_interpolated_xstring_node_append(parser->arena, node, part);
20345 if (match1(parser, PM_TOKEN_EOF)) {
20346 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20347 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20349 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20351 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
20355 case PM_TOKEN_USTAR: {
20356 parser_lex(parser);
20361 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20362 pm_parser_err_prefix(parser, diag_id);
20363 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20369 if (token_begins_expression_p(parser->current.type)) {
20370 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20373 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
20375 if (match1(parser, PM_TOKEN_COMMA)) {
20376 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20378 return parse_target_validate(parser, splat,
true);
20381 case PM_TOKEN_BANG: {
20382 if (binding_power > PM_BINDING_POWER_UNARY) {
20383 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20386 parser_lex(parser);
20389 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.
type].right, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20390 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20392 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20395 case PM_TOKEN_TILDE: {
20396 if (binding_power > PM_BINDING_POWER_UNARY) {
20397 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20399 parser_lex(parser);
20402 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20403 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20407 case PM_TOKEN_UMINUS: {
20408 if (binding_power > PM_BINDING_POWER_UNARY) {
20409 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20411 parser_lex(parser);
20414 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20415 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20419 case PM_TOKEN_UMINUS_NUM: {
20420 parser_lex(parser);
20423 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20425 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20426 pm_token_t exponent_operator = parser->previous;
20427 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20428 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20429 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20431 switch (PM_NODE_TYPE(node)) {
20432 case PM_INTEGER_NODE:
20433 case PM_FLOAT_NODE:
20434 case PM_RATIONAL_NODE:
20435 case PM_IMAGINARY_NODE:
20436 parse_negative_numeric(node);
20439 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20446 case PM_TOKEN_MINUS_GREATER: {
20447 int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
20448 parser->lambda_enclosure_nesting = parser->enclosure_nesting;
20450 size_t opening_newline_index = token_newline_index(parser);
20451 pm_accepts_block_stack_push(parser,
true);
20452 parser_lex(parser);
20455 pm_parser_scope_push(parser,
false);
20459 switch (parser->current.type) {
20460 case PM_TOKEN_PARENTHESIS_LEFT: {
20462 parser_lex(parser);
20464 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20465 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20467 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20470 accept1(parser, PM_TOKEN_NEWLINE);
20471 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20473 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
20476 case PM_CASE_PARAMETER: {
20477 pm_accepts_block_stack_push(parser,
false);
20478 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
20479 pm_accepts_block_stack_pop(parser);
20483 block_parameters = NULL;
20490 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
20492 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20493 opening = parser->previous;
20495 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20496 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
20499 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20500 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20502 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20503 opening = parser->previous;
20505 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20506 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
20509 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20510 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20511 body = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &
operator, opening.
start, (
pm_statements_node_t *) body, PM_RESCUES_LAMBDA, (uint16_t) (depth + 1)));
20513 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20516 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20520 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
20521 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->previous);
20523 pm_parser_scope_pop(parser);
20524 pm_accepts_block_stack_pop(parser);
20526 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->previous, parameters, body));
20528 case PM_TOKEN_UPLUS: {
20529 if (binding_power > PM_BINDING_POWER_UNARY) {
20530 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20532 parser_lex(parser);
20535 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20536 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20540 case PM_TOKEN_STRING_BEGIN:
20541 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
20542 case PM_TOKEN_SYMBOL_BEGIN: {
20544 parser_lex(parser);
20546 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20549 pm_context_t recoverable = context_recoverable(parser, &parser->current);
20551 if (recoverable != PM_CONTEXT_NONE) {
20552 parser->recovering =
true;
20557 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20558 pm_parser_err_prefix(parser, diag_id);
20564 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
20565 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20569 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
20571 pm_parser_err_prefix(parser, diag_id);
20574 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20589parse_assignment_value(
pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
20590 pm_node_t *value = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0))), diag_id, (uint16_t) (depth + 1));
20596 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
20597 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
20598 parser_lex(parser);
20599 parse_expression(parser, pm_binding_powers[parser->previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20604 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20605 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
20608 parser_lex(parser);
20610 pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20611 context_pop(parser);
20613 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20625 switch (PM_NODE_TYPE(node)) {
20626 case PM_BEGIN_NODE: {
20631 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20633 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20636 case PM_PARENTHESES_NODE: {
20638 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20641 case PM_STATEMENTS_NODE: {
20646 parse_assignment_value_local(parser, statement);
20668parse_assignment_values(
pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
20669 bool permitted =
true;
20670 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20672 pm_node_t *value = parse_starred_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MODIFIER ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0))), diag_id, (uint16_t) (depth + 1));
20673 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20675 parse_assignment_value_local(parser, value);
20676 bool single_value =
true;
20681 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20682 single_value =
false;
20685 pm_array_node_elements_append(parser->arena, array, value);
20688 while (accept1(parser, PM_TOKEN_COMMA)) {
20689 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20691 pm_array_node_elements_append(parser->arena, array, element);
20692 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
20694 parse_assignment_value_local(parser, element);
20702 if (single_value && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
20703 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
20704 parser_lex(parser);
20705 parse_expression(parser, pm_binding_powers[parser->previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
20710 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20711 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
20714 parser_lex(parser);
20716 bool accepts_command_call_inner =
false;
20720 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20723 accepts_command_call_inner =
true;
20727 pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (accepts_command_call_inner ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20728 context_pop(parser);
20730 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20746 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20747 pm_node_unreference(parser, UP(call_node->
arguments));
20751 if (call_node->
block != NULL) {
20752 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20753 pm_node_unreference(parser, UP(call_node->
block));
20754 call_node->
block = NULL;
20759pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20762 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20763 uint8_t value = escape_hexadecimal_digit(*cursor);
20766 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20767 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20771 pm_buffer_append_byte(unescaped, value);
20773 pm_buffer_append_string(unescaped,
"\\x", 2);
20780pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20781 uint8_t value = (uint8_t) (*cursor -
'0');
20784 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20785 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20788 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20789 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20794 pm_buffer_append_byte(unescaped, value);
20800 const uint8_t *start = cursor - 1;
20803 if (cursor >= end) {
20804 pm_buffer_append_string(unescaped,
"\\u", 2);
20808 if (*cursor !=
'{') {
20809 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20810 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
20812 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20813 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20816 return cursor + length;
20821 while (cursor < end && *cursor ==
' ') cursor++;
20823 if (cursor >= end)
break;
20824 if (*cursor ==
'}') {
20829 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20833 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
20835 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20843pm_named_capture_escape(
pm_parser_t *parser,
pm_buffer_t *unescaped,
const uint8_t *source,
const size_t length,
const uint8_t *cursor,
const pm_location_t *error_location) {
20844 const uint8_t *end = source + length;
20845 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20848 if (++cursor >= end) {
20849 pm_buffer_append_byte(unescaped,
'\\');
20855 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20857 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20858 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20861 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
20864 pm_buffer_append_byte(unescaped,
'\\');
20868 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->encoding_changed, parser->encoding);
20869 if (next_cursor == NULL)
break;
20871 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20872 cursor = next_cursor;
20875 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20887 const uint8_t *source = pm_string_source(capture);
20888 size_t length = pm_string_length(capture);
20899 const uint8_t *cursor = pm_memchr(source,
'\\', length, parser->encoding_changed, parser->encoding);
20900 if (PRISM_UNLIKELY(cursor != NULL)) {
20901 pm_named_capture_escape(parser, &unescaped, source, length, cursor, shared ? NULL : &call->receiver->location);
20902 source = (
const uint8_t *) pm_buffer_value(&unescaped);
20903 length = pm_buffer_length(&unescaped);
20906 const uint8_t *start;
20907 const uint8_t *end;
20912 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20913 pm_buffer_cleanup(&unescaped);
20921 end = source + length;
20922 name = pm_parser_constant_id_raw(parser, start, end);
20926 start = parser->start + PM_NODE_START(call->
receiver);
20927 end = parser->start + PM_NODE_END(call->
receiver);
20929 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
20930 memcpy(memory, source, length);
20931 name = pm_parser_constant_id_owned(parser, memory, length);
20936 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20937 pm_constant_id_list_append(parser->arena, names, name);
20940 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20943 if (pm_local_is_keyword((
const char *) source, length)) {
20944 pm_buffer_cleanup(&unescaped);
20950 pm_parser_local_add(parser, name, start, end, 0);
20955 if (callback_data->match == NULL) {
20956 callback_data->match = pm_match_write_node_create(parser, call);
20961 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &TOK2LOC(parser, &((
pm_token_t) { .type = 0, .start = start, .end = end })), name, depth == -1 ? 0 : (uint32_t) depth));
20962 pm_node_list_append(parser->arena, &callback_data->match->
targets, target);
20965 pm_buffer_cleanup(&unescaped);
20981 pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content),
false, extended_mode, parse_regular_expression_named_capture, &callback_data);
20983 if (callback_data.match != NULL) {
20984 return UP(callback_data.match);
20991parse_expression_infix(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20994 switch (token.type) {
20995 case PM_TOKEN_EQUAL: {
20996 switch (PM_NODE_TYPE(node)) {
20997 case PM_CALL_NODE: {
21003 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21004 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
21008 case PM_CASE_WRITABLE: {
21012 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21013 pm_parser_local_add_location(parser, &node->
location, 0);
21016 parser_lex(parser);
21017 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, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21019 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
21020 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21023 return parse_write(parser, node, &token, value);
21025 case PM_SPLAT_NODE: {
21027 pm_multi_target_node_targets_append(parser, multi_target, node);
21029 parser_lex(parser);
21030 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21031 return parse_write(parser, UP(multi_target), &token, value);
21033 case PM_SOURCE_ENCODING_NODE:
21034 case PM_FALSE_NODE:
21035 case PM_SOURCE_FILE_NODE:
21036 case PM_SOURCE_LINE_NODE:
21039 case PM_TRUE_NODE: {
21042 parser_lex(parser);
21043 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21044 return parse_unwriteable_write(parser, node, &token, value);
21050 parser_lex(parser);
21051 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21055 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21056 switch (PM_NODE_TYPE(node)) {
21057 case PM_BACK_REFERENCE_READ_NODE:
21058 case PM_NUMBERED_REFERENCE_READ_NODE:
21059 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21061 case PM_GLOBAL_VARIABLE_READ_NODE: {
21062 parser_lex(parser);
21064 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21065 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
21069 case PM_CLASS_VARIABLE_READ_NODE: {
21070 parser_lex(parser);
21072 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21077 case PM_CONSTANT_PATH_NODE: {
21078 parser_lex(parser);
21080 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21083 return parse_shareable_constant_write(parser, write);
21085 case PM_CONSTANT_READ_NODE: {
21086 parser_lex(parser);
21088 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21091 return parse_shareable_constant_write(parser, write);
21093 case PM_INSTANCE_VARIABLE_READ_NODE: {
21094 parser_lex(parser);
21096 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21101 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21103 parser_lex(parser);
21105 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21106 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
21108 pm_node_unreference(parser, node);
21111 case PM_LOCAL_VARIABLE_READ_NODE: {
21112 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21114 pm_node_unreference(parser, node);
21118 parser_lex(parser);
21120 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21121 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21125 case PM_CALL_NODE: {
21131 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21134 parser_lex(parser);
21136 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21137 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21144 parser_lex(parser);
21149 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21150 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21151 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
21155 if (pm_call_node_writable_p(parser, cast)) {
21156 parse_write_name(parser, &cast->
name);
21158 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21161 parse_call_operator_write(parser, cast, &token);
21162 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21163 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
21165 case PM_MULTI_WRITE_NODE: {
21166 parser_lex(parser);
21167 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21171 parser_lex(parser);
21176 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21180 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21181 switch (PM_NODE_TYPE(node)) {
21182 case PM_BACK_REFERENCE_READ_NODE:
21183 case PM_NUMBERED_REFERENCE_READ_NODE:
21184 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21186 case PM_GLOBAL_VARIABLE_READ_NODE: {
21187 parser_lex(parser);
21189 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21190 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
21194 case PM_CLASS_VARIABLE_READ_NODE: {
21195 parser_lex(parser);
21197 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21202 case PM_CONSTANT_PATH_NODE: {
21203 parser_lex(parser);
21205 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21208 return parse_shareable_constant_write(parser, write);
21210 case PM_CONSTANT_READ_NODE: {
21211 parser_lex(parser);
21213 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21216 return parse_shareable_constant_write(parser, write);
21218 case PM_INSTANCE_VARIABLE_READ_NODE: {
21219 parser_lex(parser);
21221 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21226 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21228 parser_lex(parser);
21230 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21231 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
21233 pm_node_unreference(parser, node);
21236 case PM_LOCAL_VARIABLE_READ_NODE: {
21237 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21238 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21239 pm_node_unreference(parser, node);
21243 parser_lex(parser);
21245 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21246 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21250 case PM_CALL_NODE: {
21256 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21259 parser_lex(parser);
21261 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21262 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21269 parser_lex(parser);
21274 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21275 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21276 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
21280 if (pm_call_node_writable_p(parser, cast)) {
21281 parse_write_name(parser, &cast->
name);
21283 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21286 parse_call_operator_write(parser, cast, &token);
21287 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21288 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
21290 case PM_MULTI_WRITE_NODE: {
21291 parser_lex(parser);
21292 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21296 parser_lex(parser);
21301 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21305 case PM_TOKEN_AMPERSAND_EQUAL:
21306 case PM_TOKEN_CARET_EQUAL:
21307 case PM_TOKEN_GREATER_GREATER_EQUAL:
21308 case PM_TOKEN_LESS_LESS_EQUAL:
21309 case PM_TOKEN_MINUS_EQUAL:
21310 case PM_TOKEN_PERCENT_EQUAL:
21311 case PM_TOKEN_PIPE_EQUAL:
21312 case PM_TOKEN_PLUS_EQUAL:
21313 case PM_TOKEN_SLASH_EQUAL:
21314 case PM_TOKEN_STAR_EQUAL:
21315 case PM_TOKEN_STAR_STAR_EQUAL: {
21316 switch (PM_NODE_TYPE(node)) {
21317 case PM_BACK_REFERENCE_READ_NODE:
21318 case PM_NUMBERED_REFERENCE_READ_NODE:
21319 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21321 case PM_GLOBAL_VARIABLE_READ_NODE: {
21322 parser_lex(parser);
21324 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21325 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
21329 case PM_CLASS_VARIABLE_READ_NODE: {
21330 parser_lex(parser);
21332 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21337 case PM_CONSTANT_PATH_NODE: {
21338 parser_lex(parser);
21340 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21343 return parse_shareable_constant_write(parser, write);
21345 case PM_CONSTANT_READ_NODE: {
21346 parser_lex(parser);
21348 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21351 return parse_shareable_constant_write(parser, write);
21353 case PM_INSTANCE_VARIABLE_READ_NODE: {
21354 parser_lex(parser);
21356 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21361 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21363 parser_lex(parser);
21365 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21366 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21368 pm_node_unreference(parser, node);
21371 case PM_LOCAL_VARIABLE_READ_NODE: {
21372 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21373 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21374 pm_node_unreference(parser, node);
21378 parser_lex(parser);
21380 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21381 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21385 case PM_CALL_NODE: {
21386 parser_lex(parser);
21392 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21395 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21396 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21404 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21405 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21406 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21410 if (pm_call_node_writable_p(parser, cast)) {
21411 parse_write_name(parser, &cast->
name);
21413 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21416 parse_call_operator_write(parser, cast, &token);
21417 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21418 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21420 case PM_MULTI_WRITE_NODE: {
21421 parser_lex(parser);
21422 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21426 parser_lex(parser);
21431 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
21435 case PM_TOKEN_AMPERSAND_AMPERSAND:
21436 case PM_TOKEN_KEYWORD_AND: {
21437 parser_lex(parser);
21439 pm_node_t *right = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (parser->previous.
type == PM_TOKEN_KEYWORD_AND ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21440 return UP(pm_and_node_create(parser, node, &token, right));
21442 case PM_TOKEN_KEYWORD_OR:
21443 case PM_TOKEN_PIPE_PIPE: {
21444 parser_lex(parser);
21446 pm_node_t *right = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (parser->previous.
type == PM_TOKEN_KEYWORD_OR ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0)), PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21447 return UP(pm_or_node_create(parser, node, &token, right));
21449 case PM_TOKEN_EQUAL_TILDE: {
21457 parser_lex(parser);
21458 pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21461 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21467 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21474 bool interpolated =
false;
21475 size_t total_length = 0;
21479 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21480 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21482 interpolated =
true;
21487 if (!interpolated && total_length > 0) {
21488 void *memory =
xmalloc(total_length);
21489 if (!memory) abort();
21491 uint8_t *cursor = memory;
21494 size_t length = pm_string_length(unescaped);
21496 memcpy(cursor, pm_string_source(unescaped), length);
21501 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21503 result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21504 pm_string_cleanup(&owned);
21506 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21517 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
21519 if (name_data.match != NULL) {
21520 result = UP(name_data.match);
21526 case PM_TOKEN_UAMPERSAND:
21527 case PM_TOKEN_USTAR:
21528 case PM_TOKEN_USTAR_STAR:
21531 case PM_TOKEN_BANG_EQUAL:
21532 case PM_TOKEN_BANG_TILDE:
21533 case PM_TOKEN_EQUAL_EQUAL:
21534 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21535 case PM_TOKEN_LESS_EQUAL_GREATER:
21536 case PM_TOKEN_CARET:
21537 case PM_TOKEN_PIPE:
21538 case PM_TOKEN_AMPERSAND:
21539 case PM_TOKEN_GREATER_GREATER:
21540 case PM_TOKEN_LESS_LESS:
21541 case PM_TOKEN_MINUS:
21542 case PM_TOKEN_PLUS:
21543 case PM_TOKEN_PERCENT:
21544 case PM_TOKEN_SLASH:
21545 case PM_TOKEN_STAR:
21546 case PM_TOKEN_STAR_STAR: {
21547 parser_lex(parser);
21549 switch (PM_NODE_TYPE(node)) {
21550 case PM_RESCUE_MODIFIER_NODE: {
21553 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21557 case PM_AND_NODE: {
21559 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21560 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21566 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21567 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21575 pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21576 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21578 case PM_TOKEN_GREATER:
21579 case PM_TOKEN_GREATER_EQUAL:
21580 case PM_TOKEN_LESS:
21581 case PM_TOKEN_LESS_EQUAL: {
21582 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21583 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21586 parser_lex(parser);
21587 pm_node_t *argument = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21588 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21590 case PM_TOKEN_AMPERSAND_DOT:
21591 case PM_TOKEN_DOT: {
21592 parser_lex(parser);
21597 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21598 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21599 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21602 switch (PM_NODE_TYPE(node)) {
21603 case PM_RESCUE_MODIFIER_NODE: {
21606 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21610 case PM_AND_NODE: {
21612 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21613 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21619 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21620 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21630 switch (parser->current.type) {
21631 case PM_CASE_OPERATOR:
21632 case PM_CASE_KEYWORD:
21633 case PM_TOKEN_CONSTANT:
21634 case PM_TOKEN_IDENTIFIER:
21635 case PM_TOKEN_METHOD_NAME: {
21636 parser_lex(parser);
21637 message = parser->previous;
21641 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
21642 message = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
21646 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21647 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21650 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21653 match1(parser, PM_TOKEN_COMMA)
21655 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21660 case PM_TOKEN_DOT_DOT:
21661 case PM_TOKEN_DOT_DOT_DOT: {
21662 parser_lex(parser);
21665 if (token_begins_expression_p(parser->current.type)) {
21666 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21669 return UP(pm_range_node_create(parser, node, &token, right));
21671 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21673 parser_lex(parser);
21675 pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21676 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21678 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21680 parser_lex(parser);
21682 pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21683 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21685 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21686 parser_lex(parser);
21688 pm_statements_node_body_append(parser, statements, node,
true);
21690 pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21691 return UP(pm_until_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0));
21693 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21694 parser_lex(parser);
21696 pm_statements_node_body_append(parser, statements, node,
true);
21698 pm_node_t *predicate = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21699 return UP(pm_while_node_modifier_create(parser, &token, predicate, statements, PM_NODE_TYPE_P(node, PM_BEGIN_NODE) ? PM_LOOP_FLAGS_BEGIN_MODIFIER : 0));
21701 case PM_TOKEN_QUESTION_MARK: {
21702 context_push(parser, PM_CONTEXT_TERNARY);
21704 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21707 parser_lex(parser);
21709 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21711 if (parser->recovering) {
21719 pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
21721 context_pop(parser);
21722 pop_block_exits(parser, previous_block_exits);
21723 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21726 accept1(parser, PM_TOKEN_NEWLINE);
21727 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21730 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21732 context_pop(parser);
21733 pop_block_exits(parser, previous_block_exits);
21734 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21736 case PM_TOKEN_COLON_COLON: {
21737 parser_lex(parser);
21740 switch (parser->current.type) {
21741 case PM_TOKEN_CONSTANT: {
21742 parser_lex(parser);
21746 (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21747 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21758 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21759 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21762 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21766 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21767 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21772 case PM_CASE_OPERATOR:
21773 case PM_CASE_KEYWORD:
21774 case PM_TOKEN_IDENTIFIER:
21775 case PM_TOKEN_METHOD_NAME: {
21776 parser_lex(parser);
21782 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21783 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21786 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21787 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21792 case PM_TOKEN_PARENTHESIS_LEFT: {
21796 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21798 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21801 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21802 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21806 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21807 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21808 parser_lex(parser);
21809 accept1(parser, PM_TOKEN_NEWLINE);
21811 pm_node_t *value = parse_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21812 context_pop(parser);
21814 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21816 case PM_TOKEN_BRACKET_LEFT: {
21817 parser_lex(parser);
21820 arguments.
opening_loc = TOK2LOC(parser, &parser->previous);
21822 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21823 pm_accepts_block_stack_push(parser,
true);
21824 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
21825 pm_accepts_block_stack_pop(parser);
21826 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21829 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
21833 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21834 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21835 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21842 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21843 block = parse_block(parser, (uint16_t) (depth + 1));
21844 pm_arguments_validate_block(parser, &arguments, block);
21845 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21846 block = parse_block(parser, (uint16_t) (depth + 1));
21849 if (block != NULL) {
21850 if (arguments.
block != NULL) {
21851 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21853 arguments.
arguments = pm_arguments_node_create(parser);
21855 pm_arguments_node_arguments_append(parser->arena, arguments.
arguments, arguments.
block);
21858 arguments.
block = UP(block);
21861 return UP(pm_call_node_aref_create(parser, node, &arguments));
21863 case PM_TOKEN_KEYWORD_IN: {
21864 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
21865 parser->pattern_matching_newlines =
true;
21868 parser->command_start =
false;
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_IN, (uint16_t) (depth + 1));
21875 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
21877 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21879 case PM_TOKEN_EQUAL_GREATER: {
21880 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
21881 parser->pattern_matching_newlines =
true;
21884 parser->command_start =
false;
21885 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21886 parser_lex(parser);
21889 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));
21891 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
21893 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21896 assert(
false &&
"unreachable");
21901#undef PM_PARSE_PATTERN_SINGLE
21902#undef PM_PARSE_PATTERN_TOP
21903#undef PM_PARSE_PATTERN_MULTI
21919 pm_binding_power_t left = pm_binding_powers[parser->current.type].
left;
21921 switch (PM_NODE_TYPE(node)) {
21922 case PM_MULTI_WRITE_NODE:
21923 case PM_RETURN_NODE:
21924 case PM_BREAK_NODE:
21926 return left > PM_BINDING_POWER_MODIFIER;
21927 case PM_CLASS_VARIABLE_WRITE_NODE:
21928 case PM_CONSTANT_PATH_WRITE_NODE:
21929 case PM_CONSTANT_WRITE_NODE:
21930 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21931 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21932 case PM_LOCAL_VARIABLE_WRITE_NODE:
21933 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
21934 case PM_CALL_NODE: {
21937 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
21938 return left > PM_BINDING_POWER_MODIFIER;
21944 if (pm_command_call_value_p(node)) {
21945 return left > PM_BINDING_POWER_COMPOSITION;
21951 if (pm_block_call_p(node)) {
21952 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL;
21957 case PM_SUPER_NODE:
21958 case PM_YIELD_NODE:
21961 if (pm_command_call_value_p(node)) {
21962 return left > PM_BINDING_POWER_COMPOSITION;
21969 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(node);
21970 case PM_RESCUE_MODIFIER_NODE:
21974 if (left > PM_BINDING_POWER_MODIFIER) {
21977 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
21994parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
21995 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
21996 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21997 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
22000 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
22005 switch (PM_NODE_TYPE(node)) {
22006 case PM_ERROR_RECOVERY_NODE:
22008 case PM_PRE_EXECUTION_NODE:
22010 case PM_POST_EXECUTION_NODE:
22011 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22012 case PM_ALIAS_METHOD_NODE:
22013 case PM_UNDEF_NODE:
22014 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
22019 case PM_SUPER_NODE:
22020 case PM_YIELD_NODE:
22022 if (parse_expression_terminator(parser, node)) {
22026 case PM_SYMBOL_NODE:
22027 if (pm_symbol_node_label_p(parser, node)) {
22038 pm_token_type_t current_token_type;
22041 current_token_type = parser->current.type,
22042 current_binding_powers = pm_binding_powers[current_token_type],
22043 binding_power <= current_binding_powers.
left &&
22044 current_binding_powers.
binary
22046 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
22047 if (parse_expression_terminator(parser, node))
return node;
22051 if (current_binding_powers.
nonassoc) {
22054 if (match1(parser, current_token_type)) {
22055 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_str(parser->current.type), pm_token_str(current_token_type));
22066 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22067 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22068 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_NON_ASSOCIATIVE_OPERATOR, pm_token_str(parser->current.type), pm_token_str(current_token_type));
22072 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->current.type].left) {
22075 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->current.type].left) {
22080 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
22089 switch (node->
type) {
22090 case PM_CALL_NODE: {
22104 cast->
block == NULL &&
22114 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22117 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22122 case PM_CONSTANT_PATH_NODE:
22125 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22130 if (context_terminator(parser->current_context->context, &parser->current)) {
22133 !next_binding_powers.
binary ||
22134 binding_power > next_binding_powers.
left ||
22135 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
22151 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22152 if (statements == NULL) {
22153 statements = pm_statements_node_create(parser);
22157 pm_arguments_node_arguments_append(
22160 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
22163 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
22166 pm_parser_constant_id_constant(parser,
"print", 5)
22170 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22171 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22172 if (statements == NULL) {
22173 statements = pm_statements_node_create(parser);
22177 pm_arguments_node_arguments_append(
22180 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
22183 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22184 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
22188 pm_parser_constant_id_constant(parser,
"$F", 2),
22192 pm_statements_node_body_prepend(parser->arena, statements, UP(write));
22196 pm_arguments_node_arguments_append(
22199 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
22202 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22204 pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
22206 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
22208 UP(pm_true_node_synthesized_create(parser))
22211 pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
22212 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22216 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
22218 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
22222 statements = wrapped_statements;
22236 if (parser->current_scope == NULL) {
22237 pm_parser_scope_push(parser,
true);
22241 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22243 parser_lex(parser);
22246 if (statements != NULL && !parser->parsing_eval) {
22250 assert(statements->
body.
size > 0);
22251 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22255 pm_locals_order(parser, &parser->current_scope->locals, &locals,
true);
22256 pm_parser_scope_pop(parser);
22261 statements = wrap_statements(parser, statements);
22263 flush_block_exits(parser, previous_block_exits);
22269 if (statements == NULL) {
22270 statements = pm_statements_node_create(parser);
22274 return UP(pm_program_node_create(parser, &locals, statements));
22291pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22292 size_t little_length = strlen(little);
22294 for (
const char *max = big + big_length - little_length; big <= max; big++) {
22295 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22302#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22310pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22311 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22312 pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
22323 const char *switches = pm_strnstr(engine,
" -", length);
22324 if (switches == NULL)
return;
22327 options->shebang_callback(
22329 (
const uint8_t *) (switches + 1),
22330 length - ((
size_t) (switches - engine)) - 1,
22331 options->shebang_callback_data
22334 size_t encoding_length;
22335 if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
22336 const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
22337 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22340 parser->command_line = next_options.command_line;
22341 parser->frozen_string_literal = next_options.frozen_string_literal;
22349 assert(arena != NULL);
22350 assert(source != NULL);
22354 .metadata_arena = { 0 },
22356 .lex_state = PM_LEX_STATE_BEG,
22357 .enclosure_nesting = 0,
22358 .lambda_enclosure_nesting = -1,
22359 .brace_nesting = 0,
22360 .do_loop_stack = 0,
22361 .accepts_block_stack = 0,
22364 .stack = {{ .mode = PM_LEX_DEFAULT }},
22365 .current = &parser->lex_modes.stack[0],
22368 .end = source + size,
22369 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22370 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22371 .next_start = NULL,
22372 .heredoc_end = NULL,
22374 .comment_list = { 0 },
22375 .magic_comment_list = { 0 },
22376 .warning_list = { 0 },
22377 .error_list = { 0 },
22378 .current_scope = NULL,
22379 .current_context = NULL,
22380 .encoding = PM_ENCODING_UTF_8_ENTRY,
22381 .encoding_changed_callback = NULL,
22382 .encoding_comment_start = source,
22383 .lex_callback = { 0 },
22385 .constant_pool = { 0 },
22386 .line_offsets = { 0 },
22388 .current_string = PM_STRING_EMPTY,
22390 .explicit_encoding = NULL,
22392 .parsing_eval =
false,
22393 .partial_script =
false,
22394 .command_start =
true,
22395 .recovering =
false,
22396 .continuable =
true,
22397 .encoding_locked =
false,
22398 .encoding_changed =
false,
22399 .pattern_matching_newlines =
false,
22400 .in_keyword_arg =
false,
22401 .current_block_exits = NULL,
22402 .semantic_token_seen =
false,
22404 .warn_mismatched_indentation =
true
22412 if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
22413 if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
22420 uint32_t constant_size = ((uint32_t) size) / 120;
22421 pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
22426 size_t newline_size = size / 22;
22427 pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
22430 if (options != NULL) {
22432 parser->filepath = options->filepath;
22435 parser->start_line = options->line;
22438 size_t encoding_length = pm_string_length(&options->encoding);
22439 if (encoding_length > 0) {
22440 const uint8_t *encoding_source = pm_string_source(&options->encoding);
22441 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22445 parser->encoding_locked = options->encoding_locked;
22448 parser->frozen_string_literal = options->frozen_string_literal;
22451 parser->command_line = options->command_line;
22454 parser->version = options->version;
22457 parser->partial_script = options->partial_script;
22460 parser->parsing_eval = options->scopes_count > 0;
22461 if (parser->parsing_eval) parser->warn_mismatched_indentation =
false;
22463 for (
size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
22465 pm_parser_scope_push(parser, scope_index == 0);
22469 parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
22471 for (
size_t local_index = 0; local_index < scope->locals_count; local_index++) {
22472 const pm_string_t *local = pm_options_scope_local(scope, local_index);
22474 const uint8_t *source = pm_string_source(local);
22475 size_t length = pm_string_length(local);
22477 uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
22478 memcpy(allocated, source, length);
22479 pm_parser_local_add_owned(parser, allocated, length);
22486 if (parser->version == PM_OPTIONS_VERSION_UNSET) {
22487 parser->version = PM_OPTIONS_VERSION_LATEST;
22490 pm_accepts_block_stack_push(parser,
true);
22493 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22494 parser->current.end += 3;
22495 parser->encoding_comment_start += 3;
22497 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
22498 parser->encoding = PM_ENCODING_UTF_8_ENTRY;
22499 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
22506 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22523 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
22524 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
22526 if (length > 2 && parser->current.end[0] ==
'#' && parser->current.end[1] ==
'!') {
22527 const char *engine;
22529 if ((engine = pm_strnstr((
const char *) parser->start,
"ruby", length)) != NULL) {
22530 if (newline != NULL) {
22531 parser->encoding_comment_start = newline + 1;
22533 if (options == NULL || options->main_script) {
22534 pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
22538 if (options != NULL && options->main_script && options->shebang_callback != NULL) {
22539 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->start)));
22542 search_shebang =
false;
22543 }
else if (options != NULL && options->main_script && !parser->parsing_eval) {
22544 search_shebang =
true;
22550 if (search_shebang) {
22553 bool found_shebang =
false;
22557 const uint8_t *cursor = parser->start;
22561 const uint8_t *newline = next_newline(cursor, parser->end - cursor);
22563 while (newline != NULL) {
22564 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
22566 cursor = newline + 1;
22567 newline = next_newline(cursor, parser->end - cursor);
22569 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
22570 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22571 const char *engine;
22572 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22573 found_shebang =
true;
22575 if (newline != NULL) {
22576 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22577 parser->encoding_comment_start = newline + 1;
22580 if (options != NULL && options->shebang_callback != NULL) {
22581 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22589 if (found_shebang) {
22590 parser->previous = (
pm_token_t) { .
type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22591 parser->current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22593 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
22594 pm_line_offset_list_clear(&parser->line_offsets);
22601 parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
22614 if (parser == NULL) abort();
22616 pm_parser_init(arena, parser, source, size, options);
22625 pm_string_cleanup(&parser->filepath);
22626 pm_arena_cleanup(&parser->metadata_arena);
22628 while (parser->current_scope != NULL) {
22633 pm_parser_scope_pop(parser);
22636 while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
22637 lex_mode_pop(parser);
22646 pm_parser_cleanup(parser);
22656pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
22658 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
22659 case PM_ERR_BEGIN_UPCASE_BRACE:
22660 case PM_ERR_CLASS_VARIABLE_BARE:
22661 case PM_ERR_END_UPCASE_BRACE:
22662 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
22663 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
22664 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
22665 case PM_ERR_EXPRESSION_NOT_WRITABLE:
22666 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
22667 case PM_ERR_FLOAT_PARSE:
22668 case PM_ERR_GLOBAL_VARIABLE_BARE:
22669 case PM_ERR_HASH_KEY:
22670 case PM_ERR_HEREDOC_IDENTIFIER:
22671 case PM_ERR_INSTANCE_VARIABLE_BARE:
22672 case PM_ERR_INVALID_BLOCK_EXIT:
22673 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
22674 case PM_ERR_INVALID_FLOAT_EXPONENT:
22675 case PM_ERR_INVALID_NUMBER_BINARY:
22676 case PM_ERR_INVALID_NUMBER_DECIMAL:
22677 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
22678 case PM_ERR_INVALID_NUMBER_OCTAL:
22679 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
22680 case PM_ERR_NO_LOCAL_VARIABLE:
22681 case PM_ERR_PARAMETER_ORDER:
22682 case PM_ERR_STATEMENT_UNDEF:
22683 case PM_ERR_VOID_EXPRESSION:
22726 if (parser->error_list.size == 0) {
22727 parser->continuable =
false;
22731 if (!parser->continuable)
return;
22733 size_t source_length = (size_t) (parser->end - parser->start);
22736 bool has_non_stray_error =
false;
22738 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE && error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT && !pm_parse_err_is_fatal(error->diag_id)) {
22739 has_non_stray_error =
true;
22747 size_t non_stray_min_start = SIZE_MAX;
22750 size_t error_start = (size_t) error->location.start;
22751 size_t error_end = error_start + (size_t) error->location.length;
22752 bool at_eof = error_end >= source_length;
22755 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
22756 parser->continuable =
false;
22761 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
22762 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
22763 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
22772 if (non_stray_min_start < error_start)
continue;
22779 if (at_eof && error_start > 0) {
22781 if (error->location.length == 1) {
22782 const uint8_t *
byte = parser->start + error_start;
22783 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
22784 parser->continuable =
false;
22794 if (has_non_stray_error)
continue;
22801 if (error->location.length == 1) {
22802 const uint8_t *
byte = parser->start + error_start;
22803 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
22807 parser->continuable =
false;
22817 pm_node_t *node = parse_program(parser);
22818 pm_parse_continuable(parser);
22830 bool eof = pm_source_stream_read(source);
22835 while (!eof && tmp->error_list.size > 0) {
22836 eof = pm_source_stream_read(source);
22839 pm_arena_cleanup(arena);
22841 tmp =
pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
22849#undef PM_CASE_KEYWORD
22850#undef PM_CASE_OPERATOR
22851#undef PM_CASE_WRITABLE
22852#undef PM_STRING_EMPTY
22857#ifndef PRISM_EXCLUDE_SERIALIZATION
22861 pm_buffer_append_string(buffer,
"PRISM", 5);
22865 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22873 pm_serialize_header(buffer);
22874 pm_serialize_content(parser, node, buffer);
22875 pm_buffer_append_byte(buffer,
'\0');
22883pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22885 pm_options_read(&options, data);
22889 pm_parser_init(&arena, &parser, source, size, &options);
22893 pm_serialize_header(buffer);
22894 pm_serialize_content(&parser, node, buffer);
22895 pm_buffer_append_byte(buffer,
'\0');
22897 pm_parser_cleanup(&parser);
22898 pm_arena_cleanup(&arena);
22899 pm_options_cleanup(&options);
22911 pm_options_read(&options, data);
22913 pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
22914 pm_serialize_header(buffer);
22915 pm_serialize_content(parser, node, buffer);
22916 pm_buffer_append_byte(buffer,
'\0');
22919 pm_arena_cleanup(&arena);
22920 pm_options_cleanup(&options);
22927pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22929 pm_options_read(&options, data);
22933 pm_parser_init(&arena, &parser, source, size, &options);
22936 pm_serialize_header(buffer);
22937 pm_serialize_encoding(parser.encoding, buffer);
22938 pm_buffer_append_varsint(buffer, parser.start_line);
22939 pm_serialize_comment_list(&parser.comment_list, buffer);
22941 pm_parser_cleanup(&parser);
22942 pm_arena_cleanup(&arena);
22943 pm_options_cleanup(&options);
#define PRISM_ALIGNOF
Get the alignment requirement of a type.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
A header file that defines macros to exclude certain features of the prism library.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
int len
Length of the buffer.
#define PRISM_INLINE
Old Visual Studio versions do not support the inline keyword, so we need to define it to be __inline.
VALUE type(ANYARGS)
ANYARGS-ed function type.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should not be frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made frozen.
#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.
PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_parser_t * pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) PRISM_NONNULL(1)
Allocate and initialize a parser with the given start and end pointers.
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser) PRISM_NONNULL(1)
Free both the memory held by the given parser and the parser itself.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1)
Initiate the parser with the given parser.
#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.
The version of the Prism library.
#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 functions related to serializing the AST to a binary format.
Functions for parsing streams.
PM_NODE_ALIGNAS struct pm_node * left
AndNode::left.
PM_NODE_ALIGNAS 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.
PM_NODE_ALIGNAS struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
PM_NODE_ALIGNAS struct pm_node * value
AssocNode::value.
PM_NODE_ALIGNAS struct pm_node * key
AssocNode::key.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
BeginNode::else_clause.
PM_NODE_ALIGNAS struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
PM_NODE_ALIGNAS struct pm_statements_node * statements
BeginNode::statements.
PM_NODE_ALIGNAS struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
pm_node_t base
The embedded base node.
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.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
pm_constant_id_t name
CallNode::name.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
CallNode::arguments.
pm_location_t equal_loc
CallNode::equal_loc.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
PM_NODE_ALIGNAS struct pm_node * block
CallNode::block.
PM_NODE_ALIGNAS struct pm_node * receiver
CallNode::receiver.
struct pm_node_list conditions
CaseMatchNode::conditions.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
CaseMatchNode::else_clause.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
CaseNode::else_clause.
struct pm_node_list conditions
CaseNode::conditions.
size_t size
The number of constant ids in the list.
pm_location_t equal_loc
DefNode::equal_loc.
PM_NODE_ALIGNAS struct pm_node * body
DefNode::body.
PM_NODE_ALIGNAS struct pm_statements_node * statements
ElseNode::statements.
PM_NODE_ALIGNAS struct pm_statements_node * statements
EnsureNode::statements.
pm_location_t opening_loc
FindPatternNode::opening_loc.
PM_NODE_ALIGNAS struct pm_node * constant
FindPatternNode::constant.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
GlobalVariableTargetNode.
struct pm_node_list elements
HashNode::elements.
PM_NODE_ALIGNAS struct pm_node * constant
HashPatternNode::constant.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_location_t closing_loc
HashPatternNode::closing_loc.
PM_NODE_ALIGNAS struct pm_statements_node * statements
IfNode::statements.
PM_NODE_ALIGNAS struct pm_node * subsequent
IfNode::subsequent.
PM_NODE_ALIGNAS struct pm_statements_node * statements
InNode::statements.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
int32_t line
The line number.
uint32_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
uint32_t depth
LocalVariableWriteNode::depth.
pm_constant_id_t name
LocalVariableWriteNode::name.
This struct represents a slice in the source code, defined by an offset and a length.
uint32_t start
The offset of the location from the start of the source.
uint32_t length
The length of the location.
struct pm_node_list targets
MatchWriteNode::targets.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_location_t location
This is the location of the node in the source.
PM_NODE_ALIGNAS struct pm_node * right
OrNode::right.
PM_NODE_ALIGNAS struct pm_node * left
OrNode::left.
PM_NODE_ALIGNAS struct pm_node * block
ParametersNode::block.
PM_NODE_ALIGNAS struct pm_node * rest
ParametersNode::rest.
PM_NODE_ALIGNAS struct pm_node * keyword_rest
ParametersNode::keyword_rest.
PM_NODE_ALIGNAS struct pm_node * body
ParenthesesNode::body.
PM_NODE_ALIGNAS struct pm_node * right
RangeNode::right.
PM_NODE_ALIGNAS 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_ALIGNAS struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
PM_NODE_ALIGNAS struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
PM_NODE_ALIGNAS struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
pm_node_t base
The embedded base node.
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t content_loc
StringNode::content_loc.
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::@110 type
The type of the string.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
SuperNode::arguments.
pm_location_t lparen_loc
SuperNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_node * block
SuperNode::block.
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.
PM_NODE_ALIGNAS struct pm_statements_node * statements
UnlessNode::statements.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
UnlessNode::else_clause.
PM_NODE_ALIGNAS struct pm_statements_node * statements
WhenNode::statements.
pm_location_t lparen_loc
YieldNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
YieldNode::arguments.
#define PRISM_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.