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_POSTEXE:
15325 case PM_CONTEXT_UNTIL:
15326 case PM_CONTEXT_WHILE:
15330 case PM_CONTEXT_DEF:
15331 case PM_CONTEXT_DEF_PARAMS:
15332 case PM_CONTEXT_DEF_ELSE:
15333 case PM_CONTEXT_DEF_ENSURE:
15334 case PM_CONTEXT_DEF_RESCUE:
15335 case PM_CONTEXT_MAIN:
15336 case PM_CONTEXT_PREEXE:
15337 case PM_CONTEXT_SCLASS:
15338 case PM_CONTEXT_SCLASS_ELSE:
15339 case PM_CONTEXT_SCLASS_ENSURE:
15340 case PM_CONTEXT_SCLASS_RESCUE:
15350 assert(parser->current_block_exits != NULL);
15351 pm_node_list_append(parser->arena, parser->current_block_exits, node);
15353 case PM_CONTEXT_BEGIN_ELSE:
15354 case PM_CONTEXT_BEGIN_ENSURE:
15355 case PM_CONTEXT_BEGIN_RESCUE:
15356 case PM_CONTEXT_BEGIN:
15357 case PM_CONTEXT_CASE_IN:
15358 case PM_CONTEXT_CASE_WHEN:
15359 case PM_CONTEXT_CLASS_ELSE:
15360 case PM_CONTEXT_CLASS_ENSURE:
15361 case PM_CONTEXT_CLASS_RESCUE:
15362 case PM_CONTEXT_CLASS:
15363 case PM_CONTEXT_DEFAULT_PARAMS:
15364 case PM_CONTEXT_ELSE:
15365 case PM_CONTEXT_ELSIF:
15366 case PM_CONTEXT_EMBEXPR:
15367 case PM_CONTEXT_FOR_INDEX:
15368 case PM_CONTEXT_IF:
15369 case PM_CONTEXT_MODULE_ELSE:
15370 case PM_CONTEXT_MODULE_ENSURE:
15371 case PM_CONTEXT_MODULE_RESCUE:
15372 case PM_CONTEXT_MODULE:
15373 case PM_CONTEXT_MULTI_TARGET:
15374 case PM_CONTEXT_PARENS:
15375 case PM_CONTEXT_PREDICATE:
15376 case PM_CONTEXT_RESCUE_MODIFIER:
15377 case PM_CONTEXT_TERNARY:
15378 case PM_CONTEXT_UNLESS:
15382 case PM_CONTEXT_NONE:
15384 assert(
false &&
"unreachable");
15396 pm_node_list_t *previous_block_exits = parser->current_block_exits;
15397 parser->current_block_exits = current_block_exits;
15398 return previous_block_exits;
15412 switch (PM_NODE_TYPE(block_exit)) {
15413 case PM_BREAK_NODE:
type =
"break";
break;
15414 case PM_NEXT_NODE:
type =
"next";
break;
15415 case PM_REDO_NODE:
type =
"redo";
break;
15416 default: assert(
false &&
"unreachable");
type =
"";
break;
15419 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15422 parser->current_block_exits = previous_block_exits;
15431 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15435 parser->current_block_exits = previous_block_exits;
15436 }
else if (previous_block_exits != NULL) {
15442 pm_node_list_concat(parser->arena, previous_block_exits, parser->current_block_exits);
15443 parser->current_block_exits = previous_block_exits;
15448 flush_block_exits(parser, previous_block_exits);
15453parse_predicate(
pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context,
pm_token_t *then_keyword, uint16_t depth) {
15454 context_push(parser, PM_CONTEXT_PREDICATE);
15455 pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
15456 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));
15459 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15461 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15462 predicate_closed =
true;
15463 *then_keyword = parser->previous;
15466 if (!predicate_closed) {
15467 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15470 context_pop(parser);
15475parse_conditional(
pm_parser_t *parser, pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15477 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15482 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15485 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15486 pm_accepts_block_stack_push(parser,
true);
15487 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15488 pm_accepts_block_stack_pop(parser);
15489 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15495 case PM_CONTEXT_IF:
15496 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15498 case PM_CONTEXT_UNLESS:
15499 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
15502 assert(
false &&
"unreachable");
15510 if (context == PM_CONTEXT_IF) {
15511 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15512 if (parser_end_of_line_p(parser)) {
15513 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
15516 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15518 parser_lex(parser);
15520 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15521 pm_accepts_block_stack_push(parser,
true);
15523 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
15524 pm_accepts_block_stack_pop(parser);
15525 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15527 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15533 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15534 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15535 opening_newline_index = token_newline_index(parser);
15537 parser_lex(parser);
15540 pm_accepts_block_stack_push(parser,
true);
15541 pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
15542 pm_accepts_block_stack_pop(parser);
15544 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15545 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15546 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
15548 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
15551 case PM_CONTEXT_IF:
15552 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
15554 case PM_CONTEXT_UNLESS:
15558 assert(
false &&
"unreachable");
15562 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15563 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
15568 case PM_CONTEXT_IF: {
15570 bool recursing =
true;
15572 while (recursing) {
15573 switch (PM_NODE_TYPE(current)) {
15575 pm_if_node_end_keyword_loc_set(parser, (
pm_if_node_t *) current, &parser->previous);
15577 recursing = current != NULL;
15580 pm_else_node_end_keyword_loc_set(parser, (
pm_else_node_t *) current, &parser->previous);
15591 case PM_CONTEXT_UNLESS:
15592 pm_unless_node_end_keyword_loc_set(parser, (
pm_unless_node_t *) parent, &parser->previous);
15595 assert(
false &&
"unreachable");
15599 pop_block_exits(parser, previous_block_exits);
15607#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15608 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15609 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15610 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: \
15611 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15612 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15613 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15614 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15615 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15616 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15617 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15623#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15624 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15625 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15626 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15627 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15628 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15629 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15630 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15637#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15638 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15639 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15640 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15641 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15642 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15643 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15644 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15645 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15651#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15652 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15653 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15654 case PM_TOKEN_CLASS_VARIABLE
15660#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15661 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15662 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15663 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15667PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15674parse_unescaped_encoding(
const pm_parser_t *parser) {
15675 if (parser->explicit_encoding != NULL) {
15676 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
15679 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15680 }
else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
15685 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15696parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15697 switch (parser->current.type) {
15704 case PM_TOKEN_STRING_CONTENT: {
15705 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
15706 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15708 parser_lex(parser);
15717 case PM_TOKEN_EMBEXPR_BEGIN: {
15720 parser->explicit_encoding = NULL;
15722 pm_lex_state_t state = parser->lex_state;
15723 int brace_nesting = parser->brace_nesting;
15725 parser->brace_nesting = 0;
15726 lex_state_set(parser, PM_LEX_STATE_BEG);
15727 parser_lex(parser);
15732 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
15733 pm_accepts_block_stack_push(parser,
true);
15734 statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
15735 pm_accepts_block_stack_pop(parser);
15738 parser->brace_nesting = brace_nesting;
15739 lex_state_set(parser, state);
15740 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15745 if (statements != NULL && statements->
body.
size == 1) {
15746 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15749 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
15758 case PM_TOKEN_EMBVAR: {
15761 parser->explicit_encoding = NULL;
15763 lex_state_set(parser, PM_LEX_STATE_BEG);
15764 parser_lex(parser);
15769 switch (parser->current.type) {
15772 case PM_TOKEN_BACK_REFERENCE:
15773 parser_lex(parser);
15774 variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
15778 case PM_TOKEN_NUMBERED_REFERENCE:
15779 parser_lex(parser);
15780 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
15784 case PM_TOKEN_GLOBAL_VARIABLE:
15785 parser_lex(parser);
15786 variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
15790 case PM_TOKEN_INSTANCE_VARIABLE:
15791 parser_lex(parser);
15792 variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
15796 case PM_TOKEN_CLASS_VARIABLE:
15797 parser_lex(parser);
15798 variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
15804 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15805 variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
15809 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15812 parser_lex(parser);
15813 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15823static const uint8_t *
15824parse_operator_symbol_name(
const pm_token_t *name) {
15825 switch (name->
type) {
15826 case PM_TOKEN_TILDE:
15827 case PM_TOKEN_BANG:
15828 if (name->
end[-1] ==
'@')
return name->
end - 1;
15837 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
15838 const uint8_t *end = parse_operator_symbol_name(&parser->current);
15840 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15841 parser_lex(parser);
15843 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, end);
15844 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15856 const pm_token_t opening = parser->previous;
15858 if (lex_mode->mode != PM_LEX_STRING) {
15859 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15861 switch (parser->current.type) {
15862 case PM_CASE_OPERATOR:
15863 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15864 case PM_TOKEN_IDENTIFIER:
15865 case PM_TOKEN_CONSTANT:
15866 case PM_TOKEN_INSTANCE_VARIABLE:
15867 case PM_TOKEN_METHOD_NAME:
15868 case PM_TOKEN_CLASS_VARIABLE:
15869 case PM_TOKEN_GLOBAL_VARIABLE:
15870 case PM_TOKEN_NUMBERED_REFERENCE:
15871 case PM_TOKEN_BACK_REFERENCE:
15872 case PM_CASE_KEYWORD:
15873 parser_lex(parser);
15876 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15880 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
15881 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
15882 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->
unescaped,
false));
15887 if (lex_mode->as.string.interpolation) {
15889 if (match1(parser, PM_TOKEN_STRING_END)) {
15890 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15891 parser_lex(parser);
15893 .
type = PM_TOKEN_STRING_CONTENT,
15894 .start = parser->previous.
start,
15895 .end = parser->previous.
start
15898 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
15902 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15906 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15907 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15908 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15910 return UP(pm_string_node_to_symbol_node(parser, (
pm_string_node_t *) part, &opening, &parser->previous));
15914 if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
15916 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15917 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15918 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
15922 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15923 if (match1(parser, PM_TOKEN_EOF)) {
15924 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15926 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15929 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
15936 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15937 content = parser->current;
15938 unescaped = parser->current_string;
15939 parser_lex(parser);
15950 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15952 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
15953 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
15955 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
15956 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
15958 if (next_state != PM_LEX_STATE_NONE) {
15959 lex_state_set(parser, next_state);
15962 parser_lex(parser);
15963 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15965 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
15969 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.
end, .end = parser->previous.
end };
15970 pm_string_shared_init(&unescaped, content.
start, content.
end);
15973 if (next_state != PM_LEX_STATE_NONE) {
15974 lex_state_set(parser, next_state);
15977 if (match1(parser, PM_TOKEN_EOF)) {
15978 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15980 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15983 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
15991parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
15992 switch (parser->current.type) {
15993 case PM_CASE_OPERATOR:
15994 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
15995 case PM_CASE_KEYWORD:
15996 case PM_TOKEN_CONSTANT:
15997 case PM_TOKEN_IDENTIFIER:
15998 case PM_TOKEN_METHOD_NAME: {
15999 parser_lex(parser);
16001 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16002 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16003 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->
unescaped,
false));
16007 case PM_TOKEN_SYMBOL_BEGIN: {
16009 parser_lex(parser);
16011 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16014 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16015 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16026parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16027 switch (parser->current.type) {
16028 case PM_CASE_OPERATOR:
16029 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16030 case PM_CASE_KEYWORD:
16031 case PM_TOKEN_CONSTANT:
16032 case PM_TOKEN_IDENTIFIER:
16033 case PM_TOKEN_METHOD_NAME: {
16034 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16035 parser_lex(parser);
16037 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16038 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16039 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->previous, &symbol->
unescaped,
false));
16043 case PM_TOKEN_SYMBOL_BEGIN: {
16045 parser_lex(parser);
16047 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16049 case PM_TOKEN_BACK_REFERENCE:
16050 parser_lex(parser);
16051 return UP(pm_back_reference_read_node_create(parser, &parser->previous));
16052 case PM_TOKEN_NUMBERED_REFERENCE:
16053 parser_lex(parser);
16054 return UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16055 case PM_TOKEN_GLOBAL_VARIABLE:
16056 parser_lex(parser);
16057 return UP(pm_global_variable_read_node_create(parser, &parser->previous));
16059 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16060 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16070 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
16072 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
16074 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16075 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth,
false));
16078 pm_scope_t *current_scope = parser->current_scope;
16079 if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16080 if (is_numbered_param) {
16085 uint8_t maximum = (uint8_t) (parser->previous.
start[1] -
'0');
16086 for (uint8_t number = 1; number <= maximum; number++) {
16087 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16090 if (!match1(parser, PM_TOKEN_EQUAL)) {
16091 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
16094 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0,
false));
16095 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16098 }
else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.
start, parser->previous.
end)) {
16099 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16100 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16114 pm_node_flags_t flags = 0;
16116 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.
end[-1] !=
'!') && (parser->previous.
end[-1] !=
'?')) {
16117 pm_node_t *node = parse_variable(parser);
16118 if (node != NULL)
return node;
16119 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16122 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
16123 pm_node_flag_set(UP(node), flags);
16134parse_method_definition_name(
pm_parser_t *parser) {
16135 switch (parser->current.type) {
16136 case PM_CASE_KEYWORD:
16137 case PM_TOKEN_CONSTANT:
16138 case PM_TOKEN_METHOD_NAME:
16139 parser_lex(parser);
16140 return parser->previous;
16141 case PM_TOKEN_IDENTIFIER:
16142 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
16143 parser_lex(parser);
16144 return parser->previous;
16145 case PM_CASE_OPERATOR:
16146 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16147 parser_lex(parser);
16148 return parser->previous;
16150 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
16151 return (
pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end };
16162 if (string->
type != PM_STRING_OWNED) {
16163 size_t length = pm_string_length(
string);
16164 writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(
string), length,
PRISM_ALIGNOF(uint8_t));
16165 pm_string_constant_init(
string, (
const char *) writable, length);
16167 writable = (uint8_t *) string->
source;
16173 size_t dest_length = pm_string_length(
string);
16174 const uint8_t *source_cursor = writable;
16175 const uint8_t *source_end = source_cursor + dest_length;
16180 size_t trimmed_whitespace = 0;
16186 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16187 if (*source_cursor ==
'\t') {
16188 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16189 if (trimmed_whitespace > common_whitespace)
break;
16191 trimmed_whitespace++;
16198 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
16199 string->length = dest_length;
16209 const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->
content_loc);
16210 return pm_memchr(cursor,
'\\', string_node->
content_loc.
length, parser->encoding_changed, parser->encoding) == NULL;
16222 bool dedent_next =
true;
16226 size_t write_index = 0;
16233 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16234 nodes->
nodes[write_index++] = node;
16235 dedent_next =
false;
16241 parse_heredoc_dedent_string(parser->arena, &string_node->
unescaped, common_whitespace);
16244 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16246 nodes->
nodes[write_index++] = node;
16250 dedent_next =
true;
16253 nodes->
size = write_index;
16260parse_strings_empty_content(
const uint8_t *location) {
16261 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16269 assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
16270 bool concating =
false;
16272 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16278 assert(lex_mode->mode == PM_LEX_STRING);
16279 bool lex_interpolation = lex_mode->as.string.interpolation;
16280 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
16283 parser_lex(parser);
16285 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16286 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16290 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
16291 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->previous);
16295 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16299 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
16300 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
start);
16303 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16304 }
else if (!lex_interpolation) {
16310 if (match1(parser, PM_TOKEN_EOF)) {
16311 unescaped = PM_STRING_EMPTY;
16312 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
16314 unescaped = parser->current_string;
16315 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16316 content = parser->previous;
16330 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16332 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16333 pm_node_list_append(parser->arena, &parts, part);
16336 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16337 pm_node_list_append(parser->arena, &parts, part);
16338 parser_lex(parser);
16339 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16341 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16342 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16343 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16344 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16345 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16346 }
else if (match1(parser, PM_TOKEN_EOF)) {
16347 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16348 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16349 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16350 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16352 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.
type));
16353 parser->previous.
start = parser->previous.
end;
16354 parser->previous.
type = 0;
16355 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16357 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16364 parser_lex(parser);
16366 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16367 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16368 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16374 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16375 const uint8_t *location = parser->previous.
end;
16376 if (location > parser->start && location[-1] ==
'\n') location--;
16377 pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
16379 parser->previous.
start = parser->previous.
end;
16380 parser->previous.
type = 0;
16382 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16383 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16384 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16389 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
16390 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16391 pm_node_list_append(parser->arena, &parts, part);
16393 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16394 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16395 pm_node_list_append(parser->arena, &parts, part);
16399 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16400 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16401 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16402 }
else if (match1(parser, PM_TOKEN_EOF)) {
16403 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16404 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16406 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16407 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16417 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16418 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16419 pm_node_list_append(parser->arena, &parts, part);
16423 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16424 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16425 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16426 }
else if (match1(parser, PM_TOKEN_EOF)) {
16427 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16428 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16430 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16431 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16435 if (current == NULL) {
16439 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16450 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16451 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16457 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16458 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16463 pm_interpolated_string_node_append(parser, container, current);
16464 current = UP(container);
16474#define PM_PARSE_PATTERN_SINGLE 0
16475#define PM_PARSE_PATTERN_TOP 1
16476#define PM_PARSE_PATTERN_MULTI 2
16489 if (peek_at(parser, parser->start + location->
start) ==
'_')
return;
16491 if (pm_constant_id_list_includes(captures, capture)) {
16492 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16494 pm_constant_id_list_append(parser->arena, captures, capture);
16505 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16507 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16508 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
16514 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16522 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16523 opening = parser->previous;
16524 accept1(parser, PM_TOKEN_NEWLINE);
16526 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16527 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16528 accept1(parser, PM_TOKEN_NEWLINE);
16529 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16532 closing = parser->previous;
16534 parser_lex(parser);
16535 opening = parser->previous;
16536 accept1(parser, PM_TOKEN_NEWLINE);
16538 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16539 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16540 accept1(parser, PM_TOKEN_NEWLINE);
16541 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16544 closing = parser->previous;
16550 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16557 switch (PM_NODE_TYPE(inner)) {
16558 case PM_ARRAY_PATTERN_NODE: {
16562 PM_NODE_START_SET_NODE(pattern_node, node);
16563 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16566 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16567 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16569 return UP(pattern_node);
16574 case PM_FIND_PATTERN_NODE: {
16578 PM_NODE_START_SET_NODE(pattern_node, node);
16579 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16582 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16583 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16585 return UP(pattern_node);
16590 case PM_HASH_PATTERN_NODE: {
16594 PM_NODE_START_SET_NODE(pattern_node, node);
16595 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16598 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16599 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16601 return UP(pattern_node);
16613 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16614 pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
16615 return UP(pattern_node);
16623 assert(parser->previous.
type == PM_TOKEN_USTAR);
16630 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16631 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
16634 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16635 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
16638 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
16639 name = UP(pm_local_variable_target_node_create(
16641 &TOK2LOC(parser, &parser->previous),
16643 (uint32_t) (depth == -1 ? 0 : depth)
16648 return pm_splat_node_create(parser, &
operator, name);
16656 assert(parser->current.type == PM_TOKEN_USTAR_STAR);
16657 parser_lex(parser);
16662 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16663 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
16666 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16667 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
16670 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16671 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
16674 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
16675 value = UP(pm_local_variable_target_node_create(
16677 &TOK2LOC(parser, &parser->previous),
16679 (uint32_t) (depth == -1 ? 0 : depth)
16683 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16691pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16692 ptrdiff_t length = end - start;
16693 if (length == 0)
return false;
16696 size_t width = char_is_identifier_start(parser, start, end - start);
16697 if (width == 0)
return false;
16700 if (parser->encoding_changed) {
16701 if (parser->encoding->isupper_char(start, length))
return false;
16703 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16708 const uint8_t *cursor = start + width;
16709 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16710 return cursor == end;
16720 const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
16721 const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
16723 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
16726 if (pm_slice_is_valid_local(parser, start, end)) {
16727 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16729 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
16731 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
16732 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
16737 pm_parser_local_add(parser, constant_id, start, end, 0);
16740 parse_pattern_capture(parser, captures, constant_id, value_loc);
16745 (uint32_t) (depth == -1 ? 0 : depth)
16748 return UP(pm_implicit_node_create(parser, UP(target)));
16757 if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, keys, node,
true) != NULL) {
16758 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16771 switch (PM_NODE_TYPE(first_node)) {
16772 case PM_ASSOC_SPLAT_NODE:
16773 case PM_NO_KEYWORDS_PARAMETER_NODE:
16776 case PM_INTERPOLATED_SYMBOL_NODE:
16777 case PM_SYMBOL_NODE: {
16778 if (pm_symbol_node_label_p(parser, first_node)) {
16779 if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
16780 pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16782 parse_pattern_hash_key(parser, &keys, first_node);
16787 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)) {
16788 if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
16789 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
16791 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
16796 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16799 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
16800 pm_node_list_append(parser->arena, &assocs, assoc);
16809 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;
16810 pm_parser_err_node(parser, first_node, diag_id);
16812 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
16813 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
16815 pm_node_list_append(parser->arena, &assocs, assoc);
16821 while (accept1(parser, PM_TOKEN_COMMA)) {
16823 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)) {
16825 if (rest != NULL) {
16826 pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16832 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16833 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16835 if (rest == NULL) {
16838 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16839 pm_node_list_append(parser->arena, &assocs, assoc);
16844 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16845 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16847 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16848 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16849 }
else if (!pm_symbol_node_label_p(parser, key)) {
16850 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16852 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
16853 key = UP(pm_symbol_node_label_create(parser, &parser->previous));
16855 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16857 pm_token_t label = { .
type = PM_TOKEN_LABEL, .start = parser->previous.
end, .end = parser->previous.
end };
16858 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
16861 parse_pattern_hash_key(parser, &keys, key);
16864 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)) {
16865 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16866 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
16868 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
16871 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16874 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
16876 if (rest != NULL) {
16877 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16880 pm_node_list_append(parser->arena, &assocs, assoc);
16887 pm_static_literals_free(&keys);
16896 switch (parser->current.type) {
16897 case PM_TOKEN_IDENTIFIER:
16898 case PM_TOKEN_METHOD_NAME: {
16899 parser_lex(parser);
16900 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
16903 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16904 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
16907 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
16908 return UP(pm_local_variable_target_node_create(
16910 &TOK2LOC(parser, &parser->previous),
16912 (uint32_t) (depth == -1 ? 0 : depth)
16915 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16917 parser_lex(parser);
16919 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16922 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
16927 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16929 accept1(parser, PM_TOKEN_NEWLINE);
16930 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16933 switch (PM_NODE_TYPE(inner)) {
16934 case PM_ARRAY_PATTERN_NODE: {
16937 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
16938 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16940 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16941 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16943 return UP(pattern_node);
16948 case PM_FIND_PATTERN_NODE: {
16951 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
16952 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
16954 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
16955 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
16957 return UP(pattern_node);
16967 pm_array_pattern_node_requireds_append(parser->arena, node, inner);
16970 case PM_TOKEN_BRACE_LEFT: {
16971 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
16972 parser->pattern_matching_newlines =
false;
16976 parser_lex(parser);
16978 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16981 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
16985 switch (parser->current.type) {
16986 case PM_TOKEN_LABEL:
16987 parser_lex(parser);
16988 first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
16990 case PM_TOKEN_USTAR_STAR:
16991 first_node = parse_pattern_keyword_rest(parser, captures);
16993 case PM_TOKEN_STRING_BEGIN:
16994 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));
16997 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
16998 parser_lex(parser);
17000 first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
17005 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17007 accept1(parser, PM_TOKEN_NEWLINE);
17008 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
17011 PM_NODE_START_SET_TOKEN(parser, node, &opening);
17012 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
17018 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17021 case PM_TOKEN_UDOT_DOT:
17022 case PM_TOKEN_UDOT_DOT_DOT: {
17024 parser_lex(parser);
17028 switch (parser->current.type) {
17029 case PM_CASE_PRIMITIVE: {
17030 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));
17031 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17034 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17035 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17036 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17040 case PM_CASE_PRIMITIVE: {
17041 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));
17044 if (pm_symbol_node_label_p(parser, node))
return node;
17047 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17048 pm_parser_err_node(parser, node, diag_id);
17049 return UP(pm_error_recovery_node_create_unexpected(parser, node));
17053 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17059 switch (parser->current.type) {
17060 case PM_CASE_PRIMITIVE: {
17061 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));
17062 return UP(pm_range_node_create(parser, node, &
operator, right));
17065 return UP(pm_range_node_create(parser, node, &
operator, NULL));
17071 case PM_TOKEN_CARET: {
17072 parser_lex(parser);
17077 switch (parser->current.type) {
17078 case PM_TOKEN_IDENTIFIER: {
17079 parser_lex(parser);
17080 pm_node_t *variable = UP(parse_variable(parser));
17082 if (variable == NULL) {
17083 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
17084 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
17087 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17089 case PM_TOKEN_INSTANCE_VARIABLE: {
17090 parser_lex(parser);
17091 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
17093 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17095 case PM_TOKEN_CLASS_VARIABLE: {
17096 parser_lex(parser);
17097 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
17099 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17101 case PM_TOKEN_GLOBAL_VARIABLE: {
17102 parser_lex(parser);
17103 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
17105 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17107 case PM_TOKEN_NUMBERED_REFERENCE: {
17108 parser_lex(parser);
17109 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
17111 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17113 case PM_TOKEN_BACK_REFERENCE: {
17114 parser_lex(parser);
17115 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
17117 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17119 case PM_TOKEN_PARENTHESIS_LEFT: {
17120 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17121 parser->pattern_matching_newlines =
false;
17124 parser_lex(parser);
17126 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));
17127 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17129 accept1(parser, PM_TOKEN_NEWLINE);
17130 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
17131 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->previous));
17136 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17137 pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17138 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17142 case PM_TOKEN_UCOLON_COLON: {
17144 parser_lex(parser);
17146 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17149 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
17151 case PM_TOKEN_CONSTANT: {
17153 parser_lex(parser);
17155 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
17156 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17159 pm_parser_err_current(parser, diag_id);
17160 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17165parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
17166 switch (PM_NODE_TYPE(node)) {
17167 case PM_LOCAL_VARIABLE_TARGET_NODE: {
17169 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17183 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
17193 bool alternation =
false;
17195 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
17196 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
17197 parse_pattern_alternation_error(parser, node);
17200 switch (parser->current.type) {
17201 case PM_TOKEN_IDENTIFIER:
17202 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17203 case PM_TOKEN_BRACE_LEFT:
17204 case PM_TOKEN_CARET:
17205 case PM_TOKEN_CONSTANT:
17206 case PM_TOKEN_UCOLON_COLON:
17207 case PM_TOKEN_UDOT_DOT:
17208 case PM_TOKEN_UDOT_DOT_DOT:
17209 case PM_CASE_PRIMITIVE: {
17210 if (!alternation) {
17211 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17214 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17216 if (captures->
size) parse_pattern_alternation_error(parser, right);
17217 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17222 case PM_TOKEN_PARENTHESIS_LEFT:
17223 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17226 parser_lex(parser);
17228 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17229 accept1(parser, PM_TOKEN_NEWLINE);
17230 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17231 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
17233 if (!alternation) {
17236 if (captures->
size) parse_pattern_alternation_error(parser, right);
17237 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17243 pm_parser_err_current(parser, diag_id);
17244 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17246 if (!alternation) {
17249 if (captures->
size) parse_pattern_alternation_error(parser, right);
17250 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
17260 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17262 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17264 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17267 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17268 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17271 parse_pattern_capture(parser, captures, constant_id, &TOK2LOC(parser, &parser->previous));
17274 &TOK2LOC(parser, &parser->previous),
17276 (uint32_t) (depth == -1 ? 0 : depth)
17279 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17292 bool leading_rest =
false;
17293 bool trailing_rest =
false;
17295 switch (parser->current.type) {
17296 case PM_TOKEN_LABEL: {
17297 parser_lex(parser);
17298 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17299 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17301 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17302 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17307 case PM_TOKEN_USTAR_STAR: {
17308 node = parse_pattern_keyword_rest(parser, captures);
17309 node = UP(parse_pattern_hash(parser, captures, node, (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_STRING_BEGIN: {
17320 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17322 if (pm_symbol_node_label_p(parser, node)) {
17323 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17325 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17326 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17332 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17335 case PM_TOKEN_USTAR: {
17336 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17337 parser_lex(parser);
17338 node = UP(parse_pattern_rest(parser, captures));
17339 leading_rest =
true;
17345 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17351 if (pm_symbol_node_label_p(parser, node)) {
17352 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17355 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17360 pm_node_list_append(parser->arena, &nodes, node);
17363 while (accept1(parser, PM_TOKEN_COMMA)) {
17365 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)) {
17366 node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
17367 pm_node_list_append(parser->arena, &nodes, node);
17368 trailing_rest =
true;
17372 if (accept1(parser, PM_TOKEN_USTAR)) {
17373 node = UP(parse_pattern_rest(parser, captures));
17378 if (trailing_rest) {
17379 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17382 trailing_rest =
true;
17384 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17387 pm_node_list_append(parser->arena, &nodes, node);
17394 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17395 node = UP(pm_find_pattern_node_create(parser, &nodes));
17397 if (nodes.
size == 2) {
17398 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17401 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17403 if (leading_rest && trailing_rest) {
17404 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17409 }
else if (leading_rest) {
17412 node = UP(pm_array_pattern_node_rest_create(parser, node));
17424parse_negative_numeric(
pm_node_t *node) {
17425 switch (PM_NODE_TYPE(node)) {
17426 case PM_INTEGER_NODE: {
17433 case PM_FLOAT_NODE: {
17440 case PM_RATIONAL_NODE: {
17447 case PM_IMAGINARY_NODE:
17453 assert(
false &&
"unreachable");
17464pm_parser_err_prefix(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
17466 case PM_ERR_HASH_KEY: {
17467 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.
type));
17470 case PM_ERR_HASH_VALUE:
17471 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17472 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17475 case PM_ERR_UNARY_RECEIVER: {
17476 const char *human = (parser->current.type == PM_TOKEN_EOF ?
"end-of-input" : pm_token_str(parser->current.type));
17477 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.
start[0]);
17480 case PM_ERR_UNARY_DISALLOWED:
17481 case PM_ERR_EXPECT_ARGUMENT: {
17482 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17486 pm_parser_err_previous(parser, diag_id);
17496#define CONTEXT_NONE 0
17497#define CONTEXT_THROUGH_ENSURE 1
17498#define CONTEXT_THROUGH_ELSE 2
17501 int context = CONTEXT_NONE;
17503 while (context_node != NULL) {
17504 switch (context_node->context) {
17505 case PM_CONTEXT_BEGIN_RESCUE:
17506 case PM_CONTEXT_BLOCK_RESCUE:
17507 case PM_CONTEXT_CLASS_RESCUE:
17508 case PM_CONTEXT_DEF_RESCUE:
17509 case PM_CONTEXT_LAMBDA_RESCUE:
17510 case PM_CONTEXT_MODULE_RESCUE:
17511 case PM_CONTEXT_SCLASS_RESCUE:
17512 case PM_CONTEXT_DEFINED:
17513 case PM_CONTEXT_RESCUE_MODIFIER:
17516 case PM_CONTEXT_CLASS:
17517 case PM_CONTEXT_DEF:
17518 case PM_CONTEXT_DEF_PARAMS:
17519 case PM_CONTEXT_MAIN:
17520 case PM_CONTEXT_MODULE:
17521 case PM_CONTEXT_PREEXE:
17522 case PM_CONTEXT_SCLASS:
17525 if (context == CONTEXT_NONE) {
17526 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17527 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17528 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17529 }
else if (context == CONTEXT_THROUGH_ELSE) {
17530 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17533 case PM_CONTEXT_BEGIN_ELSE:
17534 case PM_CONTEXT_BLOCK_ELSE:
17535 case PM_CONTEXT_CLASS_ELSE:
17536 case PM_CONTEXT_DEF_ELSE:
17537 case PM_CONTEXT_LAMBDA_ELSE:
17538 case PM_CONTEXT_MODULE_ELSE:
17539 case PM_CONTEXT_SCLASS_ELSE:
17542 context = CONTEXT_THROUGH_ELSE;
17544 case PM_CONTEXT_BEGIN_ENSURE:
17545 case PM_CONTEXT_BLOCK_ENSURE:
17546 case PM_CONTEXT_CLASS_ENSURE:
17547 case PM_CONTEXT_DEF_ENSURE:
17548 case PM_CONTEXT_LAMBDA_ENSURE:
17549 case PM_CONTEXT_MODULE_ENSURE:
17550 case PM_CONTEXT_SCLASS_ENSURE:
17553 context = CONTEXT_THROUGH_ENSURE;
17555 case PM_CONTEXT_NONE:
17557 assert(
false &&
"unreachable");
17559 case PM_CONTEXT_BEGIN:
17560 case PM_CONTEXT_BLOCK_BRACES:
17561 case PM_CONTEXT_BLOCK_KEYWORDS:
17562 case PM_CONTEXT_BLOCK_PARAMETERS:
17563 case PM_CONTEXT_CASE_IN:
17564 case PM_CONTEXT_CASE_WHEN:
17565 case PM_CONTEXT_DEFAULT_PARAMS:
17566 case PM_CONTEXT_ELSE:
17567 case PM_CONTEXT_ELSIF:
17568 case PM_CONTEXT_EMBEXPR:
17569 case PM_CONTEXT_FOR_INDEX:
17570 case PM_CONTEXT_FOR:
17571 case PM_CONTEXT_IF:
17572 case PM_CONTEXT_LAMBDA_BRACES:
17573 case PM_CONTEXT_LAMBDA_DO_END:
17574 case PM_CONTEXT_LOOP_PREDICATE:
17575 case PM_CONTEXT_MULTI_TARGET:
17576 case PM_CONTEXT_PARENS:
17577 case PM_CONTEXT_POSTEXE:
17578 case PM_CONTEXT_PREDICATE:
17579 case PM_CONTEXT_TERNARY:
17580 case PM_CONTEXT_UNLESS:
17581 case PM_CONTEXT_UNTIL:
17582 case PM_CONTEXT_WHILE:
17588 context_node = context_node->prev;
17592#undef CONTEXT_ENSURE
17603 while (context_node != NULL) {
17604 switch (context_node->context) {
17605 case PM_CONTEXT_DEF:
17606 case PM_CONTEXT_DEF_PARAMS:
17607 case PM_CONTEXT_DEFINED:
17608 case PM_CONTEXT_DEF_ENSURE:
17609 case PM_CONTEXT_DEF_RESCUE:
17610 case PM_CONTEXT_DEF_ELSE:
17614 case PM_CONTEXT_CLASS:
17615 case PM_CONTEXT_CLASS_ENSURE:
17616 case PM_CONTEXT_CLASS_RESCUE:
17617 case PM_CONTEXT_CLASS_ELSE:
17618 case PM_CONTEXT_MAIN:
17619 case PM_CONTEXT_MODULE:
17620 case PM_CONTEXT_MODULE_ENSURE:
17621 case PM_CONTEXT_MODULE_RESCUE:
17622 case PM_CONTEXT_MODULE_ELSE:
17623 case PM_CONTEXT_SCLASS:
17624 case PM_CONTEXT_SCLASS_RESCUE:
17625 case PM_CONTEXT_SCLASS_ENSURE:
17626 case PM_CONTEXT_SCLASS_ELSE:
17629 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17631 case PM_CONTEXT_NONE:
17633 assert(
false &&
"unreachable");
17635 case PM_CONTEXT_BEGIN:
17636 case PM_CONTEXT_BEGIN_ELSE:
17637 case PM_CONTEXT_BEGIN_ENSURE:
17638 case PM_CONTEXT_BEGIN_RESCUE:
17639 case PM_CONTEXT_BLOCK_BRACES:
17640 case PM_CONTEXT_BLOCK_KEYWORDS:
17641 case PM_CONTEXT_BLOCK_ELSE:
17642 case PM_CONTEXT_BLOCK_ENSURE:
17643 case PM_CONTEXT_BLOCK_PARAMETERS:
17644 case PM_CONTEXT_BLOCK_RESCUE:
17645 case PM_CONTEXT_CASE_IN:
17646 case PM_CONTEXT_CASE_WHEN:
17647 case PM_CONTEXT_DEFAULT_PARAMS:
17648 case PM_CONTEXT_ELSE:
17649 case PM_CONTEXT_ELSIF:
17650 case PM_CONTEXT_EMBEXPR:
17651 case PM_CONTEXT_FOR_INDEX:
17652 case PM_CONTEXT_FOR:
17653 case PM_CONTEXT_IF:
17654 case PM_CONTEXT_LAMBDA_BRACES:
17655 case PM_CONTEXT_LAMBDA_DO_END:
17656 case PM_CONTEXT_LAMBDA_ELSE:
17657 case PM_CONTEXT_LAMBDA_ENSURE:
17658 case PM_CONTEXT_LAMBDA_RESCUE:
17659 case PM_CONTEXT_LOOP_PREDICATE:
17660 case PM_CONTEXT_MULTI_TARGET:
17661 case PM_CONTEXT_PARENS:
17662 case PM_CONTEXT_POSTEXE:
17663 case PM_CONTEXT_PREDICATE:
17664 case PM_CONTEXT_PREEXE:
17665 case PM_CONTEXT_RESCUE_MODIFIER:
17666 case PM_CONTEXT_TERNARY:
17667 case PM_CONTEXT_UNLESS:
17668 case PM_CONTEXT_UNTIL:
17669 case PM_CONTEXT_WHILE:
17675 context_node = context_node->prev;
17687 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
17698pm_command_call_value_p(
const pm_node_t *node) {
17699 switch (PM_NODE_TYPE(node)) {
17700 case PM_CALL_NODE: {
17705 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)) {
17712 return pm_command_call_value_p(call->
receiver);
17717 case PM_SUPER_NODE: {
17721 case PM_YIELD_NODE: {
17725 case PM_RESCUE_MODIFIER_NODE:
17727 case PM_DEF_NODE: {
17731 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
17734 return pm_command_call_value_p(body);
17750pm_block_call_p(
const pm_node_t *node) {
17751 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17756 if (call->
arguments != NULL && call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE)) {
17777parse_case(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
17778 size_t opening_newline_index = token_newline_index(parser);
17779 parser_lex(parser);
17785 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17787 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17788 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17790 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
17792 }
else if (!token_begins_expression_p(parser->current.type)) {
17795 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));
17796 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17799 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
17800 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
17801 parser_lex(parser);
17802 pop_block_exits(parser, previous_block_exits);
17803 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
17804 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->previous));
17811 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
17812 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
17818 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
17819 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
17820 parser_lex(parser);
17823 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
17826 if (accept1(parser, PM_TOKEN_USTAR)) {
17828 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));
17830 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
17831 pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
17833 if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE))
break;
17835 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));
17836 pm_when_node_conditions_append(parser->arena, when_node, condition);
17840 if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE))
break;
17844 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
17845 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
17846 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
17847 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
17850 pm_when_clause_static_literals_add(parser, &literals, condition);
17852 }
while (accept1(parser, PM_TOKEN_COMMA));
17854 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17855 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
17856 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
17859 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
17860 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
17863 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
17864 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
17865 if (statements != NULL) {
17866 pm_when_node_statements_set(when_node, statements);
17870 pm_case_node_condition_append(parser->arena, case_node, UP(when_node));
17876 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
17879 pm_static_literals_free(&literals);
17880 node = UP(case_node);
17882 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
17886 if (predicate == NULL) {
17887 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
17892 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
17893 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
17895 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17896 parser->pattern_matching_newlines =
true;
17898 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
17899 parser->command_start =
false;
17900 parser_lex(parser);
17905 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));
17907 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17912 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
17914 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));
17915 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
17916 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
17918 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));
17919 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
17926 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17927 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
17928 then_keyword = parser->previous;
17931 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
17932 then_keyword = parser->previous;
17938 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
17941 statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
17946 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
17947 pm_case_match_node_condition_append(parser->arena, case_node, condition);
17953 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
17956 node = UP(case_node);
17959 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
17960 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
17964 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
17965 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
17967 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
17970 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
17971 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
17977 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
17978 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
17980 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
17981 pm_case_node_end_keyword_loc_set(parser, (
pm_case_node_t *) node, &parser->previous);
17983 pm_case_match_node_end_keyword_loc_set(parser, (
pm_case_match_node_t *) node, &parser->previous);
17986 pop_block_exits(parser, previous_block_exits);
17995parse_class(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
17996 size_t opening_newline_index = token_newline_index(parser);
17997 parser_lex(parser);
17999 pm_token_t class_keyword = parser->previous;
18000 pm_do_loop_stack_push(parser,
false);
18003 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18005 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18007 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));
18009 pm_parser_scope_push(parser,
true);
18010 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18011 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
18015 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18016 pm_accepts_block_stack_push(parser,
true);
18017 statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18018 pm_accepts_block_stack_pop(parser);
18021 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18022 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18023 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)));
18025 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18028 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18031 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18033 pm_parser_scope_pop(parser);
18034 pm_do_loop_stack_pop(parser);
18036 flush_block_exits(parser, previous_block_exits);
18037 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->previous));
18040 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));
18042 if (name.
type != PM_TOKEN_CONSTANT) {
18043 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18049 if (match1(parser, PM_TOKEN_LESS)) {
18050 inheritance_operator = parser->current;
18051 lex_state_set(parser, PM_LEX_STATE_BEG);
18053 parser->command_start =
true;
18054 parser_lex(parser);
18056 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));
18061 pm_parser_scope_push(parser,
true);
18063 if (inheritance_operator.
start != NULL) {
18064 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18066 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18070 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18071 pm_accepts_block_stack_push(parser,
true);
18072 statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18073 pm_accepts_block_stack_pop(parser);
18076 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18077 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18078 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)));
18080 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18083 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18085 if (context_def_p(parser)) {
18086 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18090 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18092 pm_parser_scope_pop(parser);
18093 pm_do_loop_stack_pop(parser);
18095 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18096 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18097 if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18098 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18102 pop_block_exits(parser, previous_block_exits);
18103 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
18110parse_def(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
18112 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18115 size_t opening_newline_index = token_newline_index(parser);
18123 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18124 parser_lex(parser);
18128 bool valid_name =
true;
18130 switch (parser->current.type) {
18131 case PM_CASE_OPERATOR:
18132 pm_parser_scope_push(parser,
true);
18133 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18134 parser_lex(parser);
18136 name = parser->previous;
18138 case PM_TOKEN_IDENTIFIER: {
18139 parser_lex(parser);
18141 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18142 receiver = parse_variable_call(parser);
18144 pm_parser_scope_push(parser,
true);
18145 lex_state_set(parser, PM_LEX_STATE_FNAME);
18146 parser_lex(parser);
18148 operator = parser->previous;
18149 name = parse_method_definition_name(parser);
18151 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
18152 pm_parser_scope_push(parser,
true);
18154 name = parser->previous;
18159 case PM_TOKEN_INSTANCE_VARIABLE:
18160 case PM_TOKEN_CLASS_VARIABLE:
18161 case PM_TOKEN_GLOBAL_VARIABLE:
18162 valid_name =
false;
18164 case PM_TOKEN_CONSTANT:
18165 case PM_TOKEN_KEYWORD_NIL:
18166 case PM_TOKEN_KEYWORD_SELF:
18167 case PM_TOKEN_KEYWORD_TRUE:
18168 case PM_TOKEN_KEYWORD_FALSE:
18169 case PM_TOKEN_KEYWORD___FILE__:
18170 case PM_TOKEN_KEYWORD___LINE__:
18171 case PM_TOKEN_KEYWORD___ENCODING__: {
18172 pm_parser_scope_push(parser,
true);
18173 parser_lex(parser);
18177 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18178 lex_state_set(parser, PM_LEX_STATE_FNAME);
18179 parser_lex(parser);
18180 operator = parser->previous;
18182 switch (identifier.
type) {
18183 case PM_TOKEN_CONSTANT:
18184 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18186 case PM_TOKEN_INSTANCE_VARIABLE:
18187 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18189 case PM_TOKEN_CLASS_VARIABLE:
18190 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18192 case PM_TOKEN_GLOBAL_VARIABLE:
18193 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18195 case PM_TOKEN_KEYWORD_NIL:
18196 receiver = UP(pm_nil_node_create(parser, &identifier));
18198 case PM_TOKEN_KEYWORD_SELF:
18199 receiver = UP(pm_self_node_create(parser, &identifier));
18201 case PM_TOKEN_KEYWORD_TRUE:
18202 receiver = UP(pm_true_node_create(parser, &identifier));
18204 case PM_TOKEN_KEYWORD_FALSE:
18205 receiver = UP(pm_false_node_create(parser, &identifier));
18207 case PM_TOKEN_KEYWORD___FILE__:
18208 receiver = UP(pm_source_file_node_create(parser, &identifier));
18210 case PM_TOKEN_KEYWORD___LINE__:
18211 receiver = UP(pm_source_line_node_create(parser, &identifier));
18213 case PM_TOKEN_KEYWORD___ENCODING__:
18214 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18220 name = parse_method_definition_name(parser);
18223 PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.
type));
18230 case PM_TOKEN_PARENTHESIS_LEFT: {
18234 context_pop(parser);
18235 parser_lex(parser);
18238 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));
18240 accept1(parser, PM_TOKEN_NEWLINE);
18241 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18244 lex_state_set(parser, PM_LEX_STATE_FNAME);
18245 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18247 operator = parser->previous;
18248 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18252 pm_parser_scope_push(parser,
true);
18253 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18254 name = parse_method_definition_name(parser);
18258 pm_parser_scope_push(parser,
true);
18259 name = parse_method_definition_name(parser);
18267 bool accept_endless_def =
true;
18268 switch (parser->current.type) {
18269 case PM_TOKEN_PARENTHESIS_LEFT: {
18270 parser_lex(parser);
18271 lparen = parser->previous;
18273 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18277 bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
18278 params = parse_parameters(
18280 PM_BINDING_POWER_DEFINED,
18282 allow_trailing_comma,
18286 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18287 (uint16_t) (depth + 1)
18291 lex_state_set(parser, PM_LEX_STATE_BEG);
18292 parser->command_start =
true;
18294 context_pop(parser);
18295 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18296 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
18297 parser->previous.
start = parser->previous.
end;
18298 parser->previous.
type = 0;
18301 rparen = parser->previous;
18304 case PM_CASE_PARAMETER: {
18307 if (parser->current.type == PM_TOKEN_LABEL) {
18308 lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
18311 params = parse_parameters(
18313 PM_BINDING_POWER_DEFINED,
18319 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18320 (uint16_t) (depth + 1)
18325 accept_endless_def =
false;
18327 context_pop(parser);
18332 context_pop(parser);
18341 if (accept1(parser, PM_TOKEN_EQUAL)) {
18342 if (token_is_setter_name(&name)) {
18343 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18345 if (!accept_endless_def) {
18346 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18349 parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
18350 parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
18352 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");
18354 equal = parser->previous;
18356 context_push(parser, PM_CONTEXT_DEF);
18357 pm_do_loop_stack_push(parser,
false);
18358 statements = UP(pm_statements_node_create(parser));
18360 uint8_t allow_flags;
18361 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
18362 allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
18366 allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18375 pm_accepts_block_stack_push(parser,
true);
18376 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));
18377 pm_accepts_block_stack_pop(parser);
18384 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18385 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18386 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18389 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18390 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18392 pm_token_t rescue_keyword = parser->previous;
18396 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));
18397 context_pop(parser);
18399 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18405 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(statement)) {
18406 PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18409 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18410 pm_do_loop_stack_pop(parser);
18411 context_pop(parser);
18413 if (lparen.
start == NULL) {
18414 lex_state_set(parser, PM_LEX_STATE_BEG);
18415 parser->command_start =
true;
18416 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18418 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18421 pm_accepts_block_stack_push(parser,
true);
18422 pm_do_loop_stack_push(parser,
false);
18424 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18425 pm_accepts_block_stack_push(parser,
true);
18426 statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18427 pm_accepts_block_stack_pop(parser);
18430 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18431 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18432 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)));
18434 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18437 pm_accepts_block_stack_pop(parser);
18438 pm_do_loop_stack_pop(parser);
18440 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18441 end_keyword = parser->previous;
18445 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18446 pm_parser_scope_pop(parser);
18451 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
18453 flush_block_exits(parser, previous_block_exits);
18455 return UP(pm_def_node_create(
18464 NTOK2PTR(
operator),
18468 NTOK2PTR(end_keyword)
18476parse_module(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18478 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18480 size_t opening_newline_index = token_newline_index(parser);
18481 parser_lex(parser);
18482 pm_token_t module_keyword = parser->previous;
18484 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));
18489 if (PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18490 pop_block_exits(parser, previous_block_exits);
18493 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
18496 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
18499 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18500 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
18506 name = parser->previous;
18507 if (name.
type != PM_TOKEN_CONSTANT) {
18508 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
18511 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)) {
18512 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18515 pm_parser_scope_push(parser,
true);
18516 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
18519 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18520 pm_accepts_block_stack_push(parser,
true);
18521 statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
18522 pm_accepts_block_stack_pop(parser);
18525 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18526 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18527 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)));
18529 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
18533 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18535 pm_parser_scope_pop(parser);
18536 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
18538 if (context_def_p(parser)) {
18539 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
18542 pop_block_exits(parser, previous_block_exits);
18544 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
18551parse_string_array(
pm_parser_t *parser, uint16_t depth) {
18552 parser_lex(parser);
18560 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
18561 switch (parser->current.type) {
18562 case PM_TOKEN_WORDS_SEP: {
18565 parser->explicit_encoding = NULL;
18567 if (current == NULL) {
18574 pm_array_node_elements_append(parser->arena, array, current);
18578 parser_lex(parser);
18581 case PM_TOKEN_STRING_CONTENT: {
18582 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
18583 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
18584 parser_lex(parser);
18586 if (current == NULL) {
18592 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
18597 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
18603 pm_interpolated_string_node_append(parser, interpolated, current);
18604 pm_interpolated_string_node_append(parser, interpolated,
string);
18605 current = UP(interpolated);
18607 assert(
false &&
"unreachable");
18612 case PM_TOKEN_EMBVAR: {
18613 if (current == NULL) {
18617 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
18618 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
18624 pm_interpolated_string_node_append(parser, interpolated, current);
18625 current = UP(interpolated);
18632 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
18636 case PM_TOKEN_EMBEXPR_BEGIN: {
18637 if (current == NULL) {
18641 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
18642 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
18648 pm_interpolated_string_node_append(parser, interpolated, current);
18649 current = UP(interpolated);
18650 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
18654 assert(
false &&
"unreachable");
18657 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
18662 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
18663 parser_lex(parser);
18670 pm_array_node_elements_append(parser->arena, array, current);
18674 if (match1(parser, PM_TOKEN_EOF)) {
18675 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
18676 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
18678 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
18681 pm_array_node_close_set(parser, array, &closing);
18689parse_symbol_array(
pm_parser_t *parser, uint16_t depth) {
18690 parser_lex(parser);
18698 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
18699 switch (parser->current.type) {
18700 case PM_TOKEN_WORDS_SEP: {
18701 if (current == NULL) {
18708 pm_array_node_elements_append(parser->arena, array, current);
18712 parser_lex(parser);
18715 case PM_TOKEN_STRING_CONTENT: {
18716 if (current == NULL) {
18721 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
18722 parser_lex(parser);
18723 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
18727 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
18728 parser_lex(parser);
18731 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
18738 .
type = PM_TOKEN_STRING_CONTENT,
18743 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
18744 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
18745 parser_lex(parser);
18748 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
18749 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
18751 current = UP(interpolated);
18753 assert(
false &&
"unreachable");
18758 case PM_TOKEN_EMBVAR: {
18759 bool start_location_set =
false;
18760 if (current == NULL) {
18764 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
18765 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
18772 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
18773 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
18774 PM_NODE_START_SET_NODE(interpolated, current);
18775 start_location_set =
true;
18776 current = UP(interpolated);
18783 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
18785 if (!start_location_set) {
18786 PM_NODE_START_SET_NODE(current, part);
18790 case PM_TOKEN_EMBEXPR_BEGIN: {
18791 bool start_location_set =
false;
18792 if (current == NULL) {
18796 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
18797 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
18804 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
18805 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
18806 PM_NODE_START_SET_NODE(interpolated, current);
18807 start_location_set =
true;
18808 current = UP(interpolated);
18809 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
18813 assert(
false &&
"unreachable");
18816 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
18818 if (!start_location_set) {
18819 PM_NODE_START_SET_NODE(current, part);
18824 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
18825 parser_lex(parser);
18832 pm_array_node_elements_append(parser->arena, array, current);
18836 if (match1(parser, PM_TOKEN_EOF)) {
18837 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
18838 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
18840 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
18842 pm_array_node_close_set(parser, array, &closing);
18852parse_parentheses(
pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
18854 pm_node_flags_t paren_flags = 0;
18857 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18859 parser_lex(parser);
18861 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18862 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18863 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18870 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
18871 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18872 pop_block_exits(parser, previous_block_exits);
18873 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
18878 pm_accepts_block_stack_push(parser,
true);
18879 context_push(parser, PM_CONTEXT_PARENS);
18880 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));
18881 context_pop(parser);
18886 bool terminator_found =
false;
18888 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18889 terminator_found =
true;
18890 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18891 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
18892 terminator_found =
true;
18895 if (terminator_found) {
18897 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
18898 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18899 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
18907 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18908 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
18909 lex_state_set(parser, PM_LEX_STATE_ENDARG);
18912 parser_lex(parser);
18913 pm_accepts_block_stack_pop(parser);
18914 pop_block_exits(parser, previous_block_exits);
18916 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
18922 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
18925 multi_target = pm_multi_target_node_create(parser);
18926 pm_multi_target_node_targets_append(parser, multi_target, statement);
18929 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
18930 multi_target->
rparen_loc = TOK2LOC(parser, &parser->previous);
18931 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
18932 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
18935 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
18936 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18937 accept1(parser, PM_TOKEN_NEWLINE);
18939 result = UP(multi_target);
18942 if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
18944 }
else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) {
18947 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
18950 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18951 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
18954 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
18964 pm_statements_node_body_append(parser, statements, statement,
true);
18966 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
18972 context_push(parser, PM_CONTEXT_PARENS);
18973 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
18976 pm_statements_node_body_append(parser, statements, statement,
true);
18980 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
18981 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18986 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));
18987 pm_statements_node_body_append(parser, statements, node,
true);
18991 if (parser->recovering) {
18994 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering =
false;
19000 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE))
break;
19004 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19005 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
19006 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
19007 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19009 }
else if (!match1(parser, PM_TOKEN_EOF)) {
19012 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19016 context_pop(parser);
19017 pm_accepts_block_stack_pop(parser);
19018 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19027 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19029 pm_multi_target_node_targets_append(parser, multi_target, statement);
19031 statement = UP(multi_target);
19035 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
19036 const uint8_t *offset = parser->start + PM_NODE_END(statement);
19037 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
19038 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
19040 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
19043 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
19047 pop_block_exits(parser, previous_block_exits);
19048 pm_void_statements_check(parser, statements,
true);
19049 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19056parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
19057 switch (parser->current.type) {
19058 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
19059 parser_lex(parser);
19061 pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
19062 pm_accepts_block_stack_push(parser,
true);
19063 bool parsed_bare_hash =
false;
19065 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
19066 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
19070 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19076 if (accept1(parser, PM_TOKEN_COMMA)) {
19079 if (accepted_newline) {
19080 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
19085 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
19086 parser->previous.
start = parser->previous.
end;
19087 parser->previous.
type = 0;
19094 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
19098 if (accept1(parser, PM_TOKEN_USTAR)) {
19102 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
19103 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
19105 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));
19108 element = UP(pm_splat_node_create(parser, &
operator, expression));
19109 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
19110 if (parsed_bare_hash) {
19111 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
19114 element = UP(pm_keyword_hash_node_create(parser));
19117 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)) {
19118 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19121 pm_static_literals_free(&hash_keys);
19122 parsed_bare_hash =
true;
19124 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));
19126 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
19127 if (parsed_bare_hash) {
19128 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
19133 pm_hash_key_static_literals_add(parser, &hash_keys, element);
19136 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
19137 operator = parser->previous;
19140 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));
19141 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(
operator), value));
19142 pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
19144 element = UP(hash);
19145 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19146 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19149 pm_static_literals_free(&hash_keys);
19150 parsed_bare_hash =
true;
19154 pm_array_node_elements_append(parser->arena, array, element);
19155 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
19158 accept1(parser, PM_TOKEN_NEWLINE);
19160 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19161 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
19162 parser->previous.
start = parser->previous.
end;
19163 parser->previous.
type = 0;
19166 pm_array_node_close_set(parser, array, &parser->previous);
19167 pm_accepts_block_stack_pop(parser);
19171 case PM_TOKEN_PARENTHESIS_LEFT:
19172 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
19173 return parse_parentheses(parser, binding_power, depth);
19174 case PM_TOKEN_BRACE_LEFT: {
19183 parser->current_hash_keys = NULL;
19185 pm_accepts_block_stack_push(parser,
true);
19186 parser_lex(parser);
19191 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
19192 if (current_hash_keys != NULL) {
19193 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
19196 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
19197 pm_static_literals_free(&hash_keys);
19200 accept1(parser, PM_TOKEN_NEWLINE);
19203 pm_accepts_block_stack_pop(parser);
19204 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
19205 pm_hash_node_closing_loc_set(parser, node, &parser->previous);
19209 case PM_TOKEN_CHARACTER_LITERAL: {
19210 pm_node_t *node = UP(pm_string_node_create_current_string(
19213 .type = PM_TOKEN_STRING_BEGIN,
19214 .start = parser->current.start,
19215 .end = parser->current.start + 1
19218 .type = PM_TOKEN_STRING_CONTENT,
19219 .start = parser->current.start + 1,
19220 .end = parser->current.end
19225 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19229 parser_lex(parser);
19233 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19234 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19239 case PM_TOKEN_CLASS_VARIABLE: {
19240 parser_lex(parser);
19241 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->previous));
19243 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19244 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19249 case PM_TOKEN_CONSTANT: {
19250 parser_lex(parser);
19256 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
19257 ((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))) ||
19258 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19259 match1(parser, PM_TOKEN_BRACE_LEFT)
19262 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19263 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
19266 pm_node_t *node = UP(pm_constant_read_node_create(parser, &parser->previous));
19268 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19271 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19276 case PM_TOKEN_UCOLON_COLON: {
19277 parser_lex(parser);
19280 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19281 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous));
19283 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19284 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19289 case PM_TOKEN_UDOT_DOT:
19290 case PM_TOKEN_UDOT_DOT_DOT: {
19292 parser_lex(parser);
19294 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));
19300 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
19301 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
19304 return UP(pm_range_node_create(parser, NULL, &
operator, right));
19306 case PM_TOKEN_FLOAT:
19307 parser_lex(parser);
19308 return UP(pm_float_node_create(parser, &parser->previous));
19309 case PM_TOKEN_FLOAT_IMAGINARY:
19310 parser_lex(parser);
19311 return UP(pm_float_node_imaginary_create(parser, &parser->previous));
19312 case PM_TOKEN_FLOAT_RATIONAL:
19313 parser_lex(parser);
19314 return UP(pm_float_node_rational_create(parser, &parser->previous));
19315 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
19316 parser_lex(parser);
19317 return UP(pm_float_node_rational_imaginary_create(parser, &parser->previous));
19318 case PM_TOKEN_NUMBERED_REFERENCE: {
19319 parser_lex(parser);
19320 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
19322 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19323 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19328 case PM_TOKEN_GLOBAL_VARIABLE: {
19329 parser_lex(parser);
19330 pm_node_t *node = UP(pm_global_variable_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_BACK_REFERENCE: {
19339 parser_lex(parser);
19340 pm_node_t *node = UP(pm_back_reference_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_IDENTIFIER:
19349 case PM_TOKEN_METHOD_NAME: {
19350 parser_lex(parser);
19352 pm_node_t *node = parse_variable_call(parser);
19354 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
19362 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
19365 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
19374 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
19376 PM_NODE_LENGTH_SET_LOCATION(call, end);
19384 ((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))) ||
19385 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19386 match1(parser, PM_TOKEN_BRACE_LEFT)
19389 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19390 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
19392 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
19396 pm_node_unreference(parser, node);
19402 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
19404 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
19405 pm_node_unreference(parser, node);
19408 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
19416 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19417 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19422 case PM_TOKEN_HEREDOC_START: {
19425 assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
19428 size_t common_whitespace = (size_t) -1;
19429 parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
19431 parser_lex(parser);
19437 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19440 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19441 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
19443 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19444 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19446 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19449 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
19450 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
19457 node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19458 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19463 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19467 cast->
closing_loc = TOK2LOC(parser, &parser->current);
19470 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19472 cast->
base.
type = PM_X_STRING_NODE;
19475 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19476 parse_heredoc_dedent_string(parser->arena, &cast->
unescaped, common_whitespace);
19480 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19486 pm_node_list_append(parser->arena, &parts, part);
19488 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19489 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19490 pm_node_list_append(parser->arena, &parts, part);
19496 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19498 cast->
parts = parts;
19500 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19501 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
19508 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19509 pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
19517 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19519 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19525 parse_heredoc_dedent(parser, nodes, common_whitespace);
19529 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19530 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19535 case PM_TOKEN_INSTANCE_VARIABLE: {
19536 parser_lex(parser);
19537 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
19539 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19540 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19545 case PM_TOKEN_INTEGER: {
19546 pm_node_flags_t base = parser->integer.base;
19547 parser_lex(parser);
19548 return UP(pm_integer_node_create(parser, base, &parser->previous));
19550 case PM_TOKEN_INTEGER_IMAGINARY: {
19551 pm_node_flags_t base = parser->integer.base;
19552 parser_lex(parser);
19553 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
19555 case PM_TOKEN_INTEGER_RATIONAL: {
19556 pm_node_flags_t base = parser->integer.base;
19557 parser_lex(parser);
19558 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
19560 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
19561 pm_node_flags_t base = parser->integer.base;
19562 parser_lex(parser);
19563 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
19565 case PM_TOKEN_KEYWORD___ENCODING__:
19566 parser_lex(parser);
19567 return UP(pm_source_encoding_node_create(parser, &parser->previous));
19568 case PM_TOKEN_KEYWORD___FILE__:
19569 parser_lex(parser);
19570 return UP(pm_source_file_node_create(parser, &parser->previous));
19571 case PM_TOKEN_KEYWORD___LINE__:
19572 parser_lex(parser);
19573 return UP(pm_source_line_node_create(parser, &parser->previous));
19574 case PM_TOKEN_KEYWORD_ALIAS: {
19575 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19576 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
19579 parser_lex(parser);
19582 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
19583 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
19585 switch (PM_NODE_TYPE(new_name)) {
19586 case PM_BACK_REFERENCE_READ_NODE:
19587 case PM_NUMBERED_REFERENCE_READ_NODE:
19588 case PM_GLOBAL_VARIABLE_READ_NODE: {
19589 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)) {
19590 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
19591 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
19593 }
else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
19594 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19595 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19598 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
19600 case PM_SYMBOL_NODE:
19601 case PM_INTERPOLATED_SYMBOL_NODE: {
19602 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)) {
19603 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19604 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19609 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
19612 case PM_TOKEN_KEYWORD_CASE:
19613 return parse_case(parser, flags, depth);
19614 case PM_TOKEN_KEYWORD_BEGIN: {
19615 size_t opening_newline_index = token_newline_index(parser);
19616 parser_lex(parser);
19618 pm_token_t begin_keyword = parser->previous;
19619 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19622 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19625 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19626 pm_accepts_block_stack_push(parser,
true);
19627 begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19628 pm_accepts_block_stack_pop(parser);
19629 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19632 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19633 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19634 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
19636 PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->previous);
19637 pm_begin_node_end_keyword_set(parser, begin_node, &parser->previous);
19638 pop_block_exits(parser, previous_block_exits);
19639 return UP(begin_node);
19641 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
19643 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19645 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19646 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
19649 parser_lex(parser);
19652 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
19654 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
19656 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
19657 pm_context_t context = parser->current_context->context;
19658 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
19659 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
19662 flush_block_exits(parser, previous_block_exits);
19663 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
19665 case PM_TOKEN_KEYWORD_BREAK:
19666 case PM_TOKEN_KEYWORD_NEXT:
19667 case PM_TOKEN_KEYWORD_RETURN: {
19668 parser_lex(parser);
19674 token_begins_expression_p(parser->current.type) ||
19675 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
19677 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
19679 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
19681 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
19684 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
19685 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.
type));
19692 if (arguments.
block != NULL) {
19693 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19694 pm_node_unreference(parser, arguments.
block);
19695 arguments.
block = NULL;
19699 switch (keyword.
type) {
19700 case PM_TOKEN_KEYWORD_BREAK: {
19702 if (!parser->partial_script) parse_block_exit(parser, node);
19705 case PM_TOKEN_KEYWORD_NEXT: {
19707 if (!parser->partial_script) parse_block_exit(parser, node);
19710 case PM_TOKEN_KEYWORD_RETURN: {
19712 parse_return(parser, node);
19716 assert(
false &&
"unreachable");
19717 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19720 case PM_TOKEN_KEYWORD_SUPER: {
19721 parser_lex(parser);
19725 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19730 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
19732 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
19735 return UP(pm_super_node_create(parser, &keyword, &arguments));
19737 case PM_TOKEN_KEYWORD_YIELD: {
19738 parser_lex(parser);
19742 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
19748 if (arguments.
block != NULL) {
19749 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
19750 pm_node_unreference(parser, arguments.
block);
19751 arguments.
block = NULL;
19755 if (!parser->parsing_eval && !parser->partial_script) parse_yield(parser, node);
19759 case PM_TOKEN_KEYWORD_CLASS:
19760 return parse_class(parser, flags, depth);
19761 case PM_TOKEN_KEYWORD_DEF:
19762 return parse_def(parser, binding_power, flags, depth);
19763 case PM_TOKEN_KEYWORD_DEFINED: {
19764 parser_lex(parser);
19771 context_push(parser, PM_CONTEXT_DEFINED);
19772 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19774 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19775 lparen = parser->previous;
19777 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19778 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
19781 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));
19783 if (!parser->recovering) {
19784 accept1(parser, PM_TOKEN_NEWLINE);
19785 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19786 rparen = parser->previous;
19790 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19793 context_pop(parser);
19794 return UP(pm_defined_node_create(
19802 case PM_TOKEN_KEYWORD_END_UPCASE: {
19803 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19804 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19807 parser_lex(parser);
19810 if (context_def_p(parser)) {
19811 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19814 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19816 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
19818 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
19819 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
19821 case PM_TOKEN_KEYWORD_FALSE:
19822 parser_lex(parser);
19823 return UP(pm_false_node_create(parser, &parser->previous));
19824 case PM_TOKEN_KEYWORD_FOR: {
19825 size_t opening_newline_index = token_newline_index(parser);
19826 parser_lex(parser);
19831 context_push(parser, PM_CONTEXT_FOR_INDEX);
19834 if (accept1(parser, PM_TOKEN_USTAR)) {
19835 pm_token_t star_operator = parser->previous;
19838 if (token_begins_expression_p(parser->current.type)) {
19839 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19842 index = UP(pm_splat_node_create(parser, &star_operator, name));
19843 }
else if (token_begins_expression_p(parser->current.type)) {
19844 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19846 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19847 index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
19851 if (match1(parser, PM_TOKEN_COMMA)) {
19852 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19854 index = parse_target(parser, index,
false,
false);
19857 context_pop(parser);
19858 pm_do_loop_stack_push(parser,
true);
19860 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19863 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));
19864 pm_do_loop_stack_pop(parser);
19867 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19868 do_keyword = parser->previous;
19870 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19871 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
19876 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19877 statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19880 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19881 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19883 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous));
19885 case PM_TOKEN_KEYWORD_IF:
19886 if (parser_end_of_line_p(parser)) {
19887 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
19890 size_t opening_newline_index = token_newline_index(parser);
19891 bool if_after_else = parser->previous.
type == PM_TOKEN_KEYWORD_ELSE;
19892 parser_lex(parser);
19894 return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19895 case PM_TOKEN_KEYWORD_UNDEF: {
19896 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19897 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19900 parser_lex(parser);
19901 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
19902 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19904 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
19906 pm_undef_node_append(parser->arena, undef, name);
19908 while (match1(parser, PM_TOKEN_COMMA)) {
19909 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19910 parser_lex(parser);
19911 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19913 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
19917 pm_undef_node_append(parser->arena, undef, name);
19923 case PM_TOKEN_KEYWORD_NOT: {
19924 parser_lex(parser);
19937 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19938 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19939 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19941 accept1(parser, PM_TOKEN_NEWLINE);
19942 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19945 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
19948 accept1(parser, PM_TOKEN_NEWLINE);
19950 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19953 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19954 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
19956 arguments.
opening_loc = TOK2LOC(parser, &lparen);
19957 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));
19959 if (!parser->recovering) {
19960 accept1(parser, PM_TOKEN_NEWLINE);
19961 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19962 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
19966 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));
19969 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19971 case PM_TOKEN_KEYWORD_UNLESS: {
19972 size_t opening_newline_index = token_newline_index(parser);
19973 parser_lex(parser);
19975 return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19977 case PM_TOKEN_KEYWORD_MODULE:
19978 return parse_module(parser, flags, depth);
19979 case PM_TOKEN_KEYWORD_NIL:
19980 parser_lex(parser);
19981 return UP(pm_nil_node_create(parser, &parser->previous));
19982 case PM_TOKEN_KEYWORD_REDO: {
19983 parser_lex(parser);
19985 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
19986 if (!parser->partial_script) parse_block_exit(parser, node);
19990 case PM_TOKEN_KEYWORD_RETRY: {
19991 parser_lex(parser);
19993 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
19994 parse_retry(parser, node);
19998 case PM_TOKEN_KEYWORD_SELF:
19999 parser_lex(parser);
20000 return UP(pm_self_node_create(parser, &parser->previous));
20001 case PM_TOKEN_KEYWORD_TRUE:
20002 parser_lex(parser);
20003 return UP(pm_true_node_create(parser, &parser->previous));
20004 case PM_TOKEN_KEYWORD_UNTIL: {
20005 size_t opening_newline_index = token_newline_index(parser);
20007 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20008 pm_do_loop_stack_push(parser,
true);
20010 parser_lex(parser);
20012 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));
20014 pm_do_loop_stack_pop(parser);
20015 context_pop(parser);
20018 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20019 do_keyword = parser->previous;
20021 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20025 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20026 pm_accepts_block_stack_push(parser,
true);
20027 statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20028 pm_accepts_block_stack_pop(parser);
20029 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20032 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20033 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
20035 return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20037 case PM_TOKEN_KEYWORD_WHILE: {
20038 size_t opening_newline_index = token_newline_index(parser);
20040 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20041 pm_do_loop_stack_push(parser,
true);
20043 parser_lex(parser);
20045 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));
20047 pm_do_loop_stack_pop(parser);
20048 context_pop(parser);
20051 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20052 do_keyword = parser->previous;
20054 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20058 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20059 pm_accepts_block_stack_push(parser,
true);
20060 statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20061 pm_accepts_block_stack_pop(parser);
20062 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20065 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20066 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
20068 return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20070 case PM_TOKEN_PERCENT_LOWER_I: {
20071 parser_lex(parser);
20076 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20077 accept1(parser, PM_TOKEN_WORDS_SEP);
20078 if (match1(parser, PM_TOKEN_STRING_END))
break;
20082 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20084 if (current == NULL) {
20085 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20086 parser_lex(parser);
20087 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20088 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20089 parser_lex(parser);
20091 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20094 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20095 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20096 parser_lex(parser);
20099 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20100 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20103 current = UP(interpolated);
20105 assert(
false &&
"unreachable");
20110 pm_array_node_elements_append(parser->arena, array, current);
20113 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20118 if (match1(parser, PM_TOKEN_EOF)) {
20119 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20120 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20122 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20124 pm_array_node_close_set(parser, array, &closing);
20128 case PM_TOKEN_PERCENT_UPPER_I:
20129 return parse_symbol_array(parser, depth);
20130 case PM_TOKEN_PERCENT_LOWER_W: {
20131 parser_lex(parser);
20136 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20137 accept1(parser, PM_TOKEN_WORDS_SEP);
20138 if (match1(parser, PM_TOKEN_STRING_END))
break;
20142 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20143 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20146 if (current == NULL) {
20148 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20150 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20152 pm_interpolated_string_node_append(parser, interpolated, current);
20153 pm_interpolated_string_node_append(parser, interpolated,
string);
20154 current = UP(interpolated);
20156 assert(
false &&
"unreachable");
20158 parser_lex(parser);
20162 pm_array_node_elements_append(parser->arena, array, current);
20165 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20170 if (match1(parser, PM_TOKEN_EOF)) {
20171 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20172 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20174 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20177 pm_array_node_close_set(parser, array, &closing);
20180 case PM_TOKEN_PERCENT_UPPER_W:
20181 return parse_string_array(parser, depth);
20182 case PM_TOKEN_REGEXP_BEGIN: {
20184 parser_lex(parser);
20186 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20191 .
type = PM_TOKEN_STRING_CONTENT,
20192 .start = parser->previous.
end,
20193 .end = parser->previous.
end
20196 parser_lex(parser);
20199 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20205 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20212 parser_lex(parser);
20217 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20224 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20225 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20233 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20235 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20236 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
20240 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20243 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20248 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20254 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20255 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20256 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20261 if (match1(parser, PM_TOKEN_EOF)) {
20262 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20263 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20265 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20268 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20269 return UP(interpolated);
20271 case PM_TOKEN_BACKTICK:
20272 case PM_TOKEN_PERCENT_LOWER_X: {
20273 parser_lex(parser);
20280 if (match1(parser, PM_TOKEN_STRING_END)) {
20285 .
type = PM_TOKEN_STRING_CONTENT,
20286 .start = parser->previous.
end,
20287 .end = parser->previous.
end
20290 parser_lex(parser);
20291 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
20296 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20303 parser_lex(parser);
20305 if (match1(parser, PM_TOKEN_STRING_END)) {
20306 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
20307 pm_node_flag_set(node, parse_unescaped_encoding(parser));
20308 parser_lex(parser);
20314 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20316 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20317 pm_node_flag_set(part, parse_unescaped_encoding(parser));
20319 pm_interpolated_xstring_node_append(parser->arena, node, part);
20324 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20328 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20329 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20330 pm_interpolated_xstring_node_append(parser->arena, node, part);
20335 if (match1(parser, PM_TOKEN_EOF)) {
20336 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20337 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20339 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20341 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
20345 case PM_TOKEN_USTAR: {
20346 parser_lex(parser);
20351 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20352 pm_parser_err_prefix(parser, diag_id);
20353 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20359 if (token_begins_expression_p(parser->current.type)) {
20360 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20363 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
20365 if (match1(parser, PM_TOKEN_COMMA)) {
20366 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20368 return parse_target_validate(parser, splat,
true);
20371 case PM_TOKEN_BANG: {
20372 if (binding_power > PM_BINDING_POWER_UNARY) {
20373 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20376 parser_lex(parser);
20379 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));
20380 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20382 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20385 case PM_TOKEN_TILDE: {
20386 if (binding_power > PM_BINDING_POWER_UNARY) {
20387 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20389 parser_lex(parser);
20392 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));
20393 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20397 case PM_TOKEN_UMINUS: {
20398 if (binding_power > PM_BINDING_POWER_UNARY) {
20399 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20401 parser_lex(parser);
20404 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));
20405 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20409 case PM_TOKEN_UMINUS_NUM: {
20410 parser_lex(parser);
20413 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));
20415 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20416 pm_token_t exponent_operator = parser->previous;
20417 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));
20418 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20419 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20421 switch (PM_NODE_TYPE(node)) {
20422 case PM_INTEGER_NODE:
20423 case PM_FLOAT_NODE:
20424 case PM_RATIONAL_NODE:
20425 case PM_IMAGINARY_NODE:
20426 parse_negative_numeric(node);
20429 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20436 case PM_TOKEN_MINUS_GREATER: {
20437 int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
20438 parser->lambda_enclosure_nesting = parser->enclosure_nesting;
20440 size_t opening_newline_index = token_newline_index(parser);
20441 pm_accepts_block_stack_push(parser,
true);
20442 parser_lex(parser);
20445 pm_parser_scope_push(parser,
false);
20449 switch (parser->current.type) {
20450 case PM_TOKEN_PARENTHESIS_LEFT: {
20452 parser_lex(parser);
20454 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20455 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20457 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20460 accept1(parser, PM_TOKEN_NEWLINE);
20461 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20463 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
20466 case PM_CASE_PARAMETER: {
20467 pm_accepts_block_stack_push(parser,
false);
20468 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
20469 pm_accepts_block_stack_pop(parser);
20473 block_parameters = NULL;
20480 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
20482 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20483 opening = parser->previous;
20485 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20486 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
20489 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20490 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20492 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20493 opening = parser->previous;
20495 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20496 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
20499 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20500 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20501 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)));
20503 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20506 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20510 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
20511 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->previous);
20513 pm_parser_scope_pop(parser);
20514 pm_accepts_block_stack_pop(parser);
20516 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->previous, parameters, body));
20518 case PM_TOKEN_UPLUS: {
20519 if (binding_power > PM_BINDING_POWER_UNARY) {
20520 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20522 parser_lex(parser);
20525 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));
20526 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20530 case PM_TOKEN_STRING_BEGIN:
20531 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
20532 case PM_TOKEN_SYMBOL_BEGIN: {
20534 parser_lex(parser);
20536 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20539 pm_context_t recoverable = context_recoverable(parser, &parser->current);
20541 if (recoverable != PM_CONTEXT_NONE) {
20542 parser->recovering =
true;
20547 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20548 pm_parser_err_prefix(parser, diag_id);
20554 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
20555 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20559 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
20561 pm_parser_err_prefix(parser, diag_id);
20564 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20579parse_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) {
20580 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));
20586 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(value) || pm_block_call_p(value))) {
20587 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
20588 parser_lex(parser);
20589 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));
20594 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20595 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
20598 parser_lex(parser);
20600 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));
20601 context_pop(parser);
20603 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20615 switch (PM_NODE_TYPE(node)) {
20616 case PM_BEGIN_NODE: {
20621 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20623 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20626 case PM_PARENTHESES_NODE: {
20628 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20631 case PM_STATEMENTS_NODE: {
20636 parse_assignment_value_local(parser, statement);
20658parse_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) {
20659 bool permitted =
true;
20660 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20662 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));
20663 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20665 parse_assignment_value_local(parser, value);
20666 bool single_value =
true;
20671 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))) {
20672 single_value =
false;
20675 pm_array_node_elements_append(parser->arena, array, value);
20678 while (accept1(parser, PM_TOKEN_COMMA)) {
20679 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20681 pm_array_node_elements_append(parser->arena, array, element);
20682 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
20684 parse_assignment_value_local(parser, element);
20692 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))) {
20693 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
20694 parser_lex(parser);
20695 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));
20700 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20701 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
20704 parser_lex(parser);
20706 bool accepts_command_call_inner =
false;
20710 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20713 accepts_command_call_inner =
true;
20717 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));
20718 context_pop(parser);
20720 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20736 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20737 pm_node_unreference(parser, UP(call_node->
arguments));
20741 if (call_node->
block != NULL) {
20742 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20743 pm_node_unreference(parser, UP(call_node->
block));
20744 call_node->
block = NULL;
20749pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20752 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20753 uint8_t value = escape_hexadecimal_digit(*cursor);
20756 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20757 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20761 pm_buffer_append_byte(unescaped, value);
20763 pm_buffer_append_string(unescaped,
"\\x", 2);
20770pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20771 uint8_t value = (uint8_t) (*cursor -
'0');
20774 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20775 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20778 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20779 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20784 pm_buffer_append_byte(unescaped, value);
20790 const uint8_t *start = cursor - 1;
20793 if (cursor >= end) {
20794 pm_buffer_append_string(unescaped,
"\\u", 2);
20798 if (*cursor !=
'{') {
20799 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20800 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
20802 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20803 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20806 return cursor + length;
20811 while (cursor < end && *cursor ==
' ') cursor++;
20813 if (cursor >= end)
break;
20814 if (*cursor ==
'}') {
20819 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20823 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
20825 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20833pm_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) {
20834 const uint8_t *end = source + length;
20835 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20838 if (++cursor >= end) {
20839 pm_buffer_append_byte(unescaped,
'\\');
20845 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20847 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20848 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20851 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
20854 pm_buffer_append_byte(unescaped,
'\\');
20858 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->encoding_changed, parser->encoding);
20859 if (next_cursor == NULL)
break;
20861 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20862 cursor = next_cursor;
20865 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20877 const uint8_t *source = pm_string_source(capture);
20878 size_t length = pm_string_length(capture);
20889 const uint8_t *cursor = pm_memchr(source,
'\\', length, parser->encoding_changed, parser->encoding);
20890 if (PRISM_UNLIKELY(cursor != NULL)) {
20891 pm_named_capture_escape(parser, &unescaped, source, length, cursor, shared ? NULL : &call->receiver->location);
20892 source = (
const uint8_t *) pm_buffer_value(&unescaped);
20893 length = pm_buffer_length(&unescaped);
20896 const uint8_t *start;
20897 const uint8_t *end;
20902 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20903 pm_buffer_cleanup(&unescaped);
20911 end = source + length;
20912 name = pm_parser_constant_id_raw(parser, start, end);
20916 start = parser->start + PM_NODE_START(call->
receiver);
20917 end = parser->start + PM_NODE_END(call->
receiver);
20919 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
20920 memcpy(memory, source, length);
20921 name = pm_parser_constant_id_owned(parser, memory, length);
20926 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20927 pm_constant_id_list_append(parser->arena, names, name);
20930 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20933 if (pm_local_is_keyword((
const char *) source, length)) {
20934 pm_buffer_cleanup(&unescaped);
20940 pm_parser_local_add(parser, name, start, end, 0);
20945 if (callback_data->match == NULL) {
20946 callback_data->match = pm_match_write_node_create(parser, call);
20951 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));
20952 pm_node_list_append(parser->arena, &callback_data->match->
targets, target);
20955 pm_buffer_cleanup(&unescaped);
20971 pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content),
false, extended_mode, parse_regular_expression_named_capture, &callback_data);
20973 if (callback_data.match != NULL) {
20974 return UP(callback_data.match);
20981parse_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) {
20984 switch (token.type) {
20985 case PM_TOKEN_EQUAL: {
20986 switch (PM_NODE_TYPE(node)) {
20987 case PM_CALL_NODE: {
20993 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20994 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
20998 case PM_CASE_WRITABLE: {
21002 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21003 pm_parser_local_add_location(parser, &node->
location, 0);
21006 parser_lex(parser);
21007 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));
21009 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
21010 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21013 return parse_write(parser, node, &token, value);
21015 case PM_SPLAT_NODE: {
21017 pm_multi_target_node_targets_append(parser, multi_target, node);
21019 parser_lex(parser);
21020 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));
21021 return parse_write(parser, UP(multi_target), &token, value);
21023 case PM_SOURCE_ENCODING_NODE:
21024 case PM_FALSE_NODE:
21025 case PM_SOURCE_FILE_NODE:
21026 case PM_SOURCE_LINE_NODE:
21029 case PM_TRUE_NODE: {
21032 parser_lex(parser);
21033 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21034 return parse_unwriteable_write(parser, node, &token, value);
21040 parser_lex(parser);
21041 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21045 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21046 switch (PM_NODE_TYPE(node)) {
21047 case PM_BACK_REFERENCE_READ_NODE:
21048 case PM_NUMBERED_REFERENCE_READ_NODE:
21049 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21051 case PM_GLOBAL_VARIABLE_READ_NODE: {
21052 parser_lex(parser);
21054 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21055 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
21059 case PM_CLASS_VARIABLE_READ_NODE: {
21060 parser_lex(parser);
21062 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21067 case PM_CONSTANT_PATH_NODE: {
21068 parser_lex(parser);
21070 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21073 return parse_shareable_constant_write(parser, write);
21075 case PM_CONSTANT_READ_NODE: {
21076 parser_lex(parser);
21078 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21081 return parse_shareable_constant_write(parser, write);
21083 case PM_INSTANCE_VARIABLE_READ_NODE: {
21084 parser_lex(parser);
21086 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 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21093 parser_lex(parser);
21095 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21096 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
21098 pm_node_unreference(parser, node);
21101 case PM_LOCAL_VARIABLE_READ_NODE: {
21102 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21104 pm_node_unreference(parser, node);
21108 parser_lex(parser);
21110 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21111 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21115 case PM_CALL_NODE: {
21121 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21124 parser_lex(parser);
21126 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21127 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21134 parser_lex(parser);
21139 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21140 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21141 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
21145 if (pm_call_node_writable_p(parser, cast)) {
21146 parse_write_name(parser, &cast->
name);
21148 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21151 parse_call_operator_write(parser, cast, &token);
21152 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21153 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
21155 case PM_MULTI_WRITE_NODE: {
21156 parser_lex(parser);
21157 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21161 parser_lex(parser);
21166 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21170 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21171 switch (PM_NODE_TYPE(node)) {
21172 case PM_BACK_REFERENCE_READ_NODE:
21173 case PM_NUMBERED_REFERENCE_READ_NODE:
21174 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21176 case PM_GLOBAL_VARIABLE_READ_NODE: {
21177 parser_lex(parser);
21179 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21180 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
21184 case PM_CLASS_VARIABLE_READ_NODE: {
21185 parser_lex(parser);
21187 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21192 case PM_CONSTANT_PATH_NODE: {
21193 parser_lex(parser);
21195 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21198 return parse_shareable_constant_write(parser, write);
21200 case PM_CONSTANT_READ_NODE: {
21201 parser_lex(parser);
21203 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21206 return parse_shareable_constant_write(parser, write);
21208 case PM_INSTANCE_VARIABLE_READ_NODE: {
21209 parser_lex(parser);
21211 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 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21218 parser_lex(parser);
21220 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21221 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
21223 pm_node_unreference(parser, node);
21226 case PM_LOCAL_VARIABLE_READ_NODE: {
21227 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21228 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21229 pm_node_unreference(parser, node);
21233 parser_lex(parser);
21235 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21236 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21240 case PM_CALL_NODE: {
21246 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21249 parser_lex(parser);
21251 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21252 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21259 parser_lex(parser);
21264 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21265 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21266 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
21270 if (pm_call_node_writable_p(parser, cast)) {
21271 parse_write_name(parser, &cast->
name);
21273 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21276 parse_call_operator_write(parser, cast, &token);
21277 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21278 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
21280 case PM_MULTI_WRITE_NODE: {
21281 parser_lex(parser);
21282 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21286 parser_lex(parser);
21291 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21295 case PM_TOKEN_AMPERSAND_EQUAL:
21296 case PM_TOKEN_CARET_EQUAL:
21297 case PM_TOKEN_GREATER_GREATER_EQUAL:
21298 case PM_TOKEN_LESS_LESS_EQUAL:
21299 case PM_TOKEN_MINUS_EQUAL:
21300 case PM_TOKEN_PERCENT_EQUAL:
21301 case PM_TOKEN_PIPE_EQUAL:
21302 case PM_TOKEN_PLUS_EQUAL:
21303 case PM_TOKEN_SLASH_EQUAL:
21304 case PM_TOKEN_STAR_EQUAL:
21305 case PM_TOKEN_STAR_STAR_EQUAL: {
21306 switch (PM_NODE_TYPE(node)) {
21307 case PM_BACK_REFERENCE_READ_NODE:
21308 case PM_NUMBERED_REFERENCE_READ_NODE:
21309 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21311 case PM_GLOBAL_VARIABLE_READ_NODE: {
21312 parser_lex(parser);
21314 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21315 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
21319 case PM_CLASS_VARIABLE_READ_NODE: {
21320 parser_lex(parser);
21322 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21327 case PM_CONSTANT_PATH_NODE: {
21328 parser_lex(parser);
21330 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21333 return parse_shareable_constant_write(parser, write);
21335 case PM_CONSTANT_READ_NODE: {
21336 parser_lex(parser);
21338 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21341 return parse_shareable_constant_write(parser, write);
21343 case PM_INSTANCE_VARIABLE_READ_NODE: {
21344 parser_lex(parser);
21346 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 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21353 parser_lex(parser);
21355 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21356 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21358 pm_node_unreference(parser, node);
21361 case PM_LOCAL_VARIABLE_READ_NODE: {
21362 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21363 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21364 pm_node_unreference(parser, node);
21368 parser_lex(parser);
21370 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21371 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21375 case PM_CALL_NODE: {
21376 parser_lex(parser);
21382 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21385 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21386 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21394 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
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 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21400 if (pm_call_node_writable_p(parser, cast)) {
21401 parse_write_name(parser, &cast->
name);
21403 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21406 parse_call_operator_write(parser, cast, &token);
21407 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21408 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21410 case PM_MULTI_WRITE_NODE: {
21411 parser_lex(parser);
21412 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21416 parser_lex(parser);
21421 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
21425 case PM_TOKEN_AMPERSAND_AMPERSAND:
21426 case PM_TOKEN_KEYWORD_AND: {
21427 parser_lex(parser);
21429 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));
21430 return UP(pm_and_node_create(parser, node, &token, right));
21432 case PM_TOKEN_KEYWORD_OR:
21433 case PM_TOKEN_PIPE_PIPE: {
21434 parser_lex(parser);
21436 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));
21437 return UP(pm_or_node_create(parser, node, &token, right));
21439 case PM_TOKEN_EQUAL_TILDE: {
21447 parser_lex(parser);
21448 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));
21451 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21457 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21464 bool interpolated =
false;
21465 size_t total_length = 0;
21469 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21470 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21472 interpolated =
true;
21477 if (!interpolated && total_length > 0) {
21478 void *memory =
xmalloc(total_length);
21479 if (!memory) abort();
21481 uint8_t *cursor = memory;
21484 size_t length = pm_string_length(unescaped);
21486 memcpy(cursor, pm_string_source(unescaped), length);
21491 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21493 result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21494 pm_string_cleanup(&owned);
21496 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21507 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
21509 if (name_data.match != NULL) {
21510 result = UP(name_data.match);
21516 case PM_TOKEN_UAMPERSAND:
21517 case PM_TOKEN_USTAR:
21518 case PM_TOKEN_USTAR_STAR:
21521 case PM_TOKEN_BANG_EQUAL:
21522 case PM_TOKEN_BANG_TILDE:
21523 case PM_TOKEN_EQUAL_EQUAL:
21524 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21525 case PM_TOKEN_LESS_EQUAL_GREATER:
21526 case PM_TOKEN_CARET:
21527 case PM_TOKEN_PIPE:
21528 case PM_TOKEN_AMPERSAND:
21529 case PM_TOKEN_GREATER_GREATER:
21530 case PM_TOKEN_LESS_LESS:
21531 case PM_TOKEN_MINUS:
21532 case PM_TOKEN_PLUS:
21533 case PM_TOKEN_PERCENT:
21534 case PM_TOKEN_SLASH:
21535 case PM_TOKEN_STAR:
21536 case PM_TOKEN_STAR_STAR: {
21537 parser_lex(parser);
21539 switch (PM_NODE_TYPE(node)) {
21540 case PM_RESCUE_MODIFIER_NODE: {
21543 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21547 case PM_AND_NODE: {
21549 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21550 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21556 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21557 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21565 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));
21566 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21568 case PM_TOKEN_GREATER:
21569 case PM_TOKEN_GREATER_EQUAL:
21570 case PM_TOKEN_LESS:
21571 case PM_TOKEN_LESS_EQUAL: {
21572 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21573 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21576 parser_lex(parser);
21577 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));
21578 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21580 case PM_TOKEN_AMPERSAND_DOT:
21581 case PM_TOKEN_DOT: {
21582 parser_lex(parser);
21587 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21588 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21589 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21592 switch (PM_NODE_TYPE(node)) {
21593 case PM_RESCUE_MODIFIER_NODE: {
21596 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21600 case PM_AND_NODE: {
21602 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21603 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21609 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21610 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
21620 switch (parser->current.type) {
21621 case PM_CASE_OPERATOR:
21622 case PM_CASE_KEYWORD:
21623 case PM_TOKEN_CONSTANT:
21624 case PM_TOKEN_IDENTIFIER:
21625 case PM_TOKEN_METHOD_NAME: {
21626 parser_lex(parser);
21627 message = parser->previous;
21631 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
21632 message = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
21636 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21637 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21640 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21643 match1(parser, PM_TOKEN_COMMA)
21645 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21650 case PM_TOKEN_DOT_DOT:
21651 case PM_TOKEN_DOT_DOT_DOT: {
21652 parser_lex(parser);
21655 if (token_begins_expression_p(parser->current.type)) {
21656 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21659 return UP(pm_range_node_create(parser, node, &token, right));
21661 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21663 parser_lex(parser);
21665 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));
21666 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21668 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21670 parser_lex(parser);
21672 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));
21673 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21675 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21676 parser_lex(parser);
21678 pm_statements_node_body_append(parser, statements, node,
true);
21680 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));
21681 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));
21683 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21684 parser_lex(parser);
21686 pm_statements_node_body_append(parser, statements, node,
true);
21688 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));
21689 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));
21691 case PM_TOKEN_QUESTION_MARK: {
21692 context_push(parser, PM_CONTEXT_TERNARY);
21694 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21697 parser_lex(parser);
21699 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));
21701 if (parser->recovering) {
21709 pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
21711 context_pop(parser);
21712 pop_block_exits(parser, previous_block_exits);
21713 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21716 accept1(parser, PM_TOKEN_NEWLINE);
21717 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21720 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));
21722 context_pop(parser);
21723 pop_block_exits(parser, previous_block_exits);
21724 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21726 case PM_TOKEN_COLON_COLON: {
21727 parser_lex(parser);
21730 switch (parser->current.type) {
21731 case PM_TOKEN_CONSTANT: {
21732 parser_lex(parser);
21736 (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21737 ((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)))
21748 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21749 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21752 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21756 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21757 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21762 case PM_CASE_OPERATOR:
21763 case PM_CASE_KEYWORD:
21764 case PM_TOKEN_IDENTIFIER:
21765 case PM_TOKEN_METHOD_NAME: {
21766 parser_lex(parser);
21772 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21773 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21776 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21777 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21782 case PM_TOKEN_PARENTHESIS_LEFT: {
21786 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21788 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21791 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21792 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21796 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21797 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21798 parser_lex(parser);
21799 accept1(parser, PM_TOKEN_NEWLINE);
21801 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));
21802 context_pop(parser);
21804 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21806 case PM_TOKEN_BRACKET_LEFT: {
21807 parser_lex(parser);
21810 arguments.
opening_loc = TOK2LOC(parser, &parser->previous);
21812 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21813 pm_accepts_block_stack_push(parser,
true);
21814 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
21815 pm_accepts_block_stack_pop(parser);
21816 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21819 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
21823 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21824 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21825 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21832 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21833 block = parse_block(parser, (uint16_t) (depth + 1));
21834 pm_arguments_validate_block(parser, &arguments, block);
21835 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21836 block = parse_block(parser, (uint16_t) (depth + 1));
21839 if (block != NULL) {
21840 if (arguments.
block != NULL) {
21841 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21843 arguments.
arguments = pm_arguments_node_create(parser);
21845 pm_arguments_node_arguments_append(parser->arena, arguments.
arguments, arguments.
block);
21848 arguments.
block = UP(block);
21851 return UP(pm_call_node_aref_create(parser, node, &arguments));
21853 case PM_TOKEN_KEYWORD_IN: {
21854 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
21855 parser->pattern_matching_newlines =
true;
21858 parser->command_start =
false;
21859 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21860 parser_lex(parser);
21863 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));
21865 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
21867 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21869 case PM_TOKEN_EQUAL_GREATER: {
21870 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
21871 parser->pattern_matching_newlines =
true;
21874 parser->command_start =
false;
21875 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21876 parser_lex(parser);
21879 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));
21881 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
21883 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21886 assert(
false &&
"unreachable");
21891#undef PM_PARSE_PATTERN_SINGLE
21892#undef PM_PARSE_PATTERN_TOP
21893#undef PM_PARSE_PATTERN_MULTI
21909 pm_binding_power_t left = pm_binding_powers[parser->current.type].
left;
21911 switch (PM_NODE_TYPE(node)) {
21912 case PM_MULTI_WRITE_NODE:
21913 case PM_RETURN_NODE:
21914 case PM_BREAK_NODE:
21916 return left > PM_BINDING_POWER_MODIFIER;
21917 case PM_CLASS_VARIABLE_WRITE_NODE:
21918 case PM_CONSTANT_PATH_WRITE_NODE:
21919 case PM_CONSTANT_WRITE_NODE:
21920 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21921 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21922 case PM_LOCAL_VARIABLE_WRITE_NODE:
21923 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
21924 case PM_CALL_NODE: {
21927 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
21928 return left > PM_BINDING_POWER_MODIFIER;
21934 if (pm_command_call_value_p(node)) {
21935 return left > PM_BINDING_POWER_COMPOSITION;
21941 if (pm_block_call_p(node)) {
21942 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL;
21947 case PM_SUPER_NODE:
21948 case PM_YIELD_NODE:
21951 if (pm_command_call_value_p(node)) {
21952 return left > PM_BINDING_POWER_COMPOSITION;
21959 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(node);
21960 case PM_RESCUE_MODIFIER_NODE:
21964 if (left > PM_BINDING_POWER_MODIFIER) {
21967 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
21984parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
21985 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
21986 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21987 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
21990 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
21995 switch (PM_NODE_TYPE(node)) {
21996 case PM_ERROR_RECOVERY_NODE:
21998 case PM_PRE_EXECUTION_NODE:
22000 case PM_POST_EXECUTION_NODE:
22001 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22002 case PM_ALIAS_METHOD_NODE:
22003 case PM_UNDEF_NODE:
22004 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
22009 case PM_SUPER_NODE:
22010 case PM_YIELD_NODE:
22012 if (parse_expression_terminator(parser, node)) {
22016 case PM_SYMBOL_NODE:
22017 if (pm_symbol_node_label_p(parser, node)) {
22028 pm_token_type_t current_token_type;
22031 current_token_type = parser->current.type,
22032 current_binding_powers = pm_binding_powers[current_token_type],
22033 binding_power <= current_binding_powers.
left &&
22034 current_binding_powers.
binary
22036 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
22037 if (parse_expression_terminator(parser, node))
return node;
22041 if (current_binding_powers.
nonassoc) {
22044 if (match1(parser, current_token_type)) {
22045 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));
22056 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22057 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22058 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));
22062 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->current.type].left) {
22065 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->current.type].left) {
22070 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
22079 switch (node->
type) {
22080 case PM_CALL_NODE: {
22094 cast->
block == NULL &&
22104 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22107 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22112 case PM_CONSTANT_PATH_NODE:
22115 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22120 if (context_terminator(parser->current_context->context, &parser->current)) {
22123 !next_binding_powers.
binary ||
22124 binding_power > next_binding_powers.
left ||
22125 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
22141 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22142 if (statements == NULL) {
22143 statements = pm_statements_node_create(parser);
22147 pm_arguments_node_arguments_append(
22150 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
22153 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
22156 pm_parser_constant_id_constant(parser,
"print", 5)
22160 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22161 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22162 if (statements == NULL) {
22163 statements = pm_statements_node_create(parser);
22167 pm_arguments_node_arguments_append(
22170 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
22173 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22174 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
22178 pm_parser_constant_id_constant(parser,
"$F", 2),
22182 pm_statements_node_body_prepend(parser->arena, statements, UP(write));
22186 pm_arguments_node_arguments_append(
22189 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
22192 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22194 pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
22196 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
22198 UP(pm_true_node_synthesized_create(parser))
22201 pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
22202 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22206 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
22208 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
22212 statements = wrapped_statements;
22226 if (parser->current_scope == NULL) {
22227 pm_parser_scope_push(parser,
true);
22231 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22233 parser_lex(parser);
22236 if (statements != NULL && !parser->parsing_eval) {
22240 assert(statements->
body.
size > 0);
22241 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22245 pm_locals_order(parser, &parser->current_scope->locals, &locals,
true);
22246 pm_parser_scope_pop(parser);
22251 statements = wrap_statements(parser, statements);
22253 flush_block_exits(parser, previous_block_exits);
22259 if (statements == NULL) {
22260 statements = pm_statements_node_create(parser);
22264 return UP(pm_program_node_create(parser, &locals, statements));
22281pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22282 size_t little_length = strlen(little);
22284 for (
const char *max = big + big_length - little_length; big <= max; big++) {
22285 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22292#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22300pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22301 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22302 pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
22313 const char *switches = pm_strnstr(engine,
" -", length);
22314 if (switches == NULL)
return;
22317 options->shebang_callback(
22319 (
const uint8_t *) (switches + 1),
22320 length - ((
size_t) (switches - engine)) - 1,
22321 options->shebang_callback_data
22324 size_t encoding_length;
22325 if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
22326 const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
22327 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22330 parser->command_line = next_options.command_line;
22331 parser->frozen_string_literal = next_options.frozen_string_literal;
22339 assert(arena != NULL);
22340 assert(source != NULL);
22344 .metadata_arena = { 0 },
22346 .lex_state = PM_LEX_STATE_BEG,
22347 .enclosure_nesting = 0,
22348 .lambda_enclosure_nesting = -1,
22349 .brace_nesting = 0,
22350 .do_loop_stack = 0,
22351 .accepts_block_stack = 0,
22354 .stack = {{ .mode = PM_LEX_DEFAULT }},
22355 .current = &parser->lex_modes.stack[0],
22358 .end = source + size,
22359 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22360 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22361 .next_start = NULL,
22362 .heredoc_end = NULL,
22364 .comment_list = { 0 },
22365 .magic_comment_list = { 0 },
22366 .warning_list = { 0 },
22367 .error_list = { 0 },
22368 .current_scope = NULL,
22369 .current_context = NULL,
22370 .encoding = PM_ENCODING_UTF_8_ENTRY,
22371 .encoding_changed_callback = NULL,
22372 .encoding_comment_start = source,
22373 .lex_callback = { 0 },
22375 .constant_pool = { 0 },
22376 .line_offsets = { 0 },
22378 .current_string = PM_STRING_EMPTY,
22380 .explicit_encoding = NULL,
22382 .parsing_eval =
false,
22383 .partial_script =
false,
22384 .command_start =
true,
22385 .recovering =
false,
22386 .continuable =
true,
22387 .encoding_locked =
false,
22388 .encoding_changed =
false,
22389 .pattern_matching_newlines =
false,
22390 .in_keyword_arg =
false,
22391 .current_block_exits = NULL,
22392 .semantic_token_seen =
false,
22394 .warn_mismatched_indentation =
true
22402 if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
22403 if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
22410 uint32_t constant_size = ((uint32_t) size) / 120;
22411 pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
22416 size_t newline_size = size / 22;
22417 pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
22420 if (options != NULL) {
22422 parser->filepath = options->filepath;
22425 parser->start_line = options->line;
22428 size_t encoding_length = pm_string_length(&options->encoding);
22429 if (encoding_length > 0) {
22430 const uint8_t *encoding_source = pm_string_source(&options->encoding);
22431 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22435 parser->encoding_locked = options->encoding_locked;
22438 parser->frozen_string_literal = options->frozen_string_literal;
22441 parser->command_line = options->command_line;
22444 parser->version = options->version;
22447 parser->partial_script = options->partial_script;
22450 parser->parsing_eval = options->scopes_count > 0;
22451 if (parser->parsing_eval) parser->warn_mismatched_indentation =
false;
22453 for (
size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
22455 pm_parser_scope_push(parser, scope_index == 0);
22459 parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
22461 for (
size_t local_index = 0; local_index < scope->locals_count; local_index++) {
22462 const pm_string_t *local = pm_options_scope_local(scope, local_index);
22464 const uint8_t *source = pm_string_source(local);
22465 size_t length = pm_string_length(local);
22467 uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
22468 memcpy(allocated, source, length);
22469 pm_parser_local_add_owned(parser, allocated, length);
22476 if (parser->version == PM_OPTIONS_VERSION_UNSET) {
22477 parser->version = PM_OPTIONS_VERSION_LATEST;
22480 pm_accepts_block_stack_push(parser,
true);
22483 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22484 parser->current.end += 3;
22485 parser->encoding_comment_start += 3;
22487 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
22488 parser->encoding = PM_ENCODING_UTF_8_ENTRY;
22489 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
22496 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22513 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
22514 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
22516 if (length > 2 && parser->current.end[0] ==
'#' && parser->current.end[1] ==
'!') {
22517 const char *engine;
22519 if ((engine = pm_strnstr((
const char *) parser->start,
"ruby", length)) != NULL) {
22520 if (newline != NULL) {
22521 parser->encoding_comment_start = newline + 1;
22523 if (options == NULL || options->main_script) {
22524 pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
22528 if (options != NULL && options->main_script && options->shebang_callback != NULL) {
22529 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->start)));
22532 search_shebang =
false;
22533 }
else if (options != NULL && options->main_script && !parser->parsing_eval) {
22534 search_shebang =
true;
22540 if (search_shebang) {
22543 bool found_shebang =
false;
22547 const uint8_t *cursor = parser->start;
22551 const uint8_t *newline = next_newline(cursor, parser->end - cursor);
22553 while (newline != NULL) {
22554 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
22556 cursor = newline + 1;
22557 newline = next_newline(cursor, parser->end - cursor);
22559 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
22560 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22561 const char *engine;
22562 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22563 found_shebang =
true;
22565 if (newline != NULL) {
22566 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22567 parser->encoding_comment_start = newline + 1;
22570 if (options != NULL && options->shebang_callback != NULL) {
22571 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22579 if (found_shebang) {
22580 parser->previous = (
pm_token_t) { .
type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22581 parser->current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22583 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
22584 pm_line_offset_list_clear(&parser->line_offsets);
22591 parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
22604 if (parser == NULL) abort();
22606 pm_parser_init(arena, parser, source, size, options);
22615 pm_string_cleanup(&parser->filepath);
22616 pm_arena_cleanup(&parser->metadata_arena);
22618 while (parser->current_scope != NULL) {
22623 pm_parser_scope_pop(parser);
22626 while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
22627 lex_mode_pop(parser);
22636 pm_parser_cleanup(parser);
22646pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
22648 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
22649 case PM_ERR_BEGIN_UPCASE_BRACE:
22650 case PM_ERR_CLASS_VARIABLE_BARE:
22651 case PM_ERR_END_UPCASE_BRACE:
22652 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
22653 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
22654 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
22655 case PM_ERR_EXPRESSION_NOT_WRITABLE:
22656 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
22657 case PM_ERR_FLOAT_PARSE:
22658 case PM_ERR_GLOBAL_VARIABLE_BARE:
22659 case PM_ERR_HASH_KEY:
22660 case PM_ERR_HEREDOC_IDENTIFIER:
22661 case PM_ERR_INSTANCE_VARIABLE_BARE:
22662 case PM_ERR_INVALID_BLOCK_EXIT:
22663 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
22664 case PM_ERR_INVALID_FLOAT_EXPONENT:
22665 case PM_ERR_INVALID_NUMBER_BINARY:
22666 case PM_ERR_INVALID_NUMBER_DECIMAL:
22667 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
22668 case PM_ERR_INVALID_NUMBER_OCTAL:
22669 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
22670 case PM_ERR_NO_LOCAL_VARIABLE:
22671 case PM_ERR_PARAMETER_ORDER:
22672 case PM_ERR_STATEMENT_UNDEF:
22673 case PM_ERR_VOID_EXPRESSION:
22716 if (parser->error_list.size == 0) {
22717 parser->continuable =
false;
22721 if (!parser->continuable)
return;
22723 size_t source_length = (size_t) (parser->end - parser->start);
22726 bool has_non_stray_error =
false;
22728 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)) {
22729 has_non_stray_error =
true;
22737 size_t non_stray_min_start = SIZE_MAX;
22740 size_t error_start = (size_t) error->location.start;
22741 size_t error_end = error_start + (size_t) error->location.length;
22742 bool at_eof = error_end >= source_length;
22745 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
22746 parser->continuable =
false;
22751 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
22752 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
22753 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
22762 if (non_stray_min_start < error_start)
continue;
22769 if (at_eof && error_start > 0) {
22771 if (error->location.length == 1) {
22772 const uint8_t *
byte = parser->start + error_start;
22773 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
22774 parser->continuable =
false;
22784 if (has_non_stray_error)
continue;
22791 if (error->location.length == 1) {
22792 const uint8_t *
byte = parser->start + error_start;
22793 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
22797 parser->continuable =
false;
22807 pm_node_t *node = parse_program(parser);
22808 pm_parse_continuable(parser);
22820 bool eof = pm_source_stream_read(source);
22825 while (!eof && tmp->error_list.size > 0) {
22826 eof = pm_source_stream_read(source);
22829 pm_arena_cleanup(arena);
22831 tmp =
pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
22839#undef PM_CASE_KEYWORD
22840#undef PM_CASE_OPERATOR
22841#undef PM_CASE_WRITABLE
22842#undef PM_STRING_EMPTY
22847#ifndef PRISM_EXCLUDE_SERIALIZATION
22851 pm_buffer_append_string(buffer,
"PRISM", 5);
22855 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22863 pm_serialize_header(buffer);
22864 pm_serialize_content(parser, node, buffer);
22865 pm_buffer_append_byte(buffer,
'\0');
22873pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22875 pm_options_read(&options, data);
22879 pm_parser_init(&arena, &parser, source, size, &options);
22883 pm_serialize_header(buffer);
22884 pm_serialize_content(&parser, node, buffer);
22885 pm_buffer_append_byte(buffer,
'\0');
22887 pm_parser_cleanup(&parser);
22888 pm_arena_cleanup(&arena);
22889 pm_options_cleanup(&options);
22901 pm_options_read(&options, data);
22903 pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
22904 pm_serialize_header(buffer);
22905 pm_serialize_content(parser, node, buffer);
22906 pm_buffer_append_byte(buffer,
'\0');
22909 pm_arena_cleanup(&arena);
22910 pm_options_cleanup(&options);
22917pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22919 pm_options_read(&options, data);
22923 pm_parser_init(&arena, &parser, source, size, &options);
22926 pm_serialize_header(buffer);
22927 pm_serialize_encoding(parser.encoding, buffer);
22928 pm_buffer_append_varsint(buffer, parser.start_line);
22929 pm_serialize_comment_list(&parser.comment_list, buffer);
22931 pm_parser_cleanup(&parser);
22932 pm_arena_cleanup(&arena);
22933 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.