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_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
117#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
118#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
119#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
121#define PM_NODE_START(node_) (UP(node_)->location.start)
122#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
123#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
124#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
126#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
127#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
129#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
130#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
131#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
132#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
133#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
143pm_location_init(uint32_t start, uint32_t length) {
148#define PM_LOCATION_INIT(start_, length_) pm_location_init((start_), (length_))
149#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
150#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
151#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
153#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
154#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
155#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
156#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
158#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
159#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
160#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
171lex_mode_incrementor(
const uint8_t start) {
188lex_mode_terminator(
const uint8_t start) {
210 lex_mode.prev = parser->lex_modes.current;
211 parser->lex_modes.index++;
213 if (parser->lex_modes.index > PM_LEX_STACK_SIZE - 1) {
215 if (PRISM_UNLIKELY(parser->lex_modes.current == NULL)) {
216 fprintf(stderr,
"prism: out of memory; aborting\n");
220 *parser->lex_modes.current = lex_mode;
222 parser->lex_modes.stack[parser->lex_modes.index] = lex_mode;
223 parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
231lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
232 uint8_t incrementor = lex_mode_incrementor(delimiter);
233 uint8_t terminator = lex_mode_terminator(delimiter);
239 .interpolation = interpolation,
242 .incrementor = incrementor,
243 .terminator = terminator
249 uint8_t *breakpoints = lex_mode.as.list.breakpoints;
250 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
251 memcpy(breakpoints,
"\\ \t\f\r\v\n",
sizeof(
"\\ \t\f\r\v\n") - 1);
256 if (terminator !=
'\0') {
257 breakpoints[index++] = terminator;
263 breakpoints[index++] =
'#';
267 if (incrementor !=
'\0') {
268 breakpoints[index++] = incrementor;
271 parser->explicit_encoding = NULL;
272 lex_mode_push(parser, lex_mode);
282 lex_mode_push_list(parser,
false,
'\0');
289lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
291 .mode = PM_LEX_REGEXP,
294 .incrementor = incrementor,
295 .terminator = terminator
302 uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
303 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
304 memcpy(breakpoints,
"\r\n\\#",
sizeof(
"\r\n\\#") - 1);
308 if (terminator !=
'\0') {
309 breakpoints[index++] = terminator;
313 if (incrementor !=
'\0') {
314 breakpoints[index++] = incrementor;
317 parser->explicit_encoding = NULL;
318 lex_mode_push(parser, lex_mode);
325lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
327 .mode = PM_LEX_STRING,
330 .interpolation = interpolation,
331 .label_allowed = label_allowed,
332 .incrementor = incrementor,
333 .terminator = terminator
339 uint8_t *breakpoints = lex_mode.as.string.breakpoints;
340 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
341 memcpy(breakpoints,
"\r\n\\",
sizeof(
"\r\n\\") - 1);
346 if (terminator !=
'\0') {
347 breakpoints[index++] = terminator;
353 breakpoints[index++] =
'#';
358 if (incrementor !=
'\0') {
359 breakpoints[index++] = incrementor;
362 parser->explicit_encoding = NULL;
363 lex_mode_push(parser, lex_mode);
373 lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
383 if (parser->lex_modes.index == 0) {
384 parser->lex_modes.current->mode = PM_LEX_DEFAULT;
385 }
else if (parser->lex_modes.index < PM_LEX_STACK_SIZE) {
386 parser->lex_modes.index--;
387 parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
389 parser->lex_modes.index--;
391 xfree_sized(parser->lex_modes.current,
sizeof(
pm_lex_mode_t));
392 parser->lex_modes.current = prev;
400lex_state_p(
const pm_parser_t *parser, pm_lex_state_t state) {
401 return parser->lex_state & state;
405 PM_IGNORED_NEWLINE_NONE = 0,
406 PM_IGNORED_NEWLINE_ALL,
407 PM_IGNORED_NEWLINE_PATTERN
408} pm_ignored_newline_type_t;
412 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);
415 return PM_IGNORED_NEWLINE_ALL;
416 }
else if ((parser->lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
417 return PM_IGNORED_NEWLINE_PATTERN;
419 return PM_IGNORED_NEWLINE_NONE;
425 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));
430 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
434lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
435 if (parser->current.end >= parser->end) {
438 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
443 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
451 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
459lex_state_set(
pm_parser_t *parser, pm_lex_state_t state) {
460 parser->lex_state = state;
463#ifndef PM_DEBUG_LOGGING
468#define PM_DEBUG_LOGGING 0
474 fprintf(stderr,
"STATE: ");
477 if (parser->lex_state == PM_LEX_STATE_NONE) {
478 fprintf(stderr,
"NONE\n");
482#define CHECK_STATE(state) \
483 if (parser->lex_state & state) { \
484 if (!first) fprintf(stderr, "|"); \
485 fprintf(stderr, "%s", #state); \
489 CHECK_STATE(PM_LEX_STATE_BEG)
490 CHECK_STATE(PM_LEX_STATE_END)
491 CHECK_STATE(PM_LEX_STATE_ENDARG)
492 CHECK_STATE(PM_LEX_STATE_ENDFN)
493 CHECK_STATE(PM_LEX_STATE_ARG)
494 CHECK_STATE(PM_LEX_STATE_CMDARG)
495 CHECK_STATE(PM_LEX_STATE_MID)
496 CHECK_STATE(PM_LEX_STATE_FNAME)
497 CHECK_STATE(PM_LEX_STATE_DOT)
498 CHECK_STATE(PM_LEX_STATE_CLASS)
499 CHECK_STATE(PM_LEX_STATE_LABEL)
500 CHECK_STATE(PM_LEX_STATE_LABELED)
501 CHECK_STATE(PM_LEX_STATE_FITEM)
505 fprintf(stderr,
"\n");
509debug_lex_state_set(
pm_parser_t *parser, pm_lex_state_t state,
char const * caller_name,
int line_number) {
510 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
512 lex_state_set(parser, state);
513 fprintf(stderr,
"Now: ");
515 fprintf(stderr,
"\n");
518#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
526#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
529#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
532#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
535#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
538#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
541#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
544#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
554pm_parser_err(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
555 pm_diagnostic_list_append(&parser->metadata_arena, &parser->error_list, start, length, diag_id);
564 pm_parser_err(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
572pm_parser_err_current(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
573 pm_parser_err_token(parser, &parser->current, diag_id);
581pm_parser_err_previous(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
582 pm_parser_err_token(parser, &parser->previous, diag_id);
591 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
597#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
598 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
604#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
605 PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
611#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
612 PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
618#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
619 PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id, __VA_ARGS__)
625#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
626 PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
632pm_parser_warn(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
633 pm_diagnostic_list_append(&parser->metadata_arena, &parser->warning_list, start, length, diag_id);
642 pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
651 pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
658#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
659 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->warning_list, start_, length_, diag_id_, __VA_ARGS__)
665#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
666 PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id_, __VA_ARGS__)
672#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
673 PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
679#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
680 PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
688pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
689 PM_PARSER_ERR_FORMAT(
691 U32(ident_start - parser->start),
695 (
const char *) ident_start
706#define PM_LOCALS_REUSE_CAPACITY 16
712pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
717 parser->free_scopes = scope->previous;
723 if (scope->locals.capacity > 0 && scope->locals.capacity <= PM_LOCALS_REUSE_CAPACITY) {
724 locals.capacity = scope->locals.capacity;
725 locals.locals = scope->locals.locals;
726 memset(locals.locals, 0, locals.capacity *
sizeof(
pm_local_t));
733 .previous = parser->current_scope,
735 .parameters = PM_SCOPE_PARAMETERS_NONE,
736 .implicit_parameters = { 0 },
737 .shareable_constant = parser->current_scope == NULL ? PM_SCOPE_SHAREABLE_CONSTANT_NONE : parser->current_scope->shareable_constant,
741 parser->current_scope = scope;
753 if (scope->previous == NULL)
return true;
754 if (scope->closed)
return false;
755 }
while ((scope = scope->previous) != NULL);
757 assert(
false &&
"unreachable");
765pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
768 while (depth-- > 0) {
769 assert(scope != NULL);
770 scope = scope->previous;
777 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
778 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
779 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
780} pm_scope_forwarding_param_check_result_t;
782static pm_scope_forwarding_param_check_result_t
783pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
785 bool conflict =
false;
787 while (scope != NULL) {
788 if (scope->parameters & mask) {
791 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
793 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
800 if (scope->closed)
break;
801 scope = scope->previous;
804 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
809 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
810 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
813 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
814 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
816 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
817 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
824 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
825 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
828 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
829 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
831 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
832 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
839 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
840 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
843 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
848 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
849 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
856 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
857 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
860 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
861 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
863 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
864 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
873pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
874 return parser->current_scope->shareable_constant;
882pm_parser_scope_shareable_constant_set(
pm_parser_t *parser, pm_shareable_constant_value_t shareable_constant) {
886 scope->shareable_constant = shareable_constant;
887 }
while (!scope->closed && (scope = scope->previous) != NULL);
897#define PM_LOCALS_HASH_THRESHOLD 5
905 uint32_t next_capacity = locals->capacity == 0 ? 4 : (locals->capacity * 2);
906 assert(next_capacity > locals->capacity);
910 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
911 if (locals->size > 0) {
912 memcpy(next_locals, locals->locals, locals->size *
sizeof(
pm_local_t));
917 bool hash_needed = (locals->capacity <= PM_LOCALS_HASH_THRESHOLD);
918 uint32_t mask = next_capacity - 1;
920 for (uint32_t index = 0; index < locals->capacity; index++) {
923 if (local->name != PM_CONSTANT_ID_UNSET) {
924 if (hash_needed) local->hash = pm_constant_id_hash(local->name);
926 uint32_t hash = local->hash;
927 while (next_locals[hash & mask].name != PM_CONSTANT_ID_UNSET) hash++;
928 next_locals[hash & mask] = *local;
933 locals->locals = next_locals;
934 locals->capacity = next_capacity;
954 if (locals->size >= (locals->capacity / 4 * 3)) {
955 pm_locals_resize(arena, locals);
958 locals->bloom |= (1u << (name & 31));
960 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
961 for (uint32_t index = 0; index < locals->capacity; index++) {
964 if (local->name == PM_CONSTANT_ID_UNSET) {
967 .location = { .start = start, .length = length },
968 .index = locals->size++,
973 }
else if (local->name == name) {
978 uint32_t mask = locals->capacity - 1;
979 uint32_t hash = pm_constant_id_hash(name);
980 uint32_t initial_hash = hash;
983 pm_local_t *local = &locals->locals[hash & mask];
985 if (local->name == PM_CONSTANT_ID_UNSET) {
988 .location = { .start = start, .length = length },
989 .index = locals->size++,
994 }
else if (local->name == name) {
999 }
while ((hash & mask) != initial_hash);
1002 assert(
false &&
"unreachable");
1012 if (!(locals->bloom & (1u << (name & 31))))
return UINT32_MAX;
1014 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
1015 for (uint32_t index = 0; index < locals->size; index++) {
1017 if (local->name == name)
return index;
1020 uint32_t mask = locals->capacity - 1;
1021 uint32_t hash = pm_constant_id_hash(name);
1022 uint32_t initial_hash = hash & mask;
1025 pm_local_t *local = &locals->locals[hash & mask];
1027 if (local->name == PM_CONSTANT_ID_UNSET) {
1029 }
else if (local->name == name) {
1034 }
while ((hash & mask) != initial_hash);
1046 uint32_t index = pm_locals_find(locals, name);
1047 assert(index != UINT32_MAX);
1050 assert(local->reads < UINT32_MAX);
1061 uint32_t index = pm_locals_find(locals, name);
1062 assert(index != UINT32_MAX);
1065 assert(local->reads > 0);
1075 uint32_t index = pm_locals_find(locals, name);
1076 assert(index != UINT32_MAX);
1078 return locals->locals[index].reads;
1091 pm_constant_id_list_init_capacity(parser->arena, list, locals->size);
1096 uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
1100 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
1102 for (uint32_t index = 0; index < capacity; index++) {
1105 if (local->name != PM_CONSTANT_ID_UNSET) {
1106 pm_constant_id_list_insert(list, (
size_t) local->index, local->name);
1108 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))) {
1109 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->name);
1111 if (constant->length >= 1 && *constant->start !=
'_') {
1112 PM_PARSER_WARN_FORMAT(
1114 local->location.
start,
1116 PM_WARN_UNUSED_LOCAL_VARIABLE,
1117 (
int) constant->length,
1118 (
const char *) constant->start
1134pm_parser_constant_id_raw(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1137 if (start == parser->constant_cache.start && end == parser->constant_cache.end) {
1138 return parser->constant_cache.id;
1141 pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (
size_t) (end - start));
1143 parser->constant_cache.start = start;
1144 parser->constant_cache.end = end;
1145 parser->constant_cache.id = id;
1154pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1155 return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length);
1162pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1163 return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (
const uint8_t *) start, length);
1171 return pm_parser_constant_id_raw(parser, token->start, token->end);
1178#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1179 case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1190 while (node != NULL) {
1191 switch (PM_NODE_TYPE(node)) {
1192 case PM_CASE_VOID_VALUE:
1193 return void_node != NULL ? void_node : node;
1194 case PM_MATCH_PREDICATE_NODE:
1196 case PM_BEGIN_NODE: {
1202 if (vn != NULL)
return vn;
1207 if (vn != NULL)
return vn;
1213 if (cast->
else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1217 if (vn == NULL)
return NULL;
1218 if (void_node == NULL) void_node = vn;
1222 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1226 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1238 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1239 pm_node_t *vn = pm_check_value_expression(parser, node);
1240 if (vn != NULL)
return vn;
1251 case PM_CASE_NODE: {
1253 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1262 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1266 if (vn == NULL)
return NULL;
1267 if (void_node == NULL) void_node = vn;
1270 node = UP(cast->else_clause);
1273 case PM_CASE_MATCH_NODE: {
1275 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1284 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1288 if (vn == NULL)
return NULL;
1289 if (void_node == NULL) void_node = vn;
1292 node = UP(cast->else_clause);
1295 case PM_ENSURE_NODE: {
1300 case PM_PARENTHESES_NODE: {
1302 node = UP(cast->
body);
1305 case PM_STATEMENTS_NODE: {
1309 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1312 switch (PM_NODE_TYPE(body_part)) {
1313 case PM_CASE_VOID_VALUE:
1314 if (void_node == NULL) {
1315 void_node = body_part;
1335 if (void_node == NULL) {
1341 case PM_UNLESS_NODE: {
1350 if (void_node == NULL) {
1356 case PM_ELSE_NODE: {
1369 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1373 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->previous;
1375 pm_locals_read(&scope->locals, cast->
name);
1388 pm_node_t *void_node = pm_check_value_expression(parser, node);
1389 if (void_node != NULL) {
1390 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1399 const char *
type = NULL;
1402 switch (PM_NODE_TYPE(node)) {
1403 case PM_BACK_REFERENCE_READ_NODE:
1404 case PM_CLASS_VARIABLE_READ_NODE:
1405 case PM_GLOBAL_VARIABLE_READ_NODE:
1406 case PM_INSTANCE_VARIABLE_READ_NODE:
1407 case PM_LOCAL_VARIABLE_READ_NODE:
1408 case PM_NUMBERED_REFERENCE_READ_NODE:
1409 type =
"a variable";
1412 case PM_CALL_NODE: {
1416 const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->
name);
1417 switch (message->length) {
1419 switch (message->start[0]) {
1430 type = (
const char *) message->start;
1436 switch (message->start[1]) {
1438 if (message->start[0] ==
'<' || message->start[0] ==
'>' || message->start[0] ==
'!' || message->start[0] ==
'=') {
1439 type = (
const char *) message->start;
1444 if (message->start[0] ==
'+' || message->start[0] ==
'-') {
1445 type = (
const char *) message->start;
1450 if (message->start[0] ==
'*') {
1451 type = (
const char *) message->start;
1458 if (memcmp(message->start,
"<=>", 3) == 0) {
1467 case PM_CONSTANT_PATH_NODE:
1471 case PM_CONSTANT_READ_NODE:
1472 type =
"a constant";
1475 case PM_DEFINED_NODE:
1484 case PM_IMAGINARY_NODE:
1485 case PM_INTEGER_NODE:
1486 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1487 case PM_INTERPOLATED_STRING_NODE:
1488 case PM_RATIONAL_NODE:
1489 case PM_REGULAR_EXPRESSION_NODE:
1490 case PM_SOURCE_ENCODING_NODE:
1491 case PM_SOURCE_FILE_NODE:
1492 case PM_SOURCE_LINE_NODE:
1493 case PM_STRING_NODE:
1494 case PM_SYMBOL_NODE:
1502 case PM_RANGE_NODE: {
1505 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1528 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1539 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1540 for (
size_t index = 0; index < size; index++) {
1541 pm_void_statement_check(parser, node->
body.
nodes[index]);
1551 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1552 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1553 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1554} pm_conditional_predicate_type_t;
1560pm_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) {
1562 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1563 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1565 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1566 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1568 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1578pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1579 switch (PM_NODE_TYPE(node)) {
1580 case PM_ARRAY_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++) {
1585 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1590 case PM_HASH_NODE: {
1591 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1594 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1596 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1599 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1606 case PM_IMAGINARY_NODE:
1607 case PM_INTEGER_NODE:
1609 case PM_RATIONAL_NODE:
1610 case PM_REGULAR_EXPRESSION_NODE:
1611 case PM_SOURCE_ENCODING_NODE:
1612 case PM_SOURCE_FILE_NODE:
1613 case PM_SOURCE_LINE_NODE:
1614 case PM_STRING_NODE:
1615 case PM_SYMBOL_NODE:
1629 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1630 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);
1648 switch (PM_NODE_TYPE(node)) {
1651 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1652 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1657 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1658 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1661 case PM_PARENTHESES_NODE: {
1664 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1666 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1671 case PM_BEGIN_NODE: {
1679 case PM_RANGE_NODE: {
1682 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1683 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1691 node->
type = PM_FLIP_FLOP_NODE;
1695 case PM_REGULAR_EXPRESSION_NODE:
1700 node->
type = PM_MATCH_LAST_LINE_NODE;
1702 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1703 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1707 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1712 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1714 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1715 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1719 case PM_INTEGER_NODE:
1720 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1721 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1722 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1725 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1728 case PM_STRING_NODE:
1729 case PM_SOURCE_FILE_NODE:
1730 case PM_INTERPOLATED_STRING_NODE:
1731 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1733 case PM_SYMBOL_NODE:
1734 case PM_INTERPOLATED_SYMBOL_NODE:
1735 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1737 case PM_SOURCE_LINE_NODE:
1738 case PM_SOURCE_ENCODING_NODE:
1740 case PM_RATIONAL_NODE:
1741 case PM_IMAGINARY_NODE:
1742 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1744 case PM_CLASS_VARIABLE_WRITE_NODE:
1747 case PM_CONSTANT_WRITE_NODE:
1750 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1753 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1756 case PM_LOCAL_VARIABLE_WRITE_NODE:
1759 case PM_MULTI_WRITE_NODE:
1795 if (arguments->
block != NULL) {
1796 uint32_t end = PM_NODE_END(arguments->
block);
1799 uint32_t arguments_end = PM_LOCATION_END(&arguments->
closing_loc);
1800 if (arguments_end > end) {
1843 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1857char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1858 if (n <= 0)
return 0;
1860 if (parser->encoding_changed) {
1863 if ((width = parser->encoding->alpha_char(b, n)) != 0) {
1865 }
else if (*b ==
'_') {
1867 }
else if (*b >= 0x80) {
1868 return parser->encoding->char_width(b, n);
1872 }
else if (*b < 0x80) {
1873 return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b ==
'_');
1875 return pm_encoding_utf_8_char_width(b, n);
1884char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1887 }
else if (*b < 0x80) {
1888 return (*b ==
'_') || (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0);
1890 return pm_encoding_utf_8_char_width(b, n);
1907#if defined(PRISM_HAS_NEON)
1908#include <arm_neon.h>
1911scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1912 const uint8_t *cursor = start;
1919 static const uint8_t low_lut_data[16] = {
1920 0x15, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
1921 0x1F, 0x1F, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0E
1923 static const uint8_t high_lut_data[16] = {
1924 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
1925 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1927 const uint8x16_t low_lut = vld1q_u8(low_lut_data);
1928 const uint8x16_t high_lut = vld1q_u8(high_lut_data);
1929 const uint8x16_t mask_0f = vdupq_n_u8(0x0F);
1931 while (cursor + 16 <= end) {
1932 uint8x16_t v = vld1q_u8(cursor);
1934 uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
1935 uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
1936 uint8x16_t ident = vandq_u8(lo_class, hi_class);
1939 if (vminvq_u8(ident) != 0) {
1945 uint8x16_t is_zero = vceqq_u8(ident, vdupq_n_u8(0));
1946 uint64_t lo = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 0);
1949 cursor += pm_ctzll(lo) / 8;
1951 uint64_t hi = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 1);
1952 cursor += 8 + pm_ctzll(hi) / 8;
1955 return (
size_t) (cursor - start);
1958 return (
size_t) (cursor - start);
1961#elif defined(PRISM_HAS_SSE2)
1962#include <emmintrin.h>
1965scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1966 const uint8_t *cursor = start;
1968 while (cursor + 16 <= end) {
1969 __m128i v = _mm_loadu_si128((
const __m128i *) cursor);
1970 __m128i zero = _mm_setzero_si128();
1977 __m128i lowered = _mm_or_si128(v, _mm_set1_epi8(0x20));
1978 __m128i letter = _mm_and_si128(
1979 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x61), lowered), zero),
1980 _mm_cmpeq_epi8(_mm_subs_epu8(lowered, _mm_set1_epi8(0x7A)), zero));
1982 __m128i digit = _mm_and_si128(
1983 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x30), v), zero),
1984 _mm_cmpeq_epi8(_mm_subs_epu8(v, _mm_set1_epi8(0x39)), zero));
1986 __m128i underscore = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5F));
1988 __m128i ident = _mm_or_si128(_mm_or_si128(letter, digit), underscore);
1989 int mask = _mm_movemask_epi8(ident);
1991 if (mask == 0xFFFF) {
1996 cursor += pm_ctzll((uint64_t) (~mask & 0xFFFF));
1997 return (
size_t) (cursor - start);
2000 return (
size_t) (cursor - start);
2007#elif defined(PRISM_HAS_SWAR)
2019scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
2020 static const uint64_t ones = 0x0101010101010101ULL;
2021 static const uint64_t highs = 0x8080808080808080ULL;
2022 const uint8_t *cursor = start;
2024 while (cursor + 8 <= end) {
2026 memcpy(&word, cursor, 8);
2029 if (word & highs)
break;
2031 uint64_t digit = ((word | highs) - ones * 0x30) & ((ones * 0x39 | highs) - word) & highs;
2038 uint64_t lowered = word | (ones * 0x20);
2039 uint64_t letter = ((lowered | highs) - ones * 0x61) & ((ones * 0x7A | highs) - lowered) & highs;
2044 uint64_t xor_us = word ^ (ones * 0x5F);
2045 uint64_t underscore = (xor_us - ones) & ~xor_us & highs;
2047 uint64_t ident = digit | letter | underscore;
2049 if (ident == highs) {
2056 uint64_t not_ident = ~ident & highs;
2057 cursor += pm_ctzll(not_ident) / 8;
2058 return (
size_t) (cursor - start);
2061 return (
size_t) (cursor - start);
2068#define scan_identifier_ascii(start, end) ((size_t) 0)
2078char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
2081 }
else if (parser->encoding_changed) {
2084 if ((width = parser->encoding->alnum_char(b, n)) != 0) {
2086 }
else if (*b ==
'_') {
2088 }
else if (*b >= 0x80) {
2089 return parser->encoding->char_width(b, n);
2094 return char_is_identifier_utf8(b, n);
2101#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
2102#define PUNCT(idx) ( \
2103 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
2104 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
2105 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
2106 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
2107 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
2110const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
2115static PRISM_INLINE bool
2116char_is_global_name_punctuation(const uint8_t b) {
2117 const unsigned int i = (const unsigned int) b;
2118 if (i <= 0x20 || 0x7e < i) return false;
2120 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
2123static PRISM_INLINE bool
2124token_is_setter_name(pm_token_t *token) {
2126 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
2127 ((token->type == PM_TOKEN_IDENTIFIER) &&
2128 (token->end - token->start >= 2) &&
2129 (token->end[-1] == '='))
2137pm_local_is_keyword(const char *source, size_t length) {
2138#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
2142 switch (source[0]) {
2143 case 'd': KEYWORD("do"); return false;
2144 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
2145 case 'o': KEYWORD("or"); return false;
2146 default: return false;
2149 switch (source[0]) {
2150 case 'a': KEYWORD("and"); return false;
2151 case 'd': KEYWORD("def"); return false;
2152 case 'e': KEYWORD("end"); return false;
2153 case 'f': KEYWORD("for"); return false;
2154 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
2155 default: return false;
2158 switch (source[0]) {
2159 case 'c': KEYWORD("case"); return false;
2160 case 'e': KEYWORD("else"); return false;
2161 case 'n': KEYWORD("next"); return false;
2162 case 'r': KEYWORD("redo"); return false;
2163 case 's': KEYWORD("self"); return false;
2164 case 't': KEYWORD("then"); KEYWORD("true"); return false;
2165 case 'w': KEYWORD("when"); return false;
2166 default: return false;
2169 switch (source[0]) {
2170 case 'a': KEYWORD("alias"); return false;
2171 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
2172 case 'c': KEYWORD("class"); return false;
2173 case 'e': KEYWORD("elsif"); return false;
2174 case 'f': KEYWORD("false"); return false;
2175 case 'r': KEYWORD("retry"); return false;
2176 case 's': KEYWORD("super"); return false;
2177 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
2178 case 'w': KEYWORD("while"); return false;
2179 case 'y': KEYWORD("yield"); return false;
2180 default: return false;
2183 switch (source[0]) {
2184 case 'e': KEYWORD("ensure"); return false;
2185 case 'm': KEYWORD("module"); return false;
2186 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
2187 case 'u': KEYWORD("unless"); return false;
2188 default: return false;
2191 KEYWORD("__LINE__");
2192 KEYWORD("__FILE__");
2195 KEYWORD("__ENCODING__");
2204/******************************************************************************/
2205/* Node flag handling functions */
2206/******************************************************************************/
2211static PRISM_INLINE void
2212pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
2213 node->flags |= flag;
2219static PRISM_INLINE void
2220pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
2221 node->flags &= (pm_node_flags_t) ~flag;
2227static PRISM_INLINE void
2228pm_node_flag_set_repeated_parameter(pm_node_t *node) {
2229 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
2230 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
2231 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
2232 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
2233 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
2234 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
2235 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
2236 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
2238 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
2241/******************************************************************************/
2242/* Node creation functions */
2243/******************************************************************************/
2250#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)
2255static PRISM_INLINE pm_node_flags_t
2256pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
2257 pm_node_flags_t flags = 0;
2259 if (closing->type == PM_TOKEN_REGEXP_END) {
2260 pm_buffer_t unknown_flags = { 0 };
2262 // The closing delimiter is normally a single byte, so the options
2263 // follow it. A `\r\n` newline delimiter is two bytes, however, so we
2264 // skip past it to avoid misreading the trailing `\n` as an option.
2265 const uint8_t *flag = closing->start + 1;
2266 if ((closing->end - closing->start) >= 2 && closing->start[0] == '\r' && closing->start[1] == '\n') {
2270 for (; flag < closing->end; flag++) {
2272 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
2273 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
2274 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
2275 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
2277 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
2278 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
2279 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
2280 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
2282 default: pm_buffer_append_byte(&unknown_flags, *flag);
2286 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
2287 if (unknown_flags_length != 0) {
2288 const char *word = unknown_flags_length >= 2 ? "options" : "option";
2289 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
2291 pm_buffer_cleanup(&unknown_flags);
2297#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
2299static pm_statements_node_t *
2300pm_statements_node_create(pm_parser_t *parser);
2303pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
2306pm_statements_node_body_length(pm_statements_node_t *node);
2312static PRISM_INLINE void
2313pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
2314 if (integer->values != NULL) {
2315 size_t byte_size = integer->length * sizeof(uint32_t);
2316 uint32_t *old_values = integer->values;
2317 integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
2325static pm_error_recovery_node_t *
2326pm_error_recovery_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
2327 return pm_error_recovery_node_new(
2331 ((pm_location_t) { .start = start, .length = length }),
2339static pm_error_recovery_node_t *
2340pm_error_recovery_node_create_unexpected(pm_parser_t *parser, pm_node_t *unexpected) {
2341 return pm_error_recovery_node_new(
2345 unexpected->location,
2353static pm_alias_global_variable_node_t *
2354pm_alias_global_variable_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_global_variable_node_new(
2361 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2364 TOK2LOC(parser, keyword)
2371static pm_alias_method_node_t *
2372pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2373 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2375 return pm_alias_method_node_new(
2379 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2382 TOK2LOC(parser, keyword)
2389static pm_alternation_pattern_node_t *
2390pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2391 return pm_alternation_pattern_node_new(
2395 PM_LOCATION_INIT_NODES(left, right),
2398 TOK2LOC(parser, operator)
2405static pm_and_node_t *
2406pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2407 pm_assert_value_expression(parser, left);
2409 return pm_and_node_new(
2413 PM_LOCATION_INIT_NODES(left, right),
2416 TOK2LOC(parser, operator)
2423static pm_arguments_node_t *
2424pm_arguments_node_create(pm_parser_t *parser) {
2425 return pm_arguments_node_new(
2429 PM_LOCATION_INIT_UNSET,
2430 ((pm_node_list_t) { 0 })
2438pm_arguments_node_size(pm_arguments_node_t *node) {
2439 return node->arguments.size;
2446pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
2447 if (pm_arguments_node_size(node) == 0) {
2448 PM_NODE_START_SET_NODE(node, argument);
2451 if (PM_NODE_END(node) < PM_NODE_END(argument)) {
2452 PM_NODE_LENGTH_SET_NODE(node, argument);
2455 pm_node_list_append(arena, &node->arguments, argument);
2457 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2458 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2459 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2461 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2469static pm_array_node_t *
2470pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2471 if (opening == NULL) {
2472 return pm_array_node_new(
2475 PM_NODE_FLAG_STATIC_LITERAL,
2476 PM_LOCATION_INIT_UNSET,
2477 ((pm_node_list_t) { 0 }),
2478 ((pm_location_t) { 0 }),
2479 ((pm_location_t) { 0 })
2482 return pm_array_node_new(
2485 PM_NODE_FLAG_STATIC_LITERAL,
2486 PM_LOCATION_INIT_TOKEN(parser, opening),
2487 ((pm_node_list_t) { 0 }),
2488 TOK2LOC(parser, opening),
2489 TOK2LOC(parser, opening)
2497static PRISM_INLINE void
2498pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
2499 if (!node->elements.size && !node->opening_loc.length) {
2500 PM_NODE_START_SET_NODE(node, element);
2503 pm_node_list_append(arena, &node->elements, element);
2504 PM_NODE_LENGTH_SET_NODE(node, element);
2506 // If the element is not a static literal, then the array is not a static
2507 // literal. Turn that flag off.
2508 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)) {
2509 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2512 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2513 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2521pm_array_node_close_set(const pm_parser_t *parser, pm_array_node_t *node, const pm_token_t *closing) {
2522 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == 0);
2523 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2524 node->closing_loc = TOK2LOC(parser, closing);
2531static pm_array_pattern_node_t *
2532pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2533 pm_array_pattern_node_t *node = pm_array_pattern_node_new(
2537 PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2539 ((pm_node_list_t) { 0 }),
2541 ((pm_node_list_t) { 0 }),
2542 ((pm_location_t) { 0 }),
2543 ((pm_location_t) { 0 })
2546 // For now we're going to just copy over each pointer manually. This could be
2547 // much more efficient, as we could instead resize the node list.
2548 bool found_rest = false;
2551 PM_NODE_LIST_FOREACH(nodes, index, child) {
2552 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2555 } else if (found_rest) {
2556 pm_node_list_append(parser->arena, &node->posts, child);
2558 pm_node_list_append(parser->arena, &node->requireds, child);
2568static pm_array_pattern_node_t *
2569pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2570 return pm_array_pattern_node_new(
2574 PM_LOCATION_INIT_NODE(rest),
2576 ((pm_node_list_t) { 0 }),
2578 ((pm_node_list_t) { 0 }),
2579 ((pm_location_t) { 0 }),
2580 ((pm_location_t) { 0 })
2588static pm_array_pattern_node_t *
2589pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2590 return pm_array_pattern_node_new(
2594 PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
2596 ((pm_node_list_t) { 0 }),
2598 ((pm_node_list_t) { 0 }),
2599 TOK2LOC(parser, opening),
2600 TOK2LOC(parser, closing)
2608static pm_array_pattern_node_t *
2609pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2610 return pm_array_pattern_node_new(
2614 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2616 ((pm_node_list_t) { 0 }),
2618 ((pm_node_list_t) { 0 }),
2619 TOK2LOC(parser, opening),
2620 TOK2LOC(parser, closing)
2624static PRISM_INLINE void
2625pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
2626 pm_node_list_append(arena, &node->requireds, inner);
2632static pm_assoc_node_t *
2633pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2636 if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
2637 end = PM_NODE_END(value);
2638 } else if (operator != NULL) {
2639 end = PM_TOKEN_END(parser, operator);
2641 end = PM_NODE_END(key);
2644 // Hash string keys will be frozen, so we can mark them as frozen here so
2645 // that the compiler picks them up and also when we check for static literal
2646 // on the keys it gets factored in.
2647 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2648 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2651 // If the key and value of this assoc node are both static literals, then
2652 // we can mark this node as a static literal.
2653 pm_node_flags_t flags = 0;
2655 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2656 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)
2658 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2661 return pm_assoc_node_new(
2665 ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
2668 NTOK2LOC(parser, operator)
2675static pm_assoc_splat_node_t *
2676pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2677 assert(operator->type == PM_TOKEN_USTAR_STAR);
2679 return pm_assoc_splat_node_new(
2683 (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
2685 TOK2LOC(parser, operator)
2692static pm_back_reference_read_node_t *
2693pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2694 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2696 return pm_back_reference_read_node_new(
2700 PM_LOCATION_INIT_TOKEN(parser, name),
2701 pm_parser_constant_id_token(parser, name)
2708static pm_begin_node_t *
2709pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2710 uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
2711 uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
2713 return pm_begin_node_new(
2717 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2718 NTOK2LOC(parser, begin_keyword),
2723 ((pm_location_t) { 0 })
2731pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2732 if (node->begin_keyword_loc.length == 0) {
2733 PM_NODE_START_SET_NODE(node, rescue_clause);
2735 PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
2736 node->rescue_clause = rescue_clause;
2743pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2744 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2745 PM_NODE_START_SET_NODE(node, else_clause);
2747 PM_NODE_LENGTH_SET_NODE(node, else_clause);
2748 node->else_clause = else_clause;
2755pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2756 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2757 PM_NODE_START_SET_NODE(node, ensure_clause);
2759 PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
2760 node->ensure_clause = ensure_clause;
2767pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
2768 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
2769 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
2770 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
2776static pm_block_argument_node_t *
2777pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2778 assert(operator->type == PM_TOKEN_UAMPERSAND);
2780 return pm_block_argument_node_new(
2784 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
2786 TOK2LOC(parser, operator)
2793static pm_block_node_t *
2794pm_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) {
2795 return pm_block_node_new(
2799 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2803 TOK2LOC(parser, opening),
2804 TOK2LOC(parser, closing)
2811static pm_block_parameter_node_t *
2812pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2813 assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2815 return pm_block_parameter_node_new(
2819 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
2820 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
2821 NTOK2LOC(parser, name),
2822 TOK2LOC(parser, operator)
2829static pm_block_parameters_node_t *
2830pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2832 if (opening != NULL) {
2833 start = PM_TOKEN_START(parser, opening);
2834 } else if (parameters != NULL) {
2835 start = PM_NODE_START(parameters);
2841 if (parameters != NULL) {
2842 end = PM_NODE_END(parameters);
2843 } else if (opening != NULL) {
2844 end = PM_TOKEN_END(parser, opening);
2849 return pm_block_parameters_node_new(
2853 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2855 ((pm_node_list_t) { 0 }),
2856 NTOK2LOC(parser, opening),
2857 ((pm_location_t) { 0 })
2865pm_block_parameters_node_closing_set(const pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_token_t *closing) {
2866 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == 0);
2867 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2868 node->closing_loc = TOK2LOC(parser, closing);
2874static pm_block_local_variable_node_t *
2875pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2876 return pm_block_local_variable_node_new(
2880 PM_LOCATION_INIT_TOKEN(parser, name),
2881 pm_parser_constant_id_token(parser, name)
2889pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2890 pm_node_list_append(arena, &node->locals, UP(local));
2892 if (PM_NODE_LENGTH(node) == 0) {
2893 PM_NODE_START_SET_NODE(node, local);
2896 PM_NODE_LENGTH_SET_NODE(node, local);
2902static pm_break_node_t *
2903pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2904 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2906 return pm_break_node_new(
2910 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
2912 TOK2LOC(parser, keyword)
2916// There are certain flags that we want to use internally but don't want to
2917// expose because they are not relevant beyond parsing. Therefore we'll define
2918// them here and not define them in config.yml/a header file.
2919static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2921static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2922static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2923static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2930static pm_call_node_t *
2931pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2932 return pm_call_node_new(
2936 PM_LOCATION_INIT_UNSET,
2938 ((pm_location_t) { 0 }),
2940 ((pm_location_t) { 0 }),
2941 ((pm_location_t) { 0 }),
2943 ((pm_location_t) { 0 }),
2944 ((pm_location_t) { 0 }),
2953static PRISM_INLINE pm_node_flags_t
2954pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2955 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2962static pm_call_node_t *
2963pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2964 pm_assert_value_expression(parser, receiver);
2966 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2967 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2968 flags |= PM_CALL_NODE_FLAGS_INDEX;
2971 pm_call_node_t *node = pm_call_node_create(parser, flags);
2973 PM_NODE_START_SET_NODE(node, receiver);
2975 const pm_location_t *end = pm_arguments_end(arguments);
2976 assert(end != NULL && "unreachable");
2977 PM_NODE_LENGTH_SET_LOCATION(node, end);
2979 node->receiver = receiver;
2980 node->message_loc.start = arguments->opening_loc.start;
2981 node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
2983 node->opening_loc = arguments->opening_loc;
2984 node->arguments = arguments->arguments;
2985 node->closing_loc = arguments->closing_loc;
2986 node->block = arguments->block;
2988 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2995static pm_call_node_t *
2996pm_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) {
2997 pm_assert_value_expression(parser, receiver);
2998 pm_assert_value_expression(parser, argument);
3000 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
3002 PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
3003 PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
3005 node->receiver = receiver;
3006 node->message_loc = TOK2LOC(parser, operator);
3008 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
3009 pm_arguments_node_arguments_append(parser->arena, arguments, argument);
3010 node->arguments = arguments;
3012 node->name = pm_parser_constant_id_token(parser, operator);
3016static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
3021static pm_call_node_t *
3022pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
3023 pm_assert_value_expression(parser, receiver);
3025 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3027 PM_NODE_START_SET_NODE(node, receiver);
3028 const pm_location_t *end = pm_arguments_end(arguments);
3030 PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
3032 PM_NODE_LENGTH_SET_LOCATION(node, end);
3035 node->receiver = receiver;
3036 node->call_operator_loc = TOK2LOC(parser, operator);
3037 node->message_loc = TOK2LOC(parser, message);
3038 node->opening_loc = arguments->opening_loc;
3039 node->arguments = arguments->arguments;
3040 node->closing_loc = arguments->closing_loc;
3041 node->block = arguments->block;
3043 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3044 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3051 node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
3058static pm_call_node_t *
3059pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
3060 pm_call_node_t *node = pm_call_node_create(parser, 0);
3061 node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
3063 node->receiver = receiver;
3064 node->arguments = arguments;
3066 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
3074static pm_call_node_t *
3075pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
3076 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3078 PM_NODE_START_SET_TOKEN(parser, node, message);
3079 const pm_location_t *end = pm_arguments_end(arguments);
3080 assert(end != NULL && "unreachable");
3081 PM_NODE_LENGTH_SET_LOCATION(node, end);
3083 node->message_loc = TOK2LOC(parser, message);
3084 node->opening_loc = arguments->opening_loc;
3085 node->arguments = arguments->arguments;
3086 node->closing_loc = arguments->closing_loc;
3087 node->block = arguments->block;
3089 node->name = pm_parser_constant_id_token(parser, message);
3097static pm_call_node_t *
3098pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
3099 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3101 node->base.location = (pm_location_t) { 0 };
3102 node->arguments = arguments;
3111static pm_call_node_t *
3112pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
3113 pm_assert_value_expression(parser, receiver);
3114 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
3116 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
3118 PM_NODE_START_SET_TOKEN(parser, node, message);
3119 if (arguments->closing_loc.length > 0) {
3120 PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
3122 assert(receiver != NULL);
3123 PM_NODE_LENGTH_SET_NODE(node, receiver);
3126 node->receiver = receiver;
3127 node->message_loc = TOK2LOC(parser, message);
3128 node->opening_loc = arguments->opening_loc;
3129 node->arguments = arguments->arguments;
3130 node->closing_loc = arguments->closing_loc;
3132 node->name = pm_parser_constant_id_constant(parser, "!", 1);
3139static pm_call_node_t *
3140pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
3141 pm_assert_value_expression(parser, receiver);
3143 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3145 PM_NODE_START_SET_NODE(node, receiver);
3146 const pm_location_t *end = pm_arguments_end(arguments);
3147 assert(end != NULL && "unreachable");
3148 PM_NODE_LENGTH_SET_LOCATION(node, end);
3150 node->receiver = receiver;
3151 node->call_operator_loc = TOK2LOC(parser, operator);
3152 node->opening_loc = arguments->opening_loc;
3153 node->arguments = arguments->arguments;
3154 node->closing_loc = arguments->closing_loc;
3155 node->block = arguments->block;
3157 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3158 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3161 node->name = pm_parser_constant_id_constant(parser, "call", 4);
3168static pm_call_node_t *
3169pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
3170 pm_assert_value_expression(parser, receiver);
3172 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3174 PM_NODE_START_SET_TOKEN(parser, node, operator);
3175 PM_NODE_LENGTH_SET_NODE(node, receiver);
3177 node->receiver = receiver;
3178 node->message_loc = TOK2LOC(parser, operator);
3180 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
3188static pm_call_node_t *
3189pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
3190 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3192 node->base.location = TOK2LOC(parser, message);
3193 node->message_loc = TOK2LOC(parser, message);
3195 node->name = pm_parser_constant_id_token(parser, message);
3203static PRISM_INLINE bool
3204pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
3206 (node->message_loc.length > 0) &&
3207 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
3208 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
3209 char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
3210 (node->opening_loc.length == 0) &&
3211 (node->arguments == NULL) &&
3212 (node->block == NULL)
3220pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
3221 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
3223 if (write_constant->length > 0) {
3224 size_t length = write_constant->length - 1;
3226 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
3227 memcpy(memory, write_constant->start, length);
3229 *read_name = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, memory, length);
3231 // We can get here if the message was missing because of a syntax error.
3232 *read_name = pm_parser_constant_id_constant(parser, "", 0);
3239static pm_call_and_write_node_t *
3240pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3241 assert(target->block == NULL);
3242 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3244 pm_call_and_write_node_t *node = pm_call_and_write_node_new(
3248 PM_LOCATION_INIT_NODES(target, value),
3250 target->call_operator_loc,
3251 target->message_loc,
3254 TOK2LOC(parser, operator),
3258 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3260 // The target is no longer necessary because we've reused its children.
3261 // It is arena-allocated so no explicit free is needed.
3271pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
3272 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
3273 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
3275 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
3276 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
3277 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
3283 if (block != NULL) {
3284 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
3292static pm_index_and_write_node_t *
3293pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3294 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3296 pm_index_arguments_check(parser, target->arguments, target->block);
3298 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3300 pm_index_and_write_node_t *node = pm_index_and_write_node_new(
3304 PM_LOCATION_INIT_NODES(target, value),
3306 target->call_operator_loc,
3307 target->opening_loc,
3309 target->closing_loc,
3310 (pm_block_argument_node_t *) target->block,
3311 TOK2LOC(parser, operator),
3315 // The target is no longer necessary because we've reused its children.
3316 // It is arena-allocated so no explicit free is needed.
3324static pm_call_operator_write_node_t *
3325pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3326 assert(target->block == NULL);
3328 pm_call_operator_write_node_t *node = pm_call_operator_write_node_new(
3332 PM_LOCATION_INIT_NODES(target, value),
3334 target->call_operator_loc,
3335 target->message_loc,
3338 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3339 TOK2LOC(parser, operator),
3343 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3345 // The target is no longer necessary because we've reused its children.
3346 // It is arena-allocated so no explicit free is needed.
3354static pm_index_operator_write_node_t *
3355pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3356 pm_index_arguments_check(parser, target->arguments, target->block);
3358 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3360 pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
3364 PM_LOCATION_INIT_NODES(target, value),
3366 target->call_operator_loc,
3367 target->opening_loc,
3369 target->closing_loc,
3370 (pm_block_argument_node_t *) target->block,
3371 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3372 TOK2LOC(parser, operator),
3376 // The target is no longer necessary because we've reused its children.
3377 // It is arena-allocated so no explicit free is needed.
3385static pm_call_or_write_node_t *
3386pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3387 assert(target->block == NULL);
3388 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3390 pm_call_or_write_node_t *node = pm_call_or_write_node_new(
3394 PM_LOCATION_INIT_NODES(target, value),
3396 target->call_operator_loc,
3397 target->message_loc,
3400 TOK2LOC(parser, operator),
3404 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3406 // The target is no longer necessary because we've reused its children.
3407 // It is arena-allocated so no explicit free is needed.
3415static pm_index_or_write_node_t *
3416pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3417 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3419 pm_index_arguments_check(parser, target->arguments, target->block);
3421 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3423 pm_index_or_write_node_t *node = pm_index_or_write_node_new(
3427 PM_LOCATION_INIT_NODES(target, value),
3429 target->call_operator_loc,
3430 target->opening_loc,
3432 target->closing_loc,
3433 (pm_block_argument_node_t *) target->block,
3434 TOK2LOC(parser, operator),
3438 // The target is no longer necessary because we've reused its children.
3439 // It is arena-allocated so no explicit free is needed.
3448static pm_call_target_node_t *
3449pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3450 pm_call_target_node_t *node = pm_call_target_node_new(
3454 PM_LOCATION_INIT_NODE(target),
3456 target->call_operator_loc,
3461 /* It is possible to get here where we have parsed an invalid syntax tree
3462 * where the call operator was not present. In that case we will have a
3463 * problem because it is a required location. In this case we need to fill
3464 * it in with a fake location so that the syntax tree remains valid. */
3465 if (node->call_operator_loc.length == 0) {
3466 node->call_operator_loc = target->base.location;
3469 // The target is no longer necessary because we've reused its children.
3470 // It is arena-allocated so no explicit free is needed.
3479static pm_index_target_node_t *
3480pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3481 pm_index_arguments_check(parser, target->arguments, target->block);
3482 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3484 pm_index_target_node_t *node = pm_index_target_node_new(
3487 FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3488 PM_LOCATION_INIT_NODE(target),
3490 target->opening_loc,
3492 target->closing_loc,
3493 (pm_block_argument_node_t *) target->block
3496 // The target is no longer necessary because we've reused its children.
3497 // It is arena-allocated so no explicit free is needed.
3505static pm_capture_pattern_node_t *
3506pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3507 return pm_capture_pattern_node_new(
3511 PM_LOCATION_INIT_NODES(value, target),
3514 TOK2LOC(parser, operator)
3521static pm_case_node_t *
3522pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3523 return pm_case_node_new(
3527 PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
3529 ((pm_node_list_t) { 0 }),
3531 TOK2LOC(parser, case_keyword),
3532 NTOK2LOC(parser, end_keyword)
3540pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
3541 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3543 pm_node_list_append(arena, &node->conditions, condition);
3544 PM_NODE_LENGTH_SET_NODE(node, condition);
3551pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3552 node->else_clause = else_clause;
3553 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3560pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
3561 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3562 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3568static pm_case_match_node_t *
3569pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
3570 return pm_case_match_node_new(
3574 PM_LOCATION_INIT_TOKEN(parser, case_keyword),
3576 ((pm_node_list_t) { 0 }),
3578 TOK2LOC(parser, case_keyword),
3579 ((pm_location_t) { 0 })
3587pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
3588 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3590 pm_node_list_append(arena, &node->conditions, condition);
3591 PM_NODE_LENGTH_SET_NODE(node, condition);
3598pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3599 node->else_clause = else_clause;
3600 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3607pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3608 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3609 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3615static pm_class_node_t *
3616pm_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) {
3617 return pm_class_node_new(
3621 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
3623 TOK2LOC(parser, class_keyword),
3625 NTOK2LOC(parser, inheritance_operator),
3628 TOK2LOC(parser, end_keyword),
3629 pm_parser_constant_id_token(parser, name)
3636static pm_class_variable_and_write_node_t *
3637pm_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) {
3638 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3640 return pm_class_variable_and_write_node_new(
3644 PM_LOCATION_INIT_NODES(target, value),
3646 target->base.location,
3647 TOK2LOC(parser, operator),
3655static pm_class_variable_operator_write_node_t *
3656pm_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) {
3657 return pm_class_variable_operator_write_node_new(
3661 PM_LOCATION_INIT_NODES(target, value),
3663 target->base.location,
3664 TOK2LOC(parser, operator),
3666 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3673static pm_class_variable_or_write_node_t *
3674pm_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) {
3675 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3677 return pm_class_variable_or_write_node_new(
3681 PM_LOCATION_INIT_NODES(target, value),
3683 target->base.location,
3684 TOK2LOC(parser, operator),
3692static pm_class_variable_read_node_t *
3693pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3694 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3696 return pm_class_variable_read_node_new(
3700 PM_LOCATION_INIT_TOKEN(parser, token),
3701 pm_parser_constant_id_token(parser, token)
3711static PRISM_INLINE pm_node_flags_t
3712pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3713 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
3722static pm_class_variable_write_node_t *
3723pm_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) {
3724 return pm_class_variable_write_node_new(
3727 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3728 PM_LOCATION_INIT_NODES(read_node, value),
3730 read_node->base.location,
3732 TOK2LOC(parser, operator)
3739static pm_constant_path_and_write_node_t *
3740pm_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) {
3741 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3743 return pm_constant_path_and_write_node_new(
3747 PM_LOCATION_INIT_NODES(target, value),
3749 TOK2LOC(parser, operator),
3757static pm_constant_path_operator_write_node_t *
3758pm_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) {
3759 return pm_constant_path_operator_write_node_new(
3763 PM_LOCATION_INIT_NODES(target, value),
3765 TOK2LOC(parser, operator),
3767 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3774static pm_constant_path_or_write_node_t *
3775pm_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) {
3776 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3778 return pm_constant_path_or_write_node_new(
3782 PM_LOCATION_INIT_NODES(target, value),
3784 TOK2LOC(parser, operator),
3792static pm_constant_path_node_t *
3793pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3794 pm_assert_value_expression(parser, parent);
3796 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3797 if (name_token->type == PM_TOKEN_CONSTANT) {
3798 name = pm_parser_constant_id_token(parser, name_token);
3801 return pm_constant_path_node_new(
3805 (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
3808 TOK2LOC(parser, delimiter),
3809 TOK2LOC(parser, name_token)
3816static pm_constant_path_write_node_t *
3817pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3818 return pm_constant_path_write_node_new(
3821 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3822 PM_LOCATION_INIT_NODES(target, value),
3824 TOK2LOC(parser, operator),
3832static pm_constant_and_write_node_t *
3833pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3834 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3836 return pm_constant_and_write_node_new(
3840 PM_LOCATION_INIT_NODES(target, value),
3842 target->base.location,
3843 TOK2LOC(parser, operator),
3851static pm_constant_operator_write_node_t *
3852pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3853 return pm_constant_operator_write_node_new(
3857 PM_LOCATION_INIT_NODES(target, value),
3859 target->base.location,
3860 TOK2LOC(parser, operator),
3862 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3869static pm_constant_or_write_node_t *
3870pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3871 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3873 return pm_constant_or_write_node_new(
3877 PM_LOCATION_INIT_NODES(target, value),
3879 target->base.location,
3880 TOK2LOC(parser, operator),
3888static pm_constant_read_node_t *
3889pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3890 assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
3892 return pm_constant_read_node_new(
3896 PM_LOCATION_INIT_TOKEN(parser, name),
3897 pm_parser_constant_id_token(parser, name)
3904static pm_constant_write_node_t *
3905pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3906 return pm_constant_write_node_new(
3909 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3910 PM_LOCATION_INIT_NODES(target, value),
3912 target->base.location,
3914 TOK2LOC(parser, operator)
3922pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3923 switch (PM_NODE_TYPE(node)) {
3924 case PM_BEGIN_NODE: {
3925 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3926 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3929 case PM_PARENTHESES_NODE: {
3930 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3931 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3934 case PM_STATEMENTS_NODE: {
3935 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3936 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3941 case PM_IMAGINARY_NODE:
3942 case PM_INTEGER_NODE:
3943 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3944 case PM_INTERPOLATED_STRING_NODE:
3945 case PM_INTERPOLATED_SYMBOL_NODE:
3946 case PM_INTERPOLATED_X_STRING_NODE:
3947 case PM_RATIONAL_NODE:
3948 case PM_REGULAR_EXPRESSION_NODE:
3949 case PM_SOURCE_ENCODING_NODE:
3950 case PM_SOURCE_FILE_NODE:
3951 case PM_SOURCE_LINE_NODE:
3952 case PM_STRING_NODE:
3953 case PM_SYMBOL_NODE:
3954 case PM_X_STRING_NODE:
3955 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3965static pm_def_node_t *
3967 pm_parser_t *parser,
3968 pm_constant_id_t name,
3969 const pm_token_t *name_loc,
3970 pm_node_t *receiver,
3971 pm_parameters_node_t *parameters,
3973 pm_constant_id_list_t *locals,
3974 const pm_token_t *def_keyword,
3975 const pm_token_t *operator,
3976 const pm_token_t *lparen,
3977 const pm_token_t *rparen,
3978 const pm_token_t *equal,
3979 const pm_token_t *end_keyword
3981 if (receiver != NULL) {
3982 pm_def_node_receiver_check(parser, receiver);
3985 return pm_def_node_new(
3989 (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
3991 TOK2LOC(parser, name_loc),
3996 TOK2LOC(parser, def_keyword),
3997 NTOK2LOC(parser, operator),
3998 NTOK2LOC(parser, lparen),
3999 NTOK2LOC(parser, rparen),
4000 NTOK2LOC(parser, equal),
4001 NTOK2LOC(parser, end_keyword)
4008static pm_defined_node_t *
4009pm_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) {
4010 return pm_defined_node_new(
4014 (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
4015 NTOK2LOC(parser, lparen),
4017 NTOK2LOC(parser, rparen),
4018 TOK2LOC(parser, keyword)
4025static pm_else_node_t *
4026pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4027 return pm_else_node_new(
4031 ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
4032 TOK2LOC(parser, else_keyword),
4034 NTOK2LOC(parser, end_keyword)
4041static pm_embedded_statements_node_t *
4042pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
4043 return pm_embedded_statements_node_new(
4047 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4048 TOK2LOC(parser, opening),
4050 TOK2LOC(parser, closing)
4057static pm_embedded_variable_node_t *
4058pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
4059 return pm_embedded_variable_node_new(
4063 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
4064 TOK2LOC(parser, operator),
4072static pm_ensure_node_t *
4073pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4074 return pm_ensure_node_new(
4078 PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
4079 TOK2LOC(parser, ensure_keyword),
4081 TOK2LOC(parser, end_keyword)
4088static pm_false_node_t *
4089pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4090 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4092 return pm_false_node_new(
4095 PM_NODE_FLAG_STATIC_LITERAL,
4096 PM_LOCATION_INIT_TOKEN(parser, token)
4104static pm_find_pattern_node_t *
4105pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4106 assert(nodes->size >= 2);
4107 pm_node_t *left = nodes->nodes[0];
4108 pm_node_t *right = nodes->nodes[nodes->size - 1];
4110 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4111 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4113 pm_find_pattern_node_t *node = pm_find_pattern_node_new(
4117 PM_LOCATION_INIT_NODES(left, right),
4119 (pm_splat_node_t *) left,
4120 ((pm_node_list_t) { 0 }),
4121 (pm_splat_node_t *) right,
4122 ((pm_location_t) { 0 }),
4123 ((pm_location_t) { 0 })
4126 // For now we're going to just copy over each pointer manually. This could be
4127 // much more efficient, as we could instead resize the node list to only point
4129 for (size_t index = 1; index < nodes->size - 1; index++) {
4130 pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
4141pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4142 ptrdiff_t diff = token->end - token->start;
4143 if (diff <= 0) return 0.0;
4145 // First, get a buffer of the content.
4146 size_t length = (size_t) diff;
4147 const size_t buffer_size = sizeof(char) * (length + 1);
4148 char *buffer = xmalloc(buffer_size);
4149 memcpy((void *) buffer, token->start, length);
4151 // Next, determine if we need to replace the decimal point because of
4152 // locale-specific options, and then normalize them if we have to.
4153 char decimal_point = *localeconv()->decimal_point;
4154 if (decimal_point != '.') {
4155 for (size_t index = 0; index < length; index++) {
4156 if (buffer[index] == '.') buffer[index] = decimal_point;
4161 * Next, handle underscores by removing them from the buffer in a single
4162 * pass to avoid quadratic-time copies.
4166 for (size_t read = 0; read < length; read++) {
4167 if (buffer[read] != '_') buffer[write++] = buffer[read];
4172 // Null-terminate the buffer so that strtod cannot read off the end.
4173 buffer[length] = '\0';
4175 // Now, call strtod to parse the value. Note that CRuby has their own
4176 // version of strtod which avoids locales. We're okay using the locale-aware
4177 // version because we've already validated through the parser that the token
4178 // is in a valid format.
4181 double value = strtod(buffer, &eptr);
4183 // This should never happen, because we've already checked that the token
4184 // is in a valid format. However it's good to be safe.
4185 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4186 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
4187 xfree_sized(buffer, buffer_size);
4191 // If errno is set, then it should only be ERANGE. At this point we need to
4192 // check if it's infinity (it should be).
4193 if (errno == ERANGE && PRISM_ISINF(value)) {
4195 const char *ellipsis;
4201 warn_width = (int) length;
4205 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);
4206 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4209 // Finally we can free the buffer and return the value.
4210 xfree_sized(buffer, buffer_size);
4217static pm_float_node_t *
4218pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4219 assert(token->type == PM_TOKEN_FLOAT);
4221 return pm_float_node_new(
4224 PM_NODE_FLAG_STATIC_LITERAL,
4225 PM_LOCATION_INIT_TOKEN(parser, token),
4226 pm_double_parse(parser, token)
4233static pm_imaginary_node_t *
4234pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4235 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4237 return pm_imaginary_node_new(
4240 PM_NODE_FLAG_STATIC_LITERAL,
4241 PM_LOCATION_INIT_TOKEN(parser, token),
4242 UP(pm_float_node_create(parser, &((pm_token_t) {
4243 .type = PM_TOKEN_FLOAT,
4244 .start = token->start,
4245 .end = token->end - 1
4253static pm_rational_node_t *
4254pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4255 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4257 pm_rational_node_t *node = pm_rational_node_new(
4260 PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4261 PM_LOCATION_INIT_TOKEN(parser, token),
4262 ((pm_integer_t) { 0 }),
4263 ((pm_integer_t) { 0 })
4266 const uint8_t *start = token->start;
4267 const uint8_t *end = token->end - 1; // r
4269 while (start < end && *start == '0') start++; // 0.1 -> .1
4270 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4272 size_t length = (size_t) (end - start);
4274 node->denominator.value = 1;
4278 const uint8_t *point = memchr(start, '.', length);
4279 assert(point && "should have a decimal point");
4281 uint8_t *digits = xmalloc(length);
4282 if (digits == NULL) {
4283 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4287 memcpy(digits, start, (unsigned long) (point - start));
4288 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4289 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4291 size_t fract_length = 0;
4292 for (const uint8_t *fract = point; fract < end; ++fract) {
4293 if (*fract != '_') ++fract_length;
4296 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
4297 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
4298 xfree_sized(digits, length);
4300 pm_integers_reduce(&node->numerator, &node->denominator);
4301 pm_integer_arena_move(parser->arena, &node->numerator);
4302 pm_integer_arena_move(parser->arena, &node->denominator);
4310static pm_imaginary_node_t *
4311pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4312 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4314 return pm_imaginary_node_new(
4317 PM_NODE_FLAG_STATIC_LITERAL,
4318 PM_LOCATION_INIT_TOKEN(parser, token),
4319 UP(pm_float_node_rational_create(parser, &((pm_token_t) {
4320 .type = PM_TOKEN_FLOAT_RATIONAL,
4321 .start = token->start,
4322 .end = token->end - 1
4330static pm_for_node_t *
4332 pm_parser_t *parser,
4334 pm_node_t *collection,
4335 pm_statements_node_t *statements,
4336 const pm_token_t *for_keyword,
4337 const pm_token_t *in_keyword,
4338 const pm_token_t *do_keyword,
4339 const pm_token_t *end_keyword
4341 return pm_for_node_new(
4345 PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
4349 TOK2LOC(parser, for_keyword),
4350 TOK2LOC(parser, in_keyword),
4351 NTOK2LOC(parser, do_keyword),
4352 TOK2LOC(parser, end_keyword)
4359static pm_forwarding_arguments_node_t *
4360pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4361 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4363 return pm_forwarding_arguments_node_new(
4367 PM_LOCATION_INIT_TOKEN(parser, token)
4374static pm_forwarding_parameter_node_t *
4375pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4376 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4378 return pm_forwarding_parameter_node_new(
4382 PM_LOCATION_INIT_TOKEN(parser, token)
4389static pm_forwarding_super_node_t *
4390pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4391 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4392 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4394 pm_block_node_t *block = NULL;
4395 if (arguments->block != NULL) {
4396 block = (pm_block_node_t *) arguments->block;
4399 return pm_forwarding_super_node_new(
4403 (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
4404 PM_LOCATION_INIT_TOKEN(parser, token),
4413static pm_hash_pattern_node_t *
4414pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4415 return pm_hash_pattern_node_new(
4419 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4421 ((pm_node_list_t) { 0 }),
4423 TOK2LOC(parser, opening),
4424 TOK2LOC(parser, closing)
4431static pm_hash_pattern_node_t *
4432pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4436 if (elements->size > 0) {
4438 start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
4439 end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
4441 start = PM_NODE_START(elements->nodes[0]);
4442 end = PM_NODE_END(elements->nodes[elements->size - 1]);
4445 assert(rest != NULL);
4446 start = PM_NODE_START(rest);
4447 end = PM_NODE_END(rest);
4450 pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
4454 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4456 ((pm_node_list_t) { 0 }),
4458 ((pm_location_t) { 0 }),
4459 ((pm_location_t) { 0 })
4462 pm_node_list_concat(parser->arena, &node->elements, elements);
4469static pm_constant_id_t
4470pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4471 switch (PM_NODE_TYPE(target)) {
4472 case PM_GLOBAL_VARIABLE_READ_NODE:
4473 return ((pm_global_variable_read_node_t *) target)->name;
4474 case PM_BACK_REFERENCE_READ_NODE:
4475 return ((pm_back_reference_read_node_t *) target)->name;
4476 case PM_NUMBERED_REFERENCE_READ_NODE:
4477 // This will only ever happen in the event of a syntax error, but we
4478 // still need to provide something for the node.
4479 return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
4481 assert(false && "unreachable");
4482 return (pm_constant_id_t) -1;
4489static pm_global_variable_and_write_node_t *
4490pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4491 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4493 return pm_global_variable_and_write_node_new(
4497 PM_LOCATION_INIT_NODES(target, value),
4498 pm_global_variable_write_name(parser, target),
4500 TOK2LOC(parser, operator),
4508static pm_global_variable_operator_write_node_t *
4509pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4510 return pm_global_variable_operator_write_node_new(
4514 PM_LOCATION_INIT_NODES(target, value),
4515 pm_global_variable_write_name(parser, target),
4517 TOK2LOC(parser, operator),
4519 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4526static pm_global_variable_or_write_node_t *
4527pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4528 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4530 return pm_global_variable_or_write_node_new(
4534 PM_LOCATION_INIT_NODES(target, value),
4535 pm_global_variable_write_name(parser, target),
4537 TOK2LOC(parser, operator),
4545static pm_global_variable_read_node_t *
4546pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4547 return pm_global_variable_read_node_new(
4551 PM_LOCATION_INIT_TOKEN(parser, name),
4552 pm_parser_constant_id_token(parser, name)
4559static pm_global_variable_read_node_t *
4560pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4561 return pm_global_variable_read_node_new(
4565 PM_LOCATION_INIT_UNSET,
4573static pm_global_variable_write_node_t *
4574pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4575 return pm_global_variable_write_node_new(
4578 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4579 PM_LOCATION_INIT_NODES(target, value),
4580 pm_global_variable_write_name(parser, target),
4583 TOK2LOC(parser, operator)
4590static pm_global_variable_write_node_t *
4591pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4592 return pm_global_variable_write_node_new(
4596 PM_LOCATION_INIT_UNSET,
4598 ((pm_location_t) { 0 }),
4600 ((pm_location_t) { 0 })
4607static pm_hash_node_t *
4608pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4609 assert(opening != NULL);
4611 return pm_hash_node_new(
4614 PM_NODE_FLAG_STATIC_LITERAL,
4615 PM_LOCATION_INIT_TOKEN(parser, opening),
4616 TOK2LOC(parser, opening),
4617 ((pm_node_list_t) { 0 }),
4618 ((pm_location_t) { 0 })
4625static PRISM_INLINE void
4626pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
4627 pm_node_list_append(arena, &hash->elements, element);
4629 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4630 if (static_literal) {
4631 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4632 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);
4633 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4634 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4637 if (!static_literal) {
4638 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4642static PRISM_INLINE void
4643pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
4644 PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
4645 hash->closing_loc = TOK2LOC(parser, token);
4651static pm_if_node_t *
4652pm_if_node_create(pm_parser_t *parser,
4653 const pm_token_t *if_keyword,
4654 pm_node_t *predicate,
4655 const pm_token_t *then_keyword,
4656 pm_statements_node_t *statements,
4657 pm_node_t *subsequent,
4658 const pm_token_t *end_keyword
4660 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4662 uint32_t start = PM_TOKEN_START(parser, if_keyword);
4665 if (end_keyword != NULL) {
4666 end = PM_TOKEN_END(parser, end_keyword);
4667 } else if (subsequent != NULL) {
4668 end = PM_NODE_END(subsequent);
4669 } else if (pm_statements_node_body_length(statements) != 0) {
4670 end = PM_NODE_END(statements);
4672 end = PM_NODE_END(predicate);
4675 return pm_if_node_new(
4678 PM_NODE_FLAG_NEWLINE,
4679 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4680 TOK2LOC(parser, if_keyword),
4682 NTOK2LOC(parser, then_keyword),
4685 NTOK2LOC(parser, end_keyword)
4692static pm_if_node_t *
4693pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4694 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4696 pm_statements_node_t *statements = pm_statements_node_create(parser);
4697 pm_statements_node_body_append(parser, statements, statement, true);
4699 return pm_if_node_new(
4702 PM_NODE_FLAG_NEWLINE,
4703 PM_LOCATION_INIT_NODES(statement, predicate),
4704 TOK2LOC(parser, if_keyword),
4706 ((pm_location_t) { 0 }),
4709 ((pm_location_t) { 0 })
4716static pm_if_node_t *
4717pm_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) {
4718 pm_assert_value_expression(parser, predicate);
4719 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4721 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4722 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4724 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4725 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4727 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
4728 return pm_if_node_new(
4731 PM_NODE_FLAG_NEWLINE,
4732 PM_LOCATION_INIT_NODES(predicate, false_expression),
4733 ((pm_location_t) { 0 }),
4735 TOK2LOC(parser, qmark),
4738 ((pm_location_t) { 0 })
4742static PRISM_INLINE void
4743pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
4744 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4745 node->end_keyword_loc = TOK2LOC(parser, keyword);
4748static PRISM_INLINE void
4749pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
4750 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4751 node->end_keyword_loc = TOK2LOC(parser, keyword);
4757static pm_implicit_node_t *
4758pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4759 return pm_implicit_node_new(
4763 PM_LOCATION_INIT_NODE(value),
4771static pm_implicit_rest_node_t *
4772pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4773 assert(token->type == PM_TOKEN_COMMA);
4775 return pm_implicit_rest_node_new(
4779 PM_LOCATION_INIT_TOKEN(parser, token)
4786static pm_integer_node_t *
4787pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4788 assert(token->type == PM_TOKEN_INTEGER);
4790 pm_integer_node_t *node = pm_integer_node_new(
4793 base | PM_NODE_FLAG_STATIC_LITERAL,
4794 PM_LOCATION_INIT_TOKEN(parser, token),
4795 ((pm_integer_t) { 0 })
4798 if (parser->integer.lexed) {
4799 // The value was already computed during lexing.
4800 node->value.value = parser->integer.value;
4801 parser->integer.lexed = false;
4803 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4805 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4806 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4807 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4808 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4809 default: assert(false && "unreachable"); break;
4812 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4813 pm_integer_arena_move(parser->arena, &node->value);
4823static pm_imaginary_node_t *
4824pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4825 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4827 return pm_imaginary_node_new(
4830 PM_NODE_FLAG_STATIC_LITERAL,
4831 PM_LOCATION_INIT_TOKEN(parser, token),
4832 UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4833 .type = PM_TOKEN_INTEGER,
4834 .start = token->start,
4835 .end = token->end - 1
4844static pm_rational_node_t *
4845pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4846 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4848 pm_rational_node_t *node = pm_rational_node_new(
4851 base | PM_NODE_FLAG_STATIC_LITERAL,
4852 PM_LOCATION_INIT_TOKEN(parser, token),
4853 ((pm_integer_t) { 0 }),
4854 ((pm_integer_t) { .value = 1 })
4857 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4859 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4860 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4861 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4862 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4863 default: assert(false && "unreachable"); break;
4866 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4867 pm_integer_arena_move(parser->arena, &node->numerator);
4876static pm_imaginary_node_t *
4877pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4878 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4880 return pm_imaginary_node_new(
4883 PM_NODE_FLAG_STATIC_LITERAL,
4884 PM_LOCATION_INIT_TOKEN(parser, token),
4885 UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4886 .type = PM_TOKEN_INTEGER_RATIONAL,
4887 .start = token->start,
4888 .end = token->end - 1
4896static pm_in_node_t *
4897pm_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) {
4898 uint32_t start = PM_TOKEN_START(parser, in_keyword);
4901 if (statements != NULL) {
4902 end = PM_NODE_END(statements);
4903 } else if (then_keyword != NULL) {
4904 end = PM_TOKEN_END(parser, then_keyword);
4906 end = PM_NODE_END(pattern);
4909 return pm_in_node_new(
4913 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4916 TOK2LOC(parser, in_keyword),
4917 NTOK2LOC(parser, then_keyword)
4924static pm_instance_variable_and_write_node_t *
4925pm_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) {
4926 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4928 return pm_instance_variable_and_write_node_new(
4932 PM_LOCATION_INIT_NODES(target, value),
4934 target->base.location,
4935 TOK2LOC(parser, operator),
4943static pm_instance_variable_operator_write_node_t *
4944pm_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) {
4945 return pm_instance_variable_operator_write_node_new(
4949 PM_LOCATION_INIT_NODES(target, value),
4951 target->base.location,
4952 TOK2LOC(parser, operator),
4954 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4961static pm_instance_variable_or_write_node_t *
4962pm_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) {
4963 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4965 return pm_instance_variable_or_write_node_new(
4969 PM_LOCATION_INIT_NODES(target, value),
4971 target->base.location,
4972 TOK2LOC(parser, operator),
4980static pm_instance_variable_read_node_t *
4981pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4982 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4984 return pm_instance_variable_read_node_new(
4988 PM_LOCATION_INIT_TOKEN(parser, token),
4989 pm_parser_constant_id_token(parser, token)
4997static pm_instance_variable_write_node_t *
4998pm_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) {
4999 return pm_instance_variable_write_node_new(
5002 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5003 PM_LOCATION_INIT_NODES(read_node, value),
5005 read_node->base.location,
5007 TOK2LOC(parser, operator)
5017pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5018 switch (PM_NODE_TYPE(part)) {
5019 case PM_STRING_NODE:
5020 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5022 case PM_EMBEDDED_STATEMENTS_NODE: {
5023 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5024 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5026 if (embedded == NULL) {
5027 // If there are no statements or more than one statement, then
5028 // we lose the static literal flag.
5029 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5030 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5031 // If the embedded statement is a string, then we can keep the
5032 // static literal flag and mark the string as frozen.
5033 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5034 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5035 // If the embedded statement is an interpolated string and it's
5036 // a static literal, then we can keep the static literal flag.
5038 // Otherwise we lose the static literal flag.
5039 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5044 case PM_EMBEDDED_VARIABLE_NODE:
5045 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5048 assert(false && "unexpected node type");
5052 pm_node_list_append(arena, parts, part);
5058static pm_interpolated_regular_expression_node_t *
5059pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5060 return pm_interpolated_regular_expression_node_new(
5063 PM_NODE_FLAG_STATIC_LITERAL,
5064 PM_LOCATION_INIT_TOKEN(parser, opening),
5065 TOK2LOC(parser, opening),
5066 ((pm_node_list_t) { 0 }),
5067 TOK2LOC(parser, opening)
5071static PRISM_INLINE void
5072pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5073 if (PM_NODE_START(node) > PM_NODE_START(part)) {
5074 PM_NODE_START_SET_NODE(node, part);
5076 if (PM_NODE_END(node) < PM_NODE_END(part)) {
5077 PM_NODE_LENGTH_SET_NODE(node, part);
5080 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5083static PRISM_INLINE void
5084pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5085 node->closing_loc = TOK2LOC(parser, closing);
5086 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5087 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
5113static PRISM_INLINE void
5114pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
5115 pm_arena_t *arena = parser->arena;
5116#define CLEAR_FLAGS(node) \
5117 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))
5119#define MUTABLE_FLAGS(node) \
5120 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5122 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5123 PM_NODE_START_SET_NODE(node, part);
5126 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5127 PM_NODE_LENGTH_SET_NODE(node, part);
5130 switch (PM_NODE_TYPE(part)) {
5131 case PM_STRING_NODE:
5132 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5133 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5134 // as long as this interpolation only consists of other string literals.
5135 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5136 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5138 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5140 case PM_INTERPOLATED_STRING_NODE:
5141 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5142 // If the string that we're concatenating is a static literal,
5143 // then we can keep the static literal flag for this string.
5145 // Otherwise, we lose the static literal flag here and we should
5146 // also clear the mutability flags.
5150 case PM_EMBEDDED_STATEMENTS_NODE: {
5151 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5152 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5154 if (embedded == NULL) {
5155 // If we're embedding multiple statements or no statements, then
5156 // the string is not longer a static literal.
5158 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5159 // If the embedded statement is a string, then we can make that
5160 // string as frozen and static literal, and not touch the static
5161 // literal status of this string.
5162 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5164 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5165 MUTABLE_FLAGS(node);
5167 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5168 // If the embedded statement is an interpolated string, but that
5169 // string is marked as static literal, then we can keep our
5170 // static literal status for this string.
5171 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5172 MUTABLE_FLAGS(node);
5175 // In all other cases, we lose the static literal flag here and
5182 case PM_EMBEDDED_VARIABLE_NODE:
5183 // Embedded variables clear static literal, which means we also
5184 // should clear the mutability flags.
5187 case PM_X_STRING_NODE:
5188 case PM_INTERPOLATED_X_STRING_NODE:
5189 case PM_SYMBOL_NODE:
5190 case PM_INTERPOLATED_SYMBOL_NODE:
5191 // These will only happen in error cases. But we want to handle it
5192 // here so that we don't fail the assertion.
5194 pm_node_list_append(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
5196 case PM_ERROR_RECOVERY_NODE:
5200 assert(false && "unexpected node type");
5204 pm_node_list_append(arena, &node->parts, part);
5213static pm_interpolated_string_node_t *
5214pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5215 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5217 switch (parser->frozen_string_literal) {
5218 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5219 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5221 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5222 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5226 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5227 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5229 pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
5233 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5234 NTOK2LOC(parser, opening),
5235 ((pm_node_list_t) { 0 }),
5236 NTOK2LOC(parser, closing)
5239 if (parts != NULL) {
5241 PM_NODE_LIST_FOREACH(parts, index, part) {
5242 pm_interpolated_string_node_append(parser, node, part);
5253pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5254 node->closing_loc = TOK2LOC(parser, closing);
5255 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5259pm_interpolated_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5260 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5261 PM_NODE_START_SET_NODE(node, part);
5264 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5266 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5267 PM_NODE_LENGTH_SET_NODE(node, part);
5272pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5273 node->closing_loc = TOK2LOC(parser, closing);
5274 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5280static pm_interpolated_symbol_node_t *
5281pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5282 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5283 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5285 pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
5288 PM_NODE_FLAG_STATIC_LITERAL,
5289 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5290 NTOK2LOC(parser, opening),
5291 ((pm_node_list_t) { 0 }),
5292 NTOK2LOC(parser, closing)
5295 if (parts != NULL) {
5297 PM_NODE_LIST_FOREACH(parts, index, part) {
5298 pm_interpolated_symbol_node_append(parser->arena, node, part);
5308static pm_interpolated_x_string_node_t *
5309pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5310 return pm_interpolated_x_string_node_new(
5314 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5315 TOK2LOC(parser, opening),
5316 ((pm_node_list_t) { 0 }),
5317 TOK2LOC(parser, closing)
5321static PRISM_INLINE void
5322pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5323 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5324 PM_NODE_LENGTH_SET_NODE(node, part);
5327static PRISM_INLINE void
5328pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5329 node->closing_loc = TOK2LOC(parser, closing);
5330 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5336static pm_it_local_variable_read_node_t *
5337pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5338 return pm_it_local_variable_read_node_new(
5342 PM_LOCATION_INIT_TOKEN(parser, name)
5349static pm_it_parameters_node_t *
5350pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5351 return pm_it_parameters_node_new(
5355 PM_LOCATION_INIT_TOKENS(parser, opening, closing)
5362static pm_keyword_hash_node_t *
5363pm_keyword_hash_node_create(pm_parser_t *parser) {
5364 return pm_keyword_hash_node_new(
5367 PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5368 PM_LOCATION_INIT_UNSET,
5369 ((pm_node_list_t) { 0 })
5377pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *hash, pm_node_t *element) {
5378 // If the element being added is not an AssocNode or does not have a symbol
5379 // key, then we want to turn the SYMBOL_KEYS flag off.
5380 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5381 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5384 pm_node_list_append(arena, &hash->elements, element);
5385 if (PM_NODE_LENGTH(hash) == 0) {
5386 PM_NODE_START_SET_NODE(hash, element);
5388 PM_NODE_LENGTH_SET_NODE(hash, element);
5394static pm_required_keyword_parameter_node_t *
5395pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5396 return pm_required_keyword_parameter_node_new(
5400 PM_LOCATION_INIT_TOKEN(parser, name),
5401 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5402 TOK2LOC(parser, name)
5409static pm_optional_keyword_parameter_node_t *
5410pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5411 return pm_optional_keyword_parameter_node_new(
5415 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5416 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5417 TOK2LOC(parser, name),
5425static pm_keyword_rest_parameter_node_t *
5426pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5427 return pm_keyword_rest_parameter_node_new(
5431 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
5432 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
5433 NTOK2LOC(parser, name),
5434 TOK2LOC(parser, operator)
5441static pm_lambda_node_t *
5442pm_lambda_node_create(
5443 pm_parser_t *parser,
5444 pm_constant_id_list_t *locals,
5445 const pm_token_t *operator,
5446 const pm_token_t *opening,
5447 const pm_token_t *closing,
5448 pm_node_t *parameters,
5451 return pm_lambda_node_new(
5455 PM_LOCATION_INIT_TOKENS(parser, operator, closing),
5457 TOK2LOC(parser, operator),
5458 TOK2LOC(parser, opening),
5459 TOK2LOC(parser, closing),
5468static pm_local_variable_and_write_node_t *
5469pm_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) {
5470 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));
5471 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5473 return pm_local_variable_and_write_node_new(
5477 PM_LOCATION_INIT_NODES(target, value),
5479 TOK2LOC(parser, operator),
5489static pm_local_variable_operator_write_node_t *
5490pm_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) {
5491 return pm_local_variable_operator_write_node_new(
5495 PM_LOCATION_INIT_NODES(target, value),
5497 TOK2LOC(parser, operator),
5500 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
5508static pm_local_variable_or_write_node_t *
5509pm_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) {
5510 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));
5511 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5513 return pm_local_variable_or_write_node_new(
5517 PM_LOCATION_INIT_NODES(target, value),
5519 TOK2LOC(parser, operator),
5529static pm_local_variable_read_node_t *
5530pm_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) {
5531 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5533 return pm_local_variable_read_node_new(
5537 PM_LOCATION_INIT_TOKEN(parser, name),
5546static pm_local_variable_read_node_t *
5547pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5548 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5549 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5556static pm_local_variable_read_node_t *
5557pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5558 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5559 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5565static pm_local_variable_write_node_t *
5566pm_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) {
5567 return pm_local_variable_write_node_new(
5570 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5571 ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
5576 TOK2LOC(parser, operator)
5583static PRISM_INLINE bool
5584pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5585 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5592static PRISM_INLINE bool
5593pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
5596 (parser->start[start] == '_') &&
5597 (parser->start[start + 1] != '0') &&
5598 pm_char_is_decimal_digit(parser->start[start + 1])
5606static PRISM_INLINE void
5607pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
5608 if (pm_token_is_numbered_parameter(parser, start, length)) {
5609 PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
5617static pm_local_variable_target_node_t *
5618pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5619 pm_refute_numbered_parameter(parser, location->start, location->length);
5621 return pm_local_variable_target_node_new(
5625 ((pm_location_t) { .start = location->start, .length = location->length }),
5634static pm_match_predicate_node_t *
5635pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5636 pm_assert_value_expression(parser, value);
5638 return pm_match_predicate_node_new(
5642 PM_LOCATION_INIT_NODES(value, pattern),
5645 TOK2LOC(parser, operator)
5652static pm_match_required_node_t *
5653pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5654 pm_assert_value_expression(parser, value);
5656 return pm_match_required_node_new(
5660 PM_LOCATION_INIT_NODES(value, pattern),
5663 TOK2LOC(parser, operator)
5670static pm_match_write_node_t *
5671pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5672 return pm_match_write_node_new(
5676 PM_LOCATION_INIT_NODE(call),
5678 ((pm_node_list_t) { 0 })
5685static pm_module_node_t *
5686pm_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) {
5687 pm_constant_id_list_t module_locals = { .ids = NULL, .size = 0, .capacity = 0 };
5688 if (locals != NULL) module_locals = *locals;
5690 return pm_module_node_new(
5694 PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
5696 TOK2LOC(parser, module_keyword),
5699 TOK2LOC(parser, end_keyword),
5700 pm_parser_constant_id_token(parser, name)
5707static pm_multi_target_node_t *
5708pm_multi_target_node_create(pm_parser_t *parser) {
5709 return pm_multi_target_node_new(
5713 PM_LOCATION_INIT_UNSET,
5714 ((pm_node_list_t) { 0 }),
5716 ((pm_node_list_t) { 0 }),
5717 ((pm_location_t) { 0 }),
5718 ((pm_location_t) { 0 })
5726pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5727 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5728 if (node->rest == NULL) {
5729 node->rest = target;
5731 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5732 pm_node_list_append(parser->arena, &node->rights, target);
5734 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5735 if (node->rest == NULL) {
5736 node->rest = target;
5738 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5739 pm_node_list_append(parser->arena, &node->rights, target);
5741 } else if (node->rest == NULL) {
5742 pm_node_list_append(parser->arena, &node->lefts, target);
5744 pm_node_list_append(parser->arena, &node->rights, target);
5747 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
5748 PM_NODE_START_SET_NODE(node, target);
5751 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
5752 PM_NODE_LENGTH_SET_NODE(node, target);
5760pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
5761 PM_NODE_START_SET_TOKEN(parser, node, lparen);
5762 PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
5763 node->lparen_loc = TOK2LOC(parser, lparen);
5770pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
5771 PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
5772 node->rparen_loc = TOK2LOC(parser, rparen);
5778static pm_multi_write_node_t *
5779pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5780 /* The target is no longer necessary because we have reused its children. It
5781 * is arena-allocated so no explicit free is needed. */
5782 return pm_multi_write_node_new(
5785 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5786 PM_LOCATION_INIT_NODES(target, value),
5792 TOK2LOC(parser, operator),
5800static pm_next_node_t *
5801pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5802 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5804 return pm_next_node_new(
5808 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
5810 TOK2LOC(parser, keyword)
5817static pm_nil_node_t *
5818pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5819 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5821 return pm_nil_node_new(
5824 PM_NODE_FLAG_STATIC_LITERAL,
5825 PM_LOCATION_INIT_TOKEN(parser, token)
5832static pm_no_block_parameter_node_t *
5833pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5834 assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5835 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5837 return pm_no_block_parameter_node_new(
5841 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5842 TOK2LOC(parser, operator),
5843 TOK2LOC(parser, keyword)
5850static pm_no_keywords_parameter_node_t *
5851pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5852 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5853 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5855 return pm_no_keywords_parameter_node_new(
5859 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5860 TOK2LOC(parser, operator),
5861 TOK2LOC(parser, keyword)
5868static pm_numbered_parameters_node_t *
5869pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
5870 return pm_numbered_parameters_node_new(
5874 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5883#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5892pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5893 const uint8_t *start = token->start + 1;
5894 const uint8_t *end = token->end;
5896 ptrdiff_t diff = end - start;
5898#if PTRDIFF_MAX > SIZE_MAX
5899 assert(diff < (ptrdiff_t) SIZE_MAX);
5901 size_t length = (size_t) diff;
5903 char *digits = xcalloc(length + 1, sizeof(char));
5904 memcpy(digits, start, length);
5905 digits[length] = '\0';
5909 unsigned long value = strtoul(digits, &endptr, 10);
5911 if ((digits == endptr) || (*endptr != '\0')) {
5912 pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
5916 xfree_sized(digits, sizeof(char) * (length + 1));
5918 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5919 PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5923 return (uint32_t) value;
5931static pm_numbered_reference_read_node_t *
5932pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5933 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5935 return pm_numbered_reference_read_node_new(
5939 PM_LOCATION_INIT_TOKEN(parser, name),
5940 pm_numbered_reference_read_node_number(parser, name)
5947static pm_optional_parameter_node_t *
5948pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5949 return pm_optional_parameter_node_new(
5953 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5954 pm_parser_constant_id_token(parser, name),
5955 TOK2LOC(parser, name),
5956 TOK2LOC(parser, operator),
5964static pm_or_node_t *
5965pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5966 pm_assert_value_expression(parser, left);
5968 return pm_or_node_new(
5972 PM_LOCATION_INIT_NODES(left, right),
5975 TOK2LOC(parser, operator)
5982static pm_parameters_node_t *
5983pm_parameters_node_create(pm_parser_t *parser) {
5984 return pm_parameters_node_new(
5988 PM_LOCATION_INIT_UNSET,
5989 ((pm_node_list_t) { 0 }),
5990 ((pm_node_list_t) { 0 }),
5992 ((pm_node_list_t) { 0 }),
5993 ((pm_node_list_t) { 0 }),
6003pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6004 if ((params->base.location.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
6005 PM_NODE_START_SET_NODE(params, param);
6008 if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
6009 PM_NODE_LENGTH_SET_NODE(params, param);
6017pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6018 pm_parameters_node_location_set(params, param);
6019 pm_node_list_append(arena, ¶ms->requireds, param);
6026pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6027 pm_parameters_node_location_set(params, UP(param));
6028 pm_node_list_append(arena, ¶ms->optionals, UP(param));
6035pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6036 pm_parameters_node_location_set(params, param);
6037 pm_node_list_append(arena, ¶ms->posts, param);
6044pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6045 pm_parameters_node_location_set(params, param);
6046 params->rest = param;
6053pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6054 pm_parameters_node_location_set(params, param);
6055 pm_node_list_append(arena, ¶ms->keywords, param);
6062pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6063 assert(params->keyword_rest == NULL);
6064 pm_parameters_node_location_set(params, param);
6065 params->keyword_rest = param;
6072pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
6073 assert(params->block == NULL);
6074 pm_parameters_node_location_set(params, param);
6075 params->block = param;
6081static pm_program_node_t *
6082pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6083 return pm_program_node_new(
6087 PM_LOCATION_INIT_NODE(statements),
6096static pm_parentheses_node_t *
6097pm_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) {
6098 return pm_parentheses_node_new(
6102 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6104 TOK2LOC(parser, opening),
6105 TOK2LOC(parser, closing)
6112static pm_pinned_expression_node_t *
6113pm_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) {
6114 return pm_pinned_expression_node_new(
6118 PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
6120 TOK2LOC(parser, operator),
6121 TOK2LOC(parser, lparen),
6122 TOK2LOC(parser, rparen)
6129static pm_pinned_variable_node_t *
6130pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6131 return pm_pinned_variable_node_new(
6135 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
6137 TOK2LOC(parser, operator)
6144static pm_post_execution_node_t *
6145pm_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) {
6146 return pm_post_execution_node_new(
6150 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6152 TOK2LOC(parser, keyword),
6153 TOK2LOC(parser, opening),
6154 TOK2LOC(parser, closing)
6161static pm_pre_execution_node_t *
6162pm_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) {
6163 return pm_pre_execution_node_new(
6167 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6169 TOK2LOC(parser, keyword),
6170 TOK2LOC(parser, opening),
6171 TOK2LOC(parser, closing)
6178static pm_range_node_t *
6179pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6180 pm_assert_value_expression(parser, left);
6181 pm_assert_value_expression(parser, right);
6182 pm_node_flags_t flags = 0;
6184 // Indicate that this node is an exclusive range if the operator is `...`.
6185 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6186 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6189 // Indicate that this node is a static literal (i.e., can be compiled with
6190 // a putobject in CRuby) if the left and right are implicit nil, explicit
6191 // nil, or integers.
6193 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6194 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6196 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6199 uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
6200 uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
6202 return pm_range_node_new(
6206 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6209 TOK2LOC(parser, operator)
6216static pm_redo_node_t *
6217pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6218 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6220 return pm_redo_node_new(
6224 PM_LOCATION_INIT_TOKEN(parser, token)
6232static pm_regular_expression_node_t *
6233pm_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) {
6234 return pm_regular_expression_node_new(
6237 pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6238 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6239 TOK2LOC(parser, opening),
6240 TOK2LOC(parser, content),
6241 TOK2LOC(parser, closing),
6249static PRISM_INLINE pm_regular_expression_node_t *
6250pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6251 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6257static pm_required_parameter_node_t *
6258pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6259 return pm_required_parameter_node_new(
6263 PM_LOCATION_INIT_TOKEN(parser, token),
6264 pm_parser_constant_id_token(parser, token)
6271static pm_rescue_modifier_node_t *
6272pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6273 return pm_rescue_modifier_node_new(
6277 PM_LOCATION_INIT_NODES(expression, rescue_expression),
6279 TOK2LOC(parser, keyword),
6287static pm_rescue_node_t *
6288pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6289 return pm_rescue_node_new(
6293 PM_LOCATION_INIT_TOKEN(parser, keyword),
6294 TOK2LOC(parser, keyword),
6295 ((pm_node_list_t) { 0 }),
6296 ((pm_location_t) { 0 }),
6298 ((pm_location_t) { 0 }),
6304static PRISM_INLINE void
6305pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
6306 node->operator_loc = TOK2LOC(parser, operator);
6313pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6314 node->reference = reference;
6315 PM_NODE_LENGTH_SET_NODE(node, reference);
6322pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6323 node->statements = statements;
6324 if (pm_statements_node_body_length(statements) > 0) {
6325 PM_NODE_LENGTH_SET_NODE(node, statements);
6333pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6334 node->subsequent = subsequent;
6335 PM_NODE_LENGTH_SET_NODE(node, subsequent);
6342pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
6343 pm_node_list_append(arena, &node->exceptions, exception);
6344 PM_NODE_LENGTH_SET_NODE(node, exception);
6350static pm_rest_parameter_node_t *
6351pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6352 return pm_rest_parameter_node_new(
6356 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
6357 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
6358 NTOK2LOC(parser, name),
6359 TOK2LOC(parser, operator)
6366static pm_retry_node_t *
6367pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6368 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6370 return pm_retry_node_new(
6374 PM_LOCATION_INIT_TOKEN(parser, token)
6381static pm_return_node_t *
6382pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6383 return pm_return_node_new(
6387 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
6388 TOK2LOC(parser, keyword),
6396static pm_self_node_t *
6397pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6398 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6400 return pm_self_node_new(
6404 PM_LOCATION_INIT_TOKEN(parser, token)
6411static pm_shareable_constant_node_t *
6412pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6413 return pm_shareable_constant_node_new(
6416 (pm_node_flags_t) value,
6417 PM_LOCATION_INIT_NODE(write),
6425static pm_singleton_class_node_t *
6426pm_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) {
6427 return pm_singleton_class_node_new(
6431 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
6433 TOK2LOC(parser, class_keyword),
6434 TOK2LOC(parser, operator),
6437 TOK2LOC(parser, end_keyword)
6444static pm_source_encoding_node_t *
6445pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6446 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6448 return pm_source_encoding_node_new(
6451 PM_NODE_FLAG_STATIC_LITERAL,
6452 PM_LOCATION_INIT_TOKEN(parser, token)
6459static pm_source_file_node_t*
6460pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6461 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6463 pm_node_flags_t flags = 0;
6465 switch (parser->frozen_string_literal) {
6466 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6467 flags |= PM_STRING_FLAGS_MUTABLE;
6469 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6470 flags |= PM_STRING_FLAGS_FROZEN;
6471 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
6472 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6477 return pm_source_file_node_new(
6481 PM_LOCATION_INIT_TOKEN(parser, file_keyword),
6489static pm_source_line_node_t *
6490pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6491 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6493 return pm_source_line_node_new(
6496 PM_NODE_FLAG_STATIC_LITERAL,
6497 PM_LOCATION_INIT_TOKEN(parser, token)
6504static pm_splat_node_t *
6505pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6506 return pm_splat_node_new(
6510 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
6511 TOK2LOC(parser, operator),
6519static pm_statements_node_t *
6520pm_statements_node_create(pm_parser_t *parser) {
6521 return pm_statements_node_new(
6525 PM_LOCATION_INIT_UNSET,
6526 ((pm_node_list_t) { 0 })
6534pm_statements_node_body_length(pm_statements_node_t *node) {
6535 return node && node->body.size;
6542static PRISM_INLINE void
6543pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6544 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6545 PM_NODE_START_SET_NODE(node, statement);
6548 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6549 PM_NODE_LENGTH_SET_NODE(node, statement);
6557pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6558 pm_statements_node_body_update(node, statement);
6560 if (node->body.size > 0) {
6561 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6563 switch (PM_NODE_TYPE(previous)) {
6568 case PM_RETURN_NODE:
6569 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6576 pm_node_list_append(parser->arena, &node->body, statement);
6577 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6584pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
6585 pm_statements_node_body_update(node, statement);
6586 pm_node_list_prepend(arena, &node->body, statement);
6587 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6593static PRISM_INLINE pm_string_node_t *
6594pm_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) {
6595 pm_node_flags_t flags = 0;
6597 switch (parser->frozen_string_literal) {
6598 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6599 flags = PM_STRING_FLAGS_MUTABLE;
6601 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6602 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6606 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6607 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6609 return pm_string_node_new(
6613 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6614 NTOK2LOC(parser, opening),
6615 TOK2LOC(parser, content),
6616 NTOK2LOC(parser, closing),
6624static pm_string_node_t *
6625pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6626 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6633static pm_string_node_t *
6634pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6635 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6636 parser->current_string = PM_STRING_EMPTY;
6643static pm_super_node_t *
6644pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6645 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6647 const pm_location_t *end = pm_arguments_end(arguments);
6648 assert(end != NULL && "unreachable");
6650 return pm_super_node_new(
6654 ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
6655 TOK2LOC(parser, keyword),
6656 arguments->opening_loc,
6657 arguments->arguments,
6658 arguments->closing_loc,
6668pm_ascii_only_p(const pm_string_t *contents) {
6669 const size_t length = pm_string_length(contents);
6670 const uint8_t *source = pm_string_source(contents);
6672 for (size_t index = 0; index < length; index++) {
6673 if (source[index] & 0x80) return false;
6683parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6684 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6685 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6688 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6701parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6702 const pm_encoding_t *encoding = parser->encoding;
6704 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6705 size_t width = encoding->char_width(cursor, end - cursor);
6708 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6725static PRISM_INLINE pm_node_flags_t
6726parse_symbol_encoding(pm_parser_t *parser, const pm_encoding_t *explicit_encoding, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6727 if (explicit_encoding != NULL) {
6728 // A Symbol may optionally have its encoding explicitly set. This will
6729 // happen if an escape sequence results in a non-ASCII code point.
6730 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6731 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6732 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6733 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6734 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6735 } else if (validate) {
6736 parse_symbol_encoding_validate_other(parser, location, contents);
6738 } else if (pm_ascii_only_p(contents)) {
6739 // Ruby stipulates that all source files must use an ASCII-compatible
6740 // encoding. Thus, all symbols appearing in source are eligible for
6741 // "downgrading" to US-ASCII.
6742 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6743 } else if (validate) {
6744 parse_symbol_encoding_validate_other(parser, location, contents);
6754static pm_symbol_node_t *
6755pm_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) {
6756 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6757 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6759 return pm_symbol_node_new(
6762 PM_NODE_FLAG_STATIC_LITERAL | flags,
6763 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6764 NTOK2LOC(parser, opening),
6765 NTOK2LOC(parser, value),
6766 NTOK2LOC(parser, closing),
6774static PRISM_INLINE pm_symbol_node_t *
6775pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6776 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6782static pm_symbol_node_t *
6783pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6784 pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, parser->explicit_encoding, value, &parser->current_string, false));
6785 parser->current_string = PM_STRING_EMPTY;
6792static pm_symbol_node_t *
6793pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6794 assert(token->type == PM_TOKEN_LABEL);
6796 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6797 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6798 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6800 assert((label.end - label.start) >= 0);
6801 pm_string_shared_init(&node->unescaped, label.start, label.end);
6802 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, parser->explicit_encoding, &label, &node->unescaped, false));
6810static pm_symbol_node_t *
6811pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6812 pm_symbol_node_t *node = pm_symbol_node_new(
6815 PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
6816 PM_LOCATION_INIT_UNSET,
6817 ((pm_location_t) { 0 }),
6818 ((pm_location_t) { 0 }),
6819 ((pm_location_t) { 0 }),
6820 ((pm_string_t) { 0 })
6823 pm_string_constant_init(&node->unescaped, content, strlen(content));
6831pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6832 const pm_location_t *location = NULL;
6834 switch (PM_NODE_TYPE(node)) {
6835 case PM_SYMBOL_NODE: {
6836 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6837 if (cast->closing_loc.length > 0) {
6838 location = &cast->closing_loc;
6842 case PM_INTERPOLATED_SYMBOL_NODE: {
6843 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6844 if (cast->closing_loc.length > 0) {
6845 location = &cast->closing_loc;
6853 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6859static pm_symbol_node_t *
6860pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6861 pm_symbol_node_t *new_node = pm_symbol_node_new(
6864 PM_NODE_FLAG_STATIC_LITERAL,
6865 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6866 TOK2LOC(parser, opening),
6868 TOK2LOC(parser, closing),
6872 pm_token_t content = {
6873 .type = PM_TOKEN_IDENTIFIER,
6874 .start = parser->start + node->content_loc.start,
6875 .end = parser->start + node->content_loc.start + node->content_loc.length
6878 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, parser->explicit_encoding, &content, &node->unescaped, true));
6880 /* The old node is arena-allocated so no explicit free is needed. */
6887static pm_string_node_t *
6888pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6889 pm_node_flags_t flags = 0;
6891 switch (parser->frozen_string_literal) {
6892 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6893 flags = PM_STRING_FLAGS_MUTABLE;
6895 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6896 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6900 pm_string_node_t *new_node = pm_string_node_new(
6904 PM_LOCATION_INIT_NODE(node),
6911 /* The old node is arena-allocated so no explicit free is needed. */
6918static pm_true_node_t *
6919pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6920 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6922 return pm_true_node_new(
6925 PM_NODE_FLAG_STATIC_LITERAL,
6926 PM_LOCATION_INIT_TOKEN(parser, token)
6933static pm_true_node_t *
6934pm_true_node_synthesized_create(pm_parser_t *parser) {
6935 return pm_true_node_new(
6938 PM_NODE_FLAG_STATIC_LITERAL,
6939 PM_LOCATION_INIT_UNSET
6946static pm_undef_node_t *
6947pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6948 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6950 return pm_undef_node_new(
6954 PM_LOCATION_INIT_TOKEN(parser, token),
6955 ((pm_node_list_t) { 0 }),
6956 TOK2LOC(parser, token)
6964pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6965 PM_NODE_LENGTH_SET_NODE(node, name);
6966 pm_node_list_append(arena, &node->names, name);
6972static pm_unless_node_t *
6973pm_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) {
6974 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6975 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6977 return pm_unless_node_new(
6980 PM_NODE_FLAG_NEWLINE,
6981 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
6982 TOK2LOC(parser, keyword),
6984 NTOK2LOC(parser, then_keyword),
6987 ((pm_location_t) { 0 })
6994static pm_unless_node_t *
6995pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6996 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6998 pm_statements_node_t *statements = pm_statements_node_create(parser);
6999 pm_statements_node_body_append(parser, statements, statement, true);
7001 return pm_unless_node_new(
7004 PM_NODE_FLAG_NEWLINE,
7005 PM_LOCATION_INIT_NODES(statement, predicate),
7006 TOK2LOC(parser, unless_keyword),
7008 ((pm_location_t) { 0 }),
7011 ((pm_location_t) { 0 })
7015static PRISM_INLINE void
7016pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
7017 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
7018 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
7027pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7028 assert(parser->current_block_exits != NULL);
7030 // All of the block exits that we want to remove should be within the
7031 // statements, and since we are modifying the statements, we shouldn't have
7032 // to check the end location.
7033 uint32_t start = statements->base.location.start;
7035 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7036 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7037 if (block_exit->location.start < start) break;
7039 // Implicitly remove from the list by lowering the size.
7040 parser->current_block_exits->size--;
7047static pm_until_node_t *
7048pm_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) {
7049 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7051 return pm_until_node_new(
7055 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7056 TOK2LOC(parser, keyword),
7057 NTOK2LOC(parser, do_keyword),
7058 TOK2LOC(parser, closing),
7067static pm_until_node_t *
7068pm_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) {
7069 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7070 pm_loop_modifier_block_exits(parser, statements);
7072 return pm_until_node_new(
7076 PM_LOCATION_INIT_NODES(statements, predicate),
7077 TOK2LOC(parser, keyword),
7078 ((pm_location_t) { 0 }),
7079 ((pm_location_t) { 0 }),
7088static pm_when_node_t *
7089pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7090 return pm_when_node_new(
7094 PM_LOCATION_INIT_TOKEN(parser, keyword),
7095 TOK2LOC(parser, keyword),
7096 ((pm_node_list_t) { 0 }),
7097 ((pm_location_t) { 0 }),
7106pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
7107 PM_NODE_LENGTH_SET_NODE(node, condition);
7108 pm_node_list_append(arena, &node->conditions, condition);
7114static PRISM_INLINE void
7115pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
7116 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
7117 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
7124pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7125 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
7126 PM_NODE_LENGTH_SET_NODE(node, statements);
7129 node->statements = statements;
7135static pm_while_node_t *
7136pm_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) {
7137 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7139 return pm_while_node_new(
7143 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7144 TOK2LOC(parser, keyword),
7145 NTOK2LOC(parser, do_keyword),
7146 TOK2LOC(parser, closing),
7155static pm_while_node_t *
7156pm_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) {
7157 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7158 pm_loop_modifier_block_exits(parser, statements);
7160 return pm_while_node_new(
7164 PM_LOCATION_INIT_NODES(statements, predicate),
7165 TOK2LOC(parser, keyword),
7166 ((pm_location_t) { 0 }),
7167 ((pm_location_t) { 0 }),
7176static pm_while_node_t *
7177pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7178 return pm_while_node_new(
7182 PM_LOCATION_INIT_UNSET,
7183 ((pm_location_t) { 0 }),
7184 ((pm_location_t) { 0 }),
7185 ((pm_location_t) { 0 }),
7195static pm_x_string_node_t *
7196pm_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) {
7197 return pm_x_string_node_new(
7200 PM_STRING_FLAGS_FROZEN,
7201 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
7202 TOK2LOC(parser, opening),
7203 TOK2LOC(parser, content),
7204 TOK2LOC(parser, closing),
7212static PRISM_INLINE pm_x_string_node_t *
7213pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7214 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7220static pm_yield_node_t *
7221pm_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) {
7222 uint32_t start = PM_TOKEN_START(parser, keyword);
7225 if (rparen_loc->length > 0) {
7226 end = PM_LOCATION_END(rparen_loc);
7227 } else if (arguments != NULL) {
7228 end = PM_NODE_END(arguments);
7229 } else if (lparen_loc->length > 0) {
7230 end = PM_LOCATION_END(lparen_loc);
7232 end = PM_TOKEN_END(parser, keyword);
7235 return pm_yield_node_new(
7239 ((pm_location_t) { .start = start, .length = U32(end - start) }),
7240 TOK2LOC(parser, keyword),
7252pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7253 pm_scope_t *scope = parser->current_scope;
7256 while (scope != NULL) {
7257 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7258 if (scope->closed) break;
7260 scope = scope->previous;
7272static PRISM_INLINE int
7273pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7274 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7280static PRISM_INLINE void
7281pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7282 pm_locals_write(&parser->metadata_arena, &parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
7288static pm_constant_id_t
7289pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7290 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
7291 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7298static PRISM_INLINE pm_constant_id_t
7299pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
7300 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
7306static PRISM_INLINE pm_constant_id_t
7307pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7308 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
7314static pm_constant_id_t
7315pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7316 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7317 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7324static pm_constant_id_t
7325pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7326 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7327 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7339pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7340 // We want to check whether the parameter name is a numbered parameter or
7342 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7344 // Otherwise we'll fetch the constant id for the parameter name and check
7345 // whether it's already in the current scope.
7346 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7348 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7349 // Add an error if the parameter doesn't start with _ and has been seen before
7350 if ((name->start < name->end) && (*name->start != '_')) {
7351 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7362pm_parser_scope_pop(pm_parser_t *parser) {
7363 pm_scope_t *scope = parser->current_scope;
7364 parser->current_scope = scope->previous;
7365 scope->previous = parser->free_scopes;
7366 parser->free_scopes = scope;
7369/******************************************************************************/
7371/******************************************************************************/
7376static PRISM_INLINE void
7377pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7378 *stack = (*stack << 1) | (value & 1);
7384static PRISM_INLINE void
7385pm_state_stack_pop(pm_state_stack_t *stack) {
7392static PRISM_INLINE bool
7393pm_state_stack_p(const pm_state_stack_t *stack) {
7397static PRISM_INLINE void
7398pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7399 // Use the negation of the value to prevent stack overflow.
7400 pm_state_stack_push(&parser->accepts_block_stack, !value);
7403static PRISM_INLINE void
7404pm_accepts_block_stack_pop(pm_parser_t *parser) {
7405 pm_state_stack_pop(&parser->accepts_block_stack);
7408static PRISM_INLINE bool
7409pm_accepts_block_stack_p(pm_parser_t *parser) {
7410 return !pm_state_stack_p(&parser->accepts_block_stack);
7413static PRISM_INLINE void
7414pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7415 pm_state_stack_push(&parser->do_loop_stack, value);
7418static PRISM_INLINE void
7419pm_do_loop_stack_pop(pm_parser_t *parser) {
7420 pm_state_stack_pop(&parser->do_loop_stack);
7423static PRISM_INLINE bool
7424pm_do_loop_stack_p(pm_parser_t *parser) {
7425 return pm_state_stack_p(&parser->do_loop_stack);
7457static PRISM_INLINE void
7458pm_enclosure_frame_push(pm_parser_t *parser) {
7459 pm_do_loop_stack_push(parser, false);
7460 pm_accepts_block_stack_push(parser, true);
7463static PRISM_INLINE void
7464pm_enclosure_frame_pop(pm_parser_t *parser) {
7465 pm_do_loop_stack_pop(parser);
7466 pm_accepts_block_stack_pop(parser);
7469/******************************************************************************/
7470/* Lexer check helpers */
7471/******************************************************************************/
7477static PRISM_INLINE uint8_t
7478peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7479 if (cursor < parser->end) {
7491static PRISM_INLINE uint8_t
7492peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7493 return peek_at(parser, parser->current.end + offset);
7500static PRISM_INLINE uint8_t
7501peek(const pm_parser_t *parser) {
7502 return peek_at(parser, parser->current.end);
7509static PRISM_INLINE bool
7510match(pm_parser_t *parser, uint8_t value) {
7511 if (peek(parser) == value) {
7512 parser->current.end++;
7522static PRISM_INLINE size_t
7523match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7524 if (peek_at(parser, cursor) == '\n') {
7527 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7538static PRISM_INLINE size_t
7539match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7540 return match_eol_at(parser, parser->current.end + offset);
7548static PRISM_INLINE size_t
7549match_eol(pm_parser_t *parser) {
7550 return match_eol_at(parser, parser->current.end);
7556static PRISM_INLINE const uint8_t *
7557next_newline(const uint8_t *cursor, ptrdiff_t length) {
7558 assert(length >= 0);
7560 // Note that it's okay for us to use memchr here to look for \n because none
7561 // of the encodings that we support have \n as a component of a multi-byte
7563 return memchr(cursor, '\n', (size_t) length);
7569static PRISM_INLINE bool
7570ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7571 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));
7579parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7580 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7582 if (encoding != NULL) {
7583 if (parser->encoding != encoding) {
7584 parser->encoding = encoding;
7585 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7588 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7600parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7601 const uint8_t *cursor = parser->current.start + 1;
7602 const uint8_t *end = parser->current.end;
7604 bool separator = false;
7606 if (end - cursor <= 6) return;
7607 switch (cursor[6]) {
7608 case 'C': case 'c': cursor += 6; continue;
7609 case 'O': case 'o': cursor += 5; continue;
7610 case 'D': case 'd': cursor += 4; continue;
7611 case 'I': case 'i': cursor += 3; continue;
7612 case 'N': case 'n': cursor += 2; continue;
7613 case 'G': case 'g': cursor += 1; continue;
7620 if (pm_char_is_whitespace(*cursor)) break;
7623 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7629 if (++cursor >= end) return;
7630 } while (pm_char_is_whitespace(*cursor));
7632 if (separator) break;
7633 if (*cursor != '=' && *cursor != ':') return;
7639 const uint8_t *value_start = cursor;
7640 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7642 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7643 // If we were unable to parse the encoding value, then we've got an
7644 // issue because we didn't understand the encoding that the user was
7645 // trying to use. In this case we'll keep using the default encoding but
7646 // add an error to the parser to indicate an unsuccessful parse.
7647 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7652 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7653 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7654 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7655} pm_magic_comment_boolean_value_t;
7661static pm_magic_comment_boolean_value_t
7662parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7663 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7664 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7665 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7666 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7668 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7672static PRISM_INLINE bool
7673pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7674 return b == '\'' || b == '"' || b == ':' || b == ';';
7683parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7687 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1,
'*', (
size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7688 if (cursor[-1] ==
'-' && cursor + 1 < end && cursor[1] ==
'-') {
7706parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7709 const uint8_t *start = parser->current.start + 1;
7710 const uint8_t *end = parser->current.end;
7711 if (end - start <= 7)
return false;
7713 const uint8_t *cursor;
7714 bool indicator =
false;
7716 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7719 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7731 if (pm_memchr(start,
':', (
size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
7737 start += pm_strspn_whitespace(start, end - start);
7741 while (cursor < end) {
7743 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7746 const uint8_t *key_start = cursor;
7747 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7749 const uint8_t *key_end = cursor;
7750 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7751 if (cursor == end)
break;
7753 if (*cursor ==
':') {
7756 if (!indicator)
return false;
7760 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7761 if (cursor == end)
break;
7763 const uint8_t *value_start;
7764 const uint8_t *value_end;
7766 if (*cursor ==
'"') {
7767 value_start = ++cursor;
7768 for (; cursor < end && *cursor !=
'"'; cursor++) {
7769 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7772 if (cursor < end && *cursor ==
'"') cursor++;
7774 value_start = cursor;
7775 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7780 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7782 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7783 if (cursor != end)
return false;
7789 const size_t key_length = (size_t) (key_end - key_start);
7790 const uint8_t *dash = pm_memchr(key_start,
'-', key_length, parser->encoding_changed, parser->encoding);
7793 pm_string_shared_init(&key, key_start, key_end);
7795 uint8_t *buffer =
xmalloc(key_length);
7796 if (buffer == NULL)
break;
7798 memcpy(buffer, key_start, key_length);
7799 buffer[dash - key_start] =
'_';
7801 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7802 buffer[dash - key_start] =
'_';
7805 pm_string_owned_init(&key, buffer, key_length);
7810 const uint8_t *key_source = pm_string_source(&key);
7811 uint32_t value_length = (uint32_t) (value_end - value_start);
7815 if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7817 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7818 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7820 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7824 if (key_length == 11) {
7825 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7826 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7827 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7828 PM_PARSER_WARN_TOKEN_FORMAT(
7831 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7833 (
const char *) key_source,
7835 (
const char *) value_start
7838 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7839 parser->warn_mismatched_indentation =
false;
7841 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7842 parser->warn_mismatched_indentation =
true;
7846 }
else if (key_length == 21) {
7847 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7850 if (semantic_token_seen) {
7851 pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7853 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7854 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7855 PM_PARSER_WARN_TOKEN_FORMAT(
7858 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7860 (
const char *) key_source,
7862 (
const char *) value_start
7865 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7868 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7874 }
else if (key_length == 24) {
7875 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7876 const uint8_t *cursor = parser->current.start;
7877 while ((cursor > parser->start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7879 if (!((cursor == parser->start) || (cursor[-1] ==
'\n'))) {
7880 pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7881 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7882 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7883 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7884 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7885 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7886 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7887 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7888 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7890 PM_PARSER_WARN_TOKEN_FORMAT(
7893 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7895 (
const char *) key_source,
7897 (
const char *) value_start
7905 pm_string_cleanup(&key);
7922static const uint32_t context_terminators[] = {
7923 [PM_CONTEXT_NONE] = 0,
7924 [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7925 [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7926 [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7927 [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7928 [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7929 [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7930 [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7931 [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7932 [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
7933 [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7934 [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7935 [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7936 [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7937 [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7938 [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7939 [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7940 [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7941 [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7942 [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7943 [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7944 [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
7945 [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
7946 [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7947 [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
7948 [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7949 [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
7950 [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
7951 [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
7952 [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7953 [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7954 [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7955 [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7956 [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7957 [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7958 [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
7959 [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
7960 [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7961 [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7962 [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7963 [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7964 [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
7965 [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7966 [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7967 [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7968 [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7969 [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
7970 [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7971 [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7972 [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7973 [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7974 [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
7975 [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7976 [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
7977 [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
7981context_terminator(pm_context_t context,
pm_token_t *token) {
7982 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7993 while (context_node != NULL) {
7994 if (context_terminator(context_node->context, token))
return context_node->context;
7995 context_node = context_node->prev;
7998 return PM_CONTEXT_NONE;
8001PM_STATIC_ASSERT(__LINE__, PM_CONTEXT_MAXIMUM <= 64,
"Expected every context to fit in the context mask.");
8004context_push(
pm_parser_t *parser, pm_context_t context) {
8006 if (context_node != NULL) {
8007 parser->free_contexts = context_node->prev;
8016 .mask = (previous == NULL ? 0 : previous->mask) | ((uint64_t) 1 << context)
8019 parser->current_context = context_node;
8026 parser->current_context = context_node->prev;
8027 context_node->prev = parser->free_contexts;
8028 parser->free_contexts = context_node;
8032context_p(
const pm_parser_t *parser, pm_context_t context) {
8033 return parser->current_context != NULL && (parser->current_context->mask & ((uint64_t) 1 << context)) != 0;
8040 while (context_node != NULL) {
8041 switch (context_node->context) {
8042 case PM_CONTEXT_DEF:
8043 case PM_CONTEXT_DEF_PARAMS:
8044 case PM_CONTEXT_DEF_ENSURE:
8045 case PM_CONTEXT_DEF_RESCUE:
8046 case PM_CONTEXT_DEF_ELSE:
8048 case PM_CONTEXT_CLASS:
8049 case PM_CONTEXT_CLASS_ENSURE:
8050 case PM_CONTEXT_CLASS_RESCUE:
8051 case PM_CONTEXT_CLASS_ELSE:
8052 case PM_CONTEXT_MODULE:
8053 case PM_CONTEXT_MODULE_ENSURE:
8054 case PM_CONTEXT_MODULE_RESCUE:
8055 case PM_CONTEXT_MODULE_ELSE:
8056 case PM_CONTEXT_SCLASS:
8057 case PM_CONTEXT_SCLASS_ENSURE:
8058 case PM_CONTEXT_SCLASS_RESCUE:
8059 case PM_CONTEXT_SCLASS_ELSE:
8062 context_node = context_node->prev;
8074context_human(pm_context_t context) {
8076 case PM_CONTEXT_NONE:
8077 case PM_CONTEXT_MAXIMUM:
8078 assert(
false &&
"unreachable");
8080 case PM_CONTEXT_BEGIN:
return "begin statement";
8081 case PM_CONTEXT_BLOCK_BRACES:
return "'{'..'}' block";
8082 case PM_CONTEXT_BLOCK_KEYWORDS:
return "'do'..'end' block";
8083 case PM_CONTEXT_BLOCK_PARAMETERS:
return "'|'..'|' block parameter";
8084 case PM_CONTEXT_CASE_WHEN:
return "'when' clause";
8085 case PM_CONTEXT_CASE_IN:
return "'in' clause";
8086 case PM_CONTEXT_CLASS:
return "class definition";
8087 case PM_CONTEXT_DEF:
return "method definition";
8088 case PM_CONTEXT_DEF_PARAMS:
return "method parameters";
8089 case PM_CONTEXT_DEFAULT_PARAMS:
return "parameter default value";
8090 case PM_CONTEXT_DEFINED:
return "'defined?' expression";
8091 case PM_CONTEXT_ELSE:
8092 case PM_CONTEXT_BEGIN_ELSE:
8093 case PM_CONTEXT_BLOCK_ELSE:
8094 case PM_CONTEXT_CLASS_ELSE:
8095 case PM_CONTEXT_DEF_ELSE:
8096 case PM_CONTEXT_LAMBDA_ELSE:
8097 case PM_CONTEXT_MODULE_ELSE:
8098 case PM_CONTEXT_SCLASS_ELSE:
return "'else' clause";
8099 case PM_CONTEXT_ELSIF:
return "'elsif' clause";
8100 case PM_CONTEXT_EMBEXPR:
return "embedded expression";
8101 case PM_CONTEXT_BEGIN_ENSURE:
8102 case PM_CONTEXT_BLOCK_ENSURE:
8103 case PM_CONTEXT_CLASS_ENSURE:
8104 case PM_CONTEXT_DEF_ENSURE:
8105 case PM_CONTEXT_LAMBDA_ENSURE:
8106 case PM_CONTEXT_MODULE_ENSURE:
8107 case PM_CONTEXT_SCLASS_ENSURE:
return "'ensure' clause";
8108 case PM_CONTEXT_FOR:
return "for loop";
8109 case PM_CONTEXT_FOR_INDEX:
return "for loop index";
8110 case PM_CONTEXT_IF:
return "if statement";
8111 case PM_CONTEXT_LAMBDA_BRACES:
return "'{'..'}' lambda block";
8112 case PM_CONTEXT_LAMBDA_DO_END:
return "'do'..'end' lambda block";
8113 case PM_CONTEXT_LOOP_PREDICATE:
return "loop predicate";
8114 case PM_CONTEXT_MAIN:
return "top level context";
8115 case PM_CONTEXT_MODULE:
return "module definition";
8116 case PM_CONTEXT_MULTI_TARGET:
return "multiple targets";
8117 case PM_CONTEXT_PARENS:
return "parentheses";
8118 case PM_CONTEXT_POSTEXE:
return "'END' block";
8119 case PM_CONTEXT_PREDICATE:
return "predicate";
8120 case PM_CONTEXT_PREEXE:
return "'BEGIN' block";
8121 case PM_CONTEXT_BEGIN_RESCUE:
8122 case PM_CONTEXT_BLOCK_RESCUE:
8123 case PM_CONTEXT_CLASS_RESCUE:
8124 case PM_CONTEXT_DEF_RESCUE:
8125 case PM_CONTEXT_LAMBDA_RESCUE:
8126 case PM_CONTEXT_MODULE_RESCUE:
8127 case PM_CONTEXT_RESCUE_MODIFIER:
8128 case PM_CONTEXT_SCLASS_RESCUE:
return "'rescue' clause";
8129 case PM_CONTEXT_SCLASS:
return "singleton class definition";
8130 case PM_CONTEXT_TERNARY:
return "ternary expression";
8131 case PM_CONTEXT_UNLESS:
return "unless statement";
8132 case PM_CONTEXT_UNTIL:
return "until statement";
8133 case PM_CONTEXT_WHILE:
return "while statement";
8136 assert(
false &&
"unreachable");
8145pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8146 if (invalid != NULL) {
8147 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8148 pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
8153pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8154 const uint8_t *invalid = NULL;
8155 size_t length = pm_strspn_binary_number(
string, parser->end -
string, &invalid);
8156 pm_strspn_number_validate(parser,
string, length, invalid);
8161pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8162 const uint8_t *invalid = NULL;
8163 size_t length = pm_strspn_octal_number(
string, parser->end -
string, &invalid);
8164 pm_strspn_number_validate(parser,
string, length, invalid);
8169pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8170 const uint8_t *invalid = NULL;
8171 size_t length = pm_strspn_decimal_number(
string, parser->end -
string, &invalid);
8172 pm_strspn_number_validate(parser,
string, length, invalid);
8177pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8178 const uint8_t *invalid = NULL;
8179 size_t length = pm_strspn_hexadecimal_number(
string, parser->end -
string, &invalid);
8180 pm_strspn_number_validate(parser,
string, length, invalid);
8184static pm_token_type_t
8185lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8186 pm_token_type_t
type = PM_TOKEN_INTEGER;
8190 if (peek(parser) ==
'.') {
8191 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8192 parser->current.end += 2;
8193 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8194 type = PM_TOKEN_FLOAT;
8204 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8205 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8206 parser->current.end += 2;
8208 if (pm_char_is_decimal_digit(peek(parser))) {
8209 parser->current.end++;
8210 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8212 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8214 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8215 parser->current.end++;
8216 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8222 type = PM_TOKEN_FLOAT;
8228static pm_token_type_t
8229lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8230 pm_token_type_t
type = PM_TOKEN_INTEGER;
8233 if (peek_offset(parser, -1) ==
'0') {
8234 switch (*parser->current.end) {
8238 parser->current.end++;
8239 if (pm_char_is_decimal_digit(peek(parser))) {
8240 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8243 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8251 parser->current.end++;
8252 if (pm_char_is_binary_digit(peek(parser))) {
8253 parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
8256 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8259 parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
8265 parser->current.end++;
8266 if (pm_char_is_octal_digit(peek(parser))) {
8267 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8270 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8273 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8286 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8287 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8293 parser->current.end++;
8294 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8295 parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
8298 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8301 parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8306 type = lex_optional_float_suffix(parser, seen_e);
8313 type = lex_optional_float_suffix(parser, seen_e);
8322 const uint8_t *cursor = parser->current.end;
8323 const uint8_t *end = parser->end;
8324 uint64_t value = (uint64_t) (cursor[-1] -
'0');
8326 bool has_underscore =
false;
8327 bool prev_underscore =
false;
8328 const uint8_t *invalid = NULL;
8330 while (cursor < end) {
8331 uint8_t c = *cursor;
8332 if (c >=
'0' && c <=
'9') {
8333 if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c -
'0');
8334 prev_underscore =
false;
8336 }
else if (c ==
'_') {
8337 has_underscore =
true;
8338 if (prev_underscore && invalid == NULL) invalid = cursor;
8339 prev_underscore =
true;
8346 if (has_underscore) {
8347 if (prev_underscore && invalid == NULL) invalid = cursor - 1;
8348 pm_strspn_number_validate(parser, parser->current.end, (
size_t) (cursor - parser->current.end), invalid);
8351 if (value <= UINT32_MAX) {
8352 parser->integer.value = (uint32_t) value;
8353 parser->integer.lexed =
true;
8356 parser->current.end = cursor;
8364 uint8_t next = peek(parser);
8365 if (next ==
'.' || next ==
'e' || next ==
'E') {
8366 type = lex_optional_float_suffix(parser, seen_e);
8370 if (
type != PM_TOKEN_INTEGER) {
8371 parser->integer.lexed =
false;
8380 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8381 const uint8_t *fraction_start = parser->current.end;
8382 const uint8_t *fraction_end = parser->current.end + 2;
8383 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
8384 pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
8390static pm_token_type_t
8392 pm_token_type_t
type = PM_TOKEN_INTEGER;
8393 parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8394 parser->integer.lexed =
false;
8396 if (parser->current.end < parser->end) {
8397 bool seen_e =
false;
8398 type = lex_numeric_prefix(parser, &seen_e);
8400 const uint8_t *end = parser->current.end;
8401 pm_token_type_t suffix_type =
type;
8403 if (
type == PM_TOKEN_INTEGER) {
8404 if (match(parser,
'r')) {
8405 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8407 if (match(parser,
'i')) {
8408 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8410 }
else if (match(parser,
'i')) {
8411 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8414 if (!seen_e && match(parser,
'r')) {
8415 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8417 if (match(parser,
'i')) {
8418 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8420 }
else if (match(parser,
'i')) {
8421 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8425 const uint8_t b = peek(parser);
8426 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8427 parser->current.end = end;
8436static pm_token_type_t
8438 if (parser->current.end >= parser->end) {
8439 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8440 return PM_TOKEN_GLOBAL_VARIABLE;
8445 bool allow_multiple =
true;
8447 switch (*parser->current.end) {
8464 parser->current.end++;
8465 return PM_TOKEN_GLOBAL_VARIABLE;
8471 parser->current.end++;
8472 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8475 parser->current.end++;
8478 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8480 parser->current.end += width;
8481 }
while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8484 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;
8485 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
8488 return PM_TOKEN_GLOBAL_VARIABLE;
8500 parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
8501 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8504 parser->current.end++;
8505 allow_multiple =
false;
8510 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8512 parser->current.end += width;
8513 }
while (allow_multiple && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8514 }
else if (pm_char_is_whitespace(peek(parser))) {
8517 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8521 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;
8522 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8523 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);
8526 return PM_TOKEN_GLOBAL_VARIABLE;
8544 pm_lex_state_t state;
8547 pm_token_type_t
type;
8551 pm_token_type_t modifier_type;
8557#define PM_KEYWORD_LENGTH_MAXIMUM 12
8563#define PM_KEYWORD_PACK(first, middle, last, length) \
8564 ((uint32_t) (first) | ((uint32_t) (middle) << 8) | ((uint32_t) (last) << 16) | ((uint32_t) (length) << 24))
8570#define PM_KEYWORD_SLOT_BITS 6
8585#define PM_KEYWORD_SLOT(packed) ((uint32_t) ((uint32_t) (packed) * 0x75f796ddU) >> (32 - PM_KEYWORD_SLOT_BITS))
8591#define PM_KEYWORD(name, first, middle, last, state, type, modifier_type) \
8592 [PM_KEYWORD_SLOT(PM_KEYWORD_PACK(first, middle, last, sizeof(name) - 1))] = { name, PM_KEYWORD_PACK(first, middle, last, sizeof(name) - 1), state, type, modifier_type }
8599static const pm_keyword_t pm_keywords[1 << PM_KEYWORD_SLOT_BITS] = {
8600 PM_KEYWORD(
"do",
'd',
'o',
'o', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF),
8601 PM_KEYWORD(
"if",
'i',
'f',
'f', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IF, PM_TOKEN_KEYWORD_IF_MODIFIER),
8602 PM_KEYWORD(
"in",
'i',
'n',
'n', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF),
8603 PM_KEYWORD(
"or",
'o',
'r',
'r', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_OR, PM_TOKEN_EOF),
8604 PM_KEYWORD(
"and",
'a',
'n',
'd', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF),
8605 PM_KEYWORD(
"def",
'd',
'e',
'f', PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF),
8606 PM_KEYWORD(
"end",
'e',
'n',
'd', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF),
8607 PM_KEYWORD(
"END",
'E',
'N',
'D', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF),
8608 PM_KEYWORD(
"for",
'f',
'o',
'r', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF),
8609 PM_KEYWORD(
"nil",
'n',
'i',
'l', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF),
8610 PM_KEYWORD(
"not",
'n',
'o',
't', PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_NOT, PM_TOKEN_EOF),
8611 PM_KEYWORD(
"case",
'c',
's',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF),
8612 PM_KEYWORD(
"else",
'e',
's',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF),
8613 PM_KEYWORD(
"next",
'n',
'x',
't', PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF),
8614 PM_KEYWORD(
"redo",
'r',
'd',
'o', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF),
8615 PM_KEYWORD(
"self",
's',
'l',
'f', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF),
8616 PM_KEYWORD(
"then",
't',
'e',
'n', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF),
8617 PM_KEYWORD(
"true",
't',
'u',
'e', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF),
8618 PM_KEYWORD(
"when",
'w',
'e',
'n', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_EOF),
8619 PM_KEYWORD(
"alias",
'a',
'i',
's', PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_ALIAS, PM_TOKEN_EOF),
8620 PM_KEYWORD(
"begin",
'b',
'g',
'n', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF),
8621 PM_KEYWORD(
"BEGIN",
'B',
'G',
'N', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF),
8622 PM_KEYWORD(
"break",
'b',
'e',
'k', PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF),
8623 PM_KEYWORD(
"class",
'c',
'a',
's', PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF),
8624 PM_KEYWORD(
"elsif",
'e',
's',
'f', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF),
8625 PM_KEYWORD(
"false",
'f',
'l',
'e', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF),
8626 PM_KEYWORD(
"retry",
'r',
't',
'y', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF),
8627 PM_KEYWORD(
"super",
's',
'p',
'r', PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF),
8628 PM_KEYWORD(
"undef",
'u',
'd',
'f', PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_UNDEF, PM_TOKEN_EOF),
8629 PM_KEYWORD(
"until",
'u',
't',
'l', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNTIL, PM_TOKEN_KEYWORD_UNTIL_MODIFIER),
8630 PM_KEYWORD(
"while",
'w',
'i',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHILE, PM_TOKEN_KEYWORD_WHILE_MODIFIER),
8631 PM_KEYWORD(
"yield",
'y',
'e',
'd', PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_YIELD, PM_TOKEN_EOF),
8632 PM_KEYWORD(
"ensure",
'e',
'u',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF),
8633 PM_KEYWORD(
"module",
'm',
'u',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF),
8634 PM_KEYWORD(
"rescue",
'r',
'c',
'e', PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_RESCUE_MODIFIER),
8635 PM_KEYWORD(
"return",
'r',
'u',
'n', PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF),
8636 PM_KEYWORD(
"unless",
'u',
'e',
's', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNLESS, PM_TOKEN_KEYWORD_UNLESS_MODIFIER),
8637 PM_KEYWORD(
"defined?",
'd',
'n',
'?', PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF),
8638 PM_KEYWORD(
"__LINE__",
'_',
'N',
'_', PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF),
8639 PM_KEYWORD(
"__FILE__",
'_',
'L',
'_', PM_LEX_STATE_END, PM_TOKEN_KEYWORD___FILE__, PM_TOKEN_EOF),
8640 PM_KEYWORD(
"__ENCODING__",
'_',
'D',
'_', PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)
8650pm_keyword_find(
const uint8_t *start,
const uint8_t *end) {
8651 ptrdiff_t width = end - start;
8652 if (width < 2 || width > PM_KEYWORD_LENGTH_MAXIMUM)
return NULL;
8654 size_t uwidth = (size_t) width;
8655 uint32_t packed = PM_KEYWORD_PACK(start[0], start[uwidth >> 1], start[uwidth - 1], uwidth);
8657 const pm_keyword_t *keyword = &pm_keywords[PM_KEYWORD_SLOT(packed)];
8658 return (keyword->packed == packed && memcmp(start + 1, keyword->name + 1, uwidth - 2) == 0) ? keyword : NULL;
8666pm_keyword_p(
const uint8_t *start,
const uint8_t *end) {
8667 return pm_keyword_find(start, end) != NULL;
8670static pm_token_type_t
8671lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8673 const uint8_t *end = parser->end;
8674 const uint8_t *current_start = parser->current.start;
8675 const uint8_t *current_end = parser->current.end;
8676 bool encoding_changed = parser->encoding_changed;
8678 if (encoding_changed) {
8680 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8681 current_end += width;
8685 current_end += scan_identifier_ascii(current_end, end);
8689 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8690 current_end += width;
8694 parser->current.end = current_end;
8698 bool method_name =
false;
8700 if (current_end < end) {
8701 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8707 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8708 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8712 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8713 (void) match(parser,
':');
8717 parser->explicit_encoding = NULL;
8718 return PM_TOKEN_LABEL;
8722 }
else 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,
'=')) {
8725 return PM_TOKEN_IDENTIFIER;
8727 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8728 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8732 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8733 (void) match(parser,
':');
8737 parser->explicit_encoding = NULL;
8738 return PM_TOKEN_LABEL;
8742 if (parser->lex_state != PM_LEX_STATE_DOT) {
8746 pm_lex_state_t previous_lex_state = parser->lex_state;
8747 const pm_keyword_t *keyword = pm_keyword_find(current_start, current_end);
8749 if (keyword != NULL) {
8750 if (previous_lex_state & PM_LEX_STATE_FNAME) {
8751 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8753 lex_state_set(parser, keyword->state);
8754 if (keyword->state == PM_LEX_STATE_BEG) {
8755 parser->command_start =
true;
8758 if ((keyword->modifier_type != PM_TOKEN_EOF) && !(previous_lex_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8759 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8760 return keyword->modifier_type;
8764 if (keyword->type == PM_TOKEN_KEYWORD_DO) {
8769 if (previous_lex_state & PM_LEX_STATE_FNAME) {
8770 return PM_TOKEN_KEYWORD_DO;
8772 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
8783 parser->lambda_enclosure_nesting = -1;
8784 return PM_TOKEN_KEYWORD_DO_LAMBDA;
8786 if (pm_do_loop_stack_p(parser)) {
8787 return PM_TOKEN_KEYWORD_DO_LOOP;
8789 if (!pm_accepts_block_stack_p(parser)) {
8790 return PM_TOKEN_KEYWORD_DO_BLOCK;
8792 return PM_TOKEN_KEYWORD_DO;
8795 return keyword->type;
8800 return PM_TOKEN_METHOD_NAME;
8803 if (encoding_changed) {
8804 return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8810 if (*current_start < 0x80) {
8811 return (*current_start >=
'A' && *current_start <=
'Z') ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8813 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8822 return (parser->current.start == parser->start) || (parser->current.start[-1] ==
'\n');
8839static pm_token_type_t
8840lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8843 if (pound + 1 >= parser->end) {
8844 parser->current.end = pound + 1;
8845 return PM_TOKEN_STRING_CONTENT;
8854 if (pound + 2 >= parser->end) {
8855 parser->current.end = pound + 1;
8856 return PM_TOKEN_STRING_CONTENT;
8861 const uint8_t *variable = pound + 2;
8862 if (*variable ==
'@' && pound + 3 < parser->end) variable++;
8864 if (char_is_identifier_start(parser, variable, parser->end - variable)) {
8868 if (pound > parser->current.start) {
8869 parser->current.end = pound;
8870 return PM_TOKEN_STRING_CONTENT;
8875 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8876 parser->current.end = pound + 1;
8877 return PM_TOKEN_EMBVAR;
8883 parser->current.end = pound + 1;
8889 if (pound + 2 >= parser->end) {
8890 parser->current.end = pound + 1;
8891 return PM_TOKEN_STRING_CONTENT;
8897 const uint8_t *check = pound + 2;
8899 if (pound[2] ==
'-') {
8900 if (pound + 3 >= parser->end) {
8901 parser->current.end = pound + 2;
8902 return PM_TOKEN_STRING_CONTENT;
8913 char_is_identifier_start(parser, check, parser->end - check) ||
8914 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8919 if (pound > parser->current.start) {
8920 parser->current.end = pound;
8921 return PM_TOKEN_STRING_CONTENT;
8926 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8927 parser->current.end = pound + 1;
8928 return PM_TOKEN_EMBVAR;
8933 parser->current.end = pound + 1;
8939 if (pound > parser->current.start) {
8940 parser->current.end = pound;
8941 return PM_TOKEN_STRING_CONTENT;
8944 parser->enclosure_nesting++;
8948 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8949 parser->current.end = pound + 2;
8950 parser->command_start =
true;
8951 pm_enclosure_frame_push(parser);
8952 return PM_TOKEN_EMBEXPR_BEGIN;
8957 parser->current.end = pound + 1;
8962static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8963static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8964static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8965static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8966static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8971static const bool ascii_printable_chars[] = {
8972 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8973 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8974 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8975 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8976 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8977 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8978 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8979 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8983char_is_ascii_printable(
const uint8_t b) {
8984 return (b < 0x80) && ascii_printable_chars[b];
8992escape_hexadecimal_digit(
const uint8_t value) {
8993 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
9002escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const pm_location_t *error_location,
const uint8_t flags) {
9004 for (
size_t index = 0; index < length; index++) {
9005 if (index != 0) value <<= 4;
9006 value |= escape_hexadecimal_digit(
string[index]);
9011 if (value >= 0xD800 && value <= 0xDFFF) {
9012 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9015 }
else if (error_location != NULL) {
9016 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
9018 pm_parser_err(parser, U32(
string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
9030escape_byte(uint8_t value,
const uint8_t flags) {
9031 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9032 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9040escape_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) {
9044 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9045 if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
9046 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9050 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
9054 parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
9057 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9058 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9062 pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
9065 pm_buffer_append_byte(buffer, 0xEF);
9066 pm_buffer_append_byte(buffer, 0xBF);
9067 pm_buffer_append_byte(buffer, 0xBD);
9078 if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
9079 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9083 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
9087 parser->explicit_encoding = parser->encoding;
9090 pm_buffer_append_byte(buffer,
byte);
9110 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9111 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9114 escape_write_byte_encoded(parser, buffer, flags,
byte);
9123 if (parser->encoding_changed) {
9124 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9126 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9130 if (parser->heredoc_end == NULL && *parser->current.end ==
'\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
9131 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
9132 }
else if (width > 1) {
9134 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9135 pm_buffer_append_bytes(b, parser->current.end, width);
9136 parser->current.end += width;
9140 parser->current.end++;
9141 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9151escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9152#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9154 PM_PARSER_WARN_TOKEN_FORMAT(
9157 PM_WARN_INVALID_CHARACTER,
9171 uint8_t peeked = peek(parser);
9174 parser->current.end++;
9175 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9179 parser->current.end++;
9180 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9184 parser->current.end++;
9185 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9189 parser->current.end++;
9190 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9194 parser->current.end++;
9195 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9199 parser->current.end++;
9200 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9204 parser->current.end++;
9205 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9209 parser->current.end++;
9210 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9214 parser->current.end++;
9215 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9219 parser->current.end++;
9220 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9224 parser->current.end++;
9225 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9228 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9229 uint8_t value = (uint8_t) (*parser->current.end -
'0');
9230 parser->current.end++;
9232 if (pm_char_is_octal_digit(peek(parser))) {
9233 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9234 parser->current.end++;
9236 if (pm_char_is_octal_digit(peek(parser))) {
9237 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9238 parser->current.end++;
9242 value = escape_byte(value, flags);
9243 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9247 const uint8_t *start = parser->current.end - 1;
9249 parser->current.end++;
9250 uint8_t
byte = peek(parser);
9252 if (pm_char_is_hexadecimal_digit(
byte)) {
9253 uint8_t value = escape_hexadecimal_digit(
byte);
9254 parser->current.end++;
9256 byte = peek(parser);
9257 if (pm_char_is_hexadecimal_digit(
byte)) {
9258 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9259 parser->current.end++;
9262 value = escape_byte(value, flags);
9263 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9264 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9265 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9267 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9271 escape_write_byte_encoded(parser, buffer, flags, value);
9273 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9279 const uint8_t *start = parser->current.end - 1;
9280 parser->current.end++;
9282 if (parser->current.end == parser->end) {
9283 const uint8_t *start = parser->current.end - 2;
9284 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9285 }
else if (peek(parser) ==
'{') {
9286 const uint8_t *unicode_codepoints_start = parser->current.end - 2;
9287 parser->current.end++;
9291 if ((whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end)) > 0) {
9292 parser->current.end += whitespace;
9293 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9298 parser->current.end += 2;
9304 const uint8_t *extra_codepoints_start = NULL;
9305 int codepoints_count = 0;
9307 while ((parser->current.end < parser->end) && (*parser->current.end !=
'}')) {
9308 const uint8_t *unicode_start = parser->current.end;
9309 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
9311 if (hexadecimal_length > 6) {
9313 pm_parser_err(parser, U32(unicode_start - parser->start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9314 }
else if (hexadecimal_length == 0) {
9317 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9322 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9324 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
9325 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9331 parser->current.end += hexadecimal_length;
9333 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9334 extra_codepoints_start = unicode_start;
9337 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
9338 escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
9340 parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
9345 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9346 pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9349 if (parser->current.end == parser->end) {
9350 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);
9351 }
else if (peek(parser) ==
'}') {
9352 parser->current.end++;
9354 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9359 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9361 pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9365 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9366 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->current.end - unicode_codepoints_start));
9369 size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
9372 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9373 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9375 const uint8_t *start = parser->current.end - 2;
9376 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9378 }
else if (length == 4) {
9379 uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
9381 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9382 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end + 4 - start));
9385 escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
9386 parser->current.end += 4;
9388 parser->current.end += length;
9390 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9394 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9396 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9404 parser->current.end++;
9405 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9406 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9409 if (parser->current.end == parser->end) {
9410 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9414 uint8_t peeked = peek(parser);
9417 parser->current.end++;
9418 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9422 parser->current.end++;
9424 if (match(parser,
'u') || match(parser,
'U')) {
9425 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9429 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9432 parser->current.end++;
9433 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9434 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9437 parser->current.end++;
9438 escape_read_warn(parser, flags, 0,
"\\t");
9439 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9442 if (!char_is_ascii_printable(peeked)) {
9443 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9447 if (parser->heredoc_end == NULL && peeked ==
'\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
9448 parser->current.end++;
9449 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9455 parser->current.end++;
9456 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9457 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9460 if (peek(parser) !=
'-') {
9461 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9462 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9466 parser->current.end++;
9467 if (parser->current.end == parser->end) {
9468 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9472 uint8_t peeked = peek(parser);
9475 parser->current.end++;
9476 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9480 parser->current.end++;
9482 if (match(parser,
'u') || match(parser,
'U')) {
9483 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9487 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9490 parser->current.end++;
9491 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9492 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9495 parser->current.end++;
9496 escape_read_warn(parser, flags, 0,
"\\t");
9497 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9500 if (!char_is_ascii_printable(peeked)) {
9501 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9502 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9506 if (parser->heredoc_end == NULL && peeked ==
'\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
9507 parser->current.end++;
9508 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9514 parser->current.end++;
9515 if (flags & PM_ESCAPE_FLAG_META) {
9516 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9519 if (peek(parser) !=
'-') {
9520 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9521 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9525 parser->current.end++;
9526 if (parser->current.end == parser->end) {
9527 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9531 uint8_t peeked = peek(parser);
9534 parser->current.end++;
9536 if (match(parser,
'u') || match(parser,
'U')) {
9537 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9541 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9544 parser->current.end++;
9545 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9546 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9549 parser->current.end++;
9550 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9551 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9554 if (!char_is_ascii_printable(peeked)) {
9555 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9556 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9560 if (parser->heredoc_end == NULL && peeked ==
'\n') pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
9561 parser->current.end++;
9562 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9567 if (peek_offset(parser, 1) ==
'\n') {
9568 if (parser->heredoc_end == NULL) pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
9569 parser->current.end += 2;
9570 escape_write_byte_encoded(parser, buffer, flags, escape_byte(
'\n', flags));
9576 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9577 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9578 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9581 if (parser->current.end < parser->end) {
9582 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9584 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9616static pm_token_type_t
9618 if (lex_state_end_p(parser)) {
9619 lex_state_set(parser, PM_LEX_STATE_BEG);
9620 return PM_TOKEN_QUESTION_MARK;
9628 parser->explicit_encoding = NULL;
9630 if (parser->current.end >= parser->end) {
9631 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9632 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9633 return PM_TOKEN_CHARACTER_LITERAL;
9636 if (pm_char_is_whitespace(*parser->current.end)) {
9637 lex_state_set(parser, PM_LEX_STATE_BEG);
9638 return PM_TOKEN_QUESTION_MARK;
9641 lex_state_set(parser, PM_LEX_STATE_BEG);
9643 if (match(parser,
'\\')) {
9644 lex_state_set(parser, PM_LEX_STATE_END);
9647 pm_buffer_init(&buffer, 3);
9649 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9652 void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length,
PRISM_ALIGNOF(uint8_t));
9653 pm_string_constant_init(&parser->current_string, (
const char *) arena_data, buffer.length);
9654 pm_buffer_cleanup(&buffer);
9656 return PM_TOKEN_CHARACTER_LITERAL;
9658 size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9663 !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) ==
'_') ||
9665 (parser->current.end + encoding_width >= parser->end) ||
9666 !char_is_identifier(parser, parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
9669 lex_state_set(parser, PM_LEX_STATE_END);
9670 parser->current.end += encoding_width;
9671 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9672 return PM_TOKEN_CHARACTER_LITERAL;
9676 return PM_TOKEN_QUESTION_MARK;
9683static pm_token_type_t
9685 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9686 const uint8_t *end = parser->end;
9689 if ((width = char_is_identifier_start(parser, parser->current.end, end - parser->current.end)) > 0) {
9690 parser->current.end += width;
9692 while ((width = char_is_identifier(parser, parser->current.end, end - parser->current.end)) > 0) {
9693 parser->current.end += width;
9695 }
else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
9696 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9697 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
9698 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9701 size_t width = parser->encoding->char_width(parser->current.end, end - parser->current.end);
9702 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, (
int) ((parser->current.end + width) - parser->current.start), (
const char *) parser->current.start);
9704 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9705 pm_parser_err_token(parser, &parser->current, diag_id);
9710 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
9711 lex_mode_pop(parser);
9722 if (parser->lex_callback.callback) {
9723 parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
9736 .location = TOK2LOC(parser, &parser->current)
9747static pm_token_type_t
9750 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9752 if (newline == NULL) {
9753 parser->current.end = parser->end;
9755 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9756 parser->current.end = newline + 1;
9759 parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
9760 parser_lex_callback(parser);
9763 const uint8_t *comment_start = parser->current.start;
9764 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9768 while (parser->current.end + 4 <= parser->end) {
9769 parser->current.start = parser->current.end;
9774 (memcmp(parser->current.end,
"=end", 4) == 0) &&
9776 (parser->current.end + 4 == parser->end) ||
9777 pm_char_is_whitespace(parser->current.end[4]) ||
9778 (parser->current.end[4] ==
'\0') ||
9779 (parser->current.end[4] ==
'\004') ||
9780 (parser->current.end[4] ==
'\032')
9783 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9785 if (newline == NULL) {
9786 parser->current.end = parser->end;
9788 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9789 parser->current.end = newline + 1;
9792 parser->current.type = PM_TOKEN_EMBDOC_END;
9793 parser_lex_callback(parser);
9795 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9796 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9798 return PM_TOKEN_EMBDOC_END;
9803 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9805 if (newline == NULL) {
9806 parser->current.end = parser->end;
9808 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9809 parser->current.end = newline + 1;
9812 parser->current.type = PM_TOKEN_EMBDOC_LINE;
9813 parser_lex_callback(parser);
9816 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9818 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9819 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9821 return PM_TOKEN_EOF;
9831 parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
9832 parser_lex_callback(parser);
9846 assert(parser->heredoc_end <= parser->end);
9847 parser->next_start = parser->heredoc_end;
9848 parser->heredoc_end = NULL;
9856 const uint8_t *cursor = parser->current.end;
9858 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9859 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9922 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9936 if (parser->encoding_changed) {
9937 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9939 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9944 return (width == 0 ? 1 : width);
9952 size_t width = parser_char_width(parser);
9953 pm_buffer_append_bytes(&token_buffer->
buffer, parser->current.end, width);
9954 parser->current.end += width;
9959 size_t width = parser_char_width(parser);
9960 const uint8_t *start = parser->current.end;
9961 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, width);
9962 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, width);
9963 parser->current.end += width;
9975 size_t len = pm_buffer_length(&token_buffer->
buffer);
9976 void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->
buffer),
len,
PRISM_ALIGNOF(uint8_t));
9977 pm_string_constant_init(&parser->current_string, (
const char *) arena_data,
len);
9978 pm_buffer_cleanup(&token_buffer->
buffer);
9983 pm_token_buffer_copy(parser, &token_buffer->
base);
9998 if (token_buffer->
cursor == NULL) {
9999 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
10001 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->current.end - token_buffer->
cursor));
10002 pm_token_buffer_copy(parser, token_buffer);
10009 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
10011 const uint8_t *cursor = token_buffer->
base.
cursor;
10012 size_t length = (size_t) (parser->current.end - cursor);
10013 pm_buffer_append_bytes(&token_buffer->
base.
buffer, cursor, length);
10014 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, cursor, length);
10015 pm_regexp_token_buffer_copy(parser, token_buffer);
10019#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10031 const uint8_t *start;
10032 if (token_buffer->
cursor == NULL) {
10033 pm_buffer_init(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10034 start = parser->current.start;
10036 start = token_buffer->
cursor;
10039 const uint8_t *end = parser->current.end - 1;
10040 assert(end >= start);
10041 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10043 token_buffer->
cursor = end;
10048 const uint8_t *start;
10050 pm_buffer_init(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10051 pm_buffer_init(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10052 start = parser->current.start;
10057 const uint8_t *end = parser->current.end - 1;
10058 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10059 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10064#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10071pm_heredoc_strspn_inline_whitespace(
pm_parser_t *parser,
const uint8_t **cursor, pm_heredoc_indent_t indent) {
10072 size_t whitespace = 0;
10075 case PM_HEREDOC_INDENT_NONE:
10080 case PM_HEREDOC_INDENT_DASH:
10082 *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
10084 case PM_HEREDOC_INDENT_TILDE:
10087 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10088 if (**cursor ==
'\t') {
10089 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10108 size_t eol_length = match_eol(parser);
10111 if (parser->heredoc_end) {
10115 parser_flush_heredoc_end(parser);
10118 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
10121 uint8_t delimiter = *parser->current.end;
10125 if (eol_length == 2) {
10126 delimiter = *(parser->current.end + 1);
10129 parser->current.end += eol_length;
10133 return *parser->current.end++;
10140#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10150 assert(parser->current.end <= parser->end);
10151 parser->previous = parser->current;
10154 bool previous_command_start = parser->command_start;
10155 parser->command_start =
false;
10159 bool lexed_comment =
false;
10163 unsigned int semantic_token_seen = parser->semantic_token_seen;
10164 parser->semantic_token_seen =
true;
10172 switch (parser->lex_modes.current->mode) {
10173 case PM_LEX_DEFAULT:
10174 case PM_LEX_EMBEXPR:
10175 case PM_LEX_EMBVAR:
10184 if (parser->next_start != NULL) {
10185 parser->current.end = parser->next_start;
10186 parser->next_start = NULL;
10191 bool space_seen =
false;
10196 bool chomping =
true;
10203 static const uint8_t inline_whitespace[256] = {
10204 [
' '] = 1, [
'\t'] = 1, [
'\f'] = 1, [
'\v'] = 1
10206 const uint8_t *scan = parser->current.end;
10207 while (scan < parser->end && inline_whitespace[*scan]) scan++;
10208 if (scan > parser->current.end) {
10209 parser->current.end = scan;
10212 if (scan >= parser->end)
break;
10215 switch (*parser->current.end) {
10217 if (match_eol_offset(parser, 1)) {
10220 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10221 parser->current.end++;
10226 size_t eol_length = match_eol_offset(parser, 1);
10228 if (parser->heredoc_end) {
10229 parser->current.end = parser->heredoc_end;
10230 parser->heredoc_end = NULL;
10232 parser->current.end += eol_length + 1;
10233 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10236 }
else if (pm_char_is_inline_whitespace(*parser->current.end)) {
10237 parser->current.end += 2;
10251 parser->current.start = parser->current.end;
10255 if (parser->current.end >= parser->end) {
10259 if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
10260 lex_mode_pop(parser);
10261 goto switch_lex_modes;
10269 if (parser->current.start > parser->start && (*(parser->current.start - 1) ==
'\n')) {
10270 parser->current.start -= 1;
10277 switch (*parser->current.end++) {
10281 parser->current.end--;
10285 const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
10286 parser->current.end = ending == NULL ? parser->end : ending;
10291 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10292 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
10294 parser->current.type = PM_TOKEN_COMMENT;
10295 parser_lex_callback(parser);
10299 if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
10300 ptrdiff_t length = parser->current.end - parser->current.start;
10306 if (length >= 10 && !parser->encoding_locked) {
10307 parser_lex_magic_comment_encoding(parser);
10315 if (ending == NULL) {
10316 lexed_comment =
true;
10318 parser->current.start = ending;
10319 parser->current.end = ending + 1;
10325 parser->semantic_token_seen = semantic_token_seen & 0x1;
10326 size_t eol_length = match_eol_at(parser, parser->current.end - 1);
10338 if (!lexed_comment) {
10339 parser->current.end += eol_length - 1;
10342 if (parser->heredoc_end == NULL) {
10343 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10347 if (parser->heredoc_end) {
10348 parser_flush_heredoc_end(parser);
10353 switch (lex_state_ignored_p(parser)) {
10354 case PM_IGNORED_NEWLINE_NONE:
10356 case PM_IGNORED_NEWLINE_PATTERN:
10357 if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
10358 if (!lexed_comment) {
10359 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10360 parser_lex_callback(parser);
10363 lex_state_set(parser, PM_LEX_STATE_BEG);
10364 parser->command_start =
true;
10365 parser->current.type = PM_TOKEN_NEWLINE;
10369 case PM_IGNORED_NEWLINE_ALL:
10370 if (!lexed_comment) parser_lex_ignored_newline(parser);
10371 lexed_comment =
false;
10372 goto lex_next_token;
10379 const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
10380 next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
10382 if (next_content < parser->end) {
10388 if (next_content[0] ==
'#') {
10390 const uint8_t *following = next_newline(next_content, parser->end - next_content);
10392 while (following && (following + 1 < parser->end)) {
10394 following += pm_strspn_inline_whitespace(following, parser->end - following);
10398 if (peek_at(parser, following) !=
'#')
break;
10402 following = next_newline(following, parser->end - following);
10407 if (lex_state_ignored_p(parser)) {
10408 if (!lexed_comment) parser_lex_ignored_newline(parser);
10409 lexed_comment =
false;
10410 goto lex_next_token;
10416 (peek_at(parser, following) ==
'.') ||
10417 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10419 if (!lexed_comment) parser_lex_ignored_newline(parser);
10420 lexed_comment =
false;
10421 goto lex_next_token;
10429 (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
10431 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10432 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10434 peek_at(parser, following) ==
'a' &&
10435 peek_at(parser, following + 1) ==
'n' &&
10436 peek_at(parser, following + 2) ==
'd' &&
10437 peek_at(parser, next_content + 3) !=
'!' &&
10438 peek_at(parser, next_content + 3) !=
'?' &&
10439 !char_is_identifier(parser, following + 3, parser->end - (following + 3))
10442 peek_at(parser, following) ==
'o' &&
10443 peek_at(parser, following + 1) ==
'r' &&
10444 peek_at(parser, next_content + 2) !=
'!' &&
10445 peek_at(parser, next_content + 2) !=
'?' &&
10446 !char_is_identifier(parser, following + 2, parser->end - (following + 2))
10450 if (!lexed_comment) parser_lex_ignored_newline(parser);
10451 lexed_comment =
false;
10452 goto lex_next_token;
10458 if (next_content[0] ==
'.') {
10462 if (peek_at(parser, next_content + 1) ==
'.') {
10463 if (!lexed_comment) {
10464 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10465 parser_lex_callback(parser);
10468 lex_state_set(parser, PM_LEX_STATE_BEG);
10469 parser->command_start =
true;
10470 parser->current.type = PM_TOKEN_NEWLINE;
10474 if (!lexed_comment) parser_lex_ignored_newline(parser);
10475 lex_state_set(parser, PM_LEX_STATE_DOT);
10476 parser->current.start = next_content;
10477 parser->current.end = next_content + 1;
10478 parser->next_start = NULL;
10484 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10485 if (!lexed_comment) parser_lex_ignored_newline(parser);
10486 lex_state_set(parser, PM_LEX_STATE_DOT);
10487 parser->current.start = next_content;
10488 parser->current.end = next_content + 2;
10489 parser->next_start = NULL;
10490 LEX(PM_TOKEN_AMPERSAND_DOT);
10493 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
10496 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10497 if (!lexed_comment) parser_lex_ignored_newline(parser);
10498 lex_state_set(parser, PM_LEX_STATE_BEG);
10499 parser->current.start = next_content;
10500 parser->current.end = next_content + 2;
10501 parser->next_start = NULL;
10502 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10507 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10508 if (!lexed_comment) parser_lex_ignored_newline(parser);
10509 lex_state_set(parser, PM_LEX_STATE_BEG);
10510 parser->current.start = next_content;
10511 parser->current.end = next_content + 2;
10512 parser->next_start = NULL;
10513 LEX(PM_TOKEN_PIPE_PIPE);
10519 peek_at(parser, next_content) ==
'a' &&
10520 peek_at(parser, next_content + 1) ==
'n' &&
10521 peek_at(parser, next_content + 2) ==
'd' &&
10522 peek_at(parser, next_content + 3) !=
'!' &&
10523 peek_at(parser, next_content + 3) !=
'?' &&
10524 !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
10526 if (!lexed_comment) parser_lex_ignored_newline(parser);
10527 lex_state_set(parser, PM_LEX_STATE_BEG);
10528 parser->current.start = next_content;
10529 parser->current.end = next_content + 3;
10530 parser->next_start = NULL;
10531 parser->command_start =
true;
10532 LEX(PM_TOKEN_KEYWORD_AND);
10538 peek_at(parser, next_content) ==
'o' &&
10539 peek_at(parser, next_content + 1) ==
'r' &&
10540 peek_at(parser, next_content + 2) !=
'!' &&
10541 peek_at(parser, next_content + 2) !=
'?' &&
10542 !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
10544 if (!lexed_comment) parser_lex_ignored_newline(parser);
10545 lex_state_set(parser, PM_LEX_STATE_BEG);
10546 parser->current.start = next_content;
10547 parser->current.end = next_content + 2;
10548 parser->next_start = NULL;
10549 parser->command_start =
true;
10550 LEX(PM_TOKEN_KEYWORD_OR);
10557 lex_state_set(parser, PM_LEX_STATE_BEG);
10558 parser->command_start =
true;
10559 parser->current.type = PM_TOKEN_NEWLINE;
10560 if (!lexed_comment) parser_lex_callback(parser);
10566 if ((parser->previous.
type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
10567 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
10570 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10571 LEX(PM_TOKEN_COMMA);
10579 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10581 if (lex_state_beg_p(parser)) {
10582 type = PM_TOKEN_PARENTHESIS_LEFT_GROUPING;
10583 }
else if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10584 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10587 parser->enclosure_nesting++;
10588 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10589 pm_enclosure_frame_push(parser);
10595 parser->enclosure_nesting--;
10596 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10597 pm_enclosure_frame_pop(parser);
10598 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10602 lex_state_set(parser, PM_LEX_STATE_BEG);
10603 parser->command_start =
true;
10604 LEX(PM_TOKEN_SEMICOLON);
10608 parser->enclosure_nesting++;
10609 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10611 if (lex_state_operator_p(parser)) {
10612 if (match(parser,
']')) {
10613 parser->enclosure_nesting--;
10614 lex_state_set(parser, PM_LEX_STATE_ARG);
10615 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10618 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10622 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10623 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10626 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10627 pm_enclosure_frame_push(parser);
10632 parser->enclosure_nesting--;
10633 lex_state_set(parser, PM_LEX_STATE_END);
10634 pm_enclosure_frame_pop(parser);
10635 LEX(PM_TOKEN_BRACKET_RIGHT);
10639 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10641 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
10643 parser->command_start =
true;
10644 lex_state_set(parser, PM_LEX_STATE_BEG);
10645 type = PM_TOKEN_LAMBDA_BEGIN;
10646 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10648 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10649 type = PM_TOKEN_BRACE_LEFT_HASH;
10650 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10652 parser->command_start =
true;
10653 lex_state_set(parser, PM_LEX_STATE_BEG);
10654 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10657 parser->command_start =
true;
10658 lex_state_set(parser, PM_LEX_STATE_BEG);
10659 type = PM_TOKEN_BRACE_LEFT_ARGUMENT;
10662 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10663 type = PM_TOKEN_BRACE_LEFT_HASH;
10666 parser->enclosure_nesting++;
10667 parser->brace_nesting++;
10668 pm_enclosure_frame_push(parser);
10675 parser->enclosure_nesting--;
10676 pm_enclosure_frame_pop(parser);
10678 if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
10679 lex_mode_pop(parser);
10680 LEX(PM_TOKEN_EMBEXPR_END);
10683 parser->brace_nesting--;
10684 lex_state_set(parser, PM_LEX_STATE_END);
10685 LEX(PM_TOKEN_BRACE_RIGHT);
10689 if (match(parser,
'*')) {
10690 if (match(parser,
'=')) {
10691 lex_state_set(parser, PM_LEX_STATE_BEG);
10692 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10695 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10697 if (lex_state_spcarg_p(parser, space_seen)) {
10698 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10699 type = PM_TOKEN_USTAR_STAR;
10700 }
else if (lex_state_beg_p(parser)) {
10701 type = PM_TOKEN_USTAR_STAR;
10702 }
else if (ambiguous_operator_p(parser, space_seen)) {
10703 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10706 if (lex_state_operator_p(parser)) {
10707 lex_state_set(parser, PM_LEX_STATE_ARG);
10709 lex_state_set(parser, PM_LEX_STATE_BEG);
10715 if (match(parser,
'=')) {
10716 lex_state_set(parser, PM_LEX_STATE_BEG);
10717 LEX(PM_TOKEN_STAR_EQUAL);
10720 pm_token_type_t
type = PM_TOKEN_STAR;
10722 if (lex_state_spcarg_p(parser, space_seen)) {
10723 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10724 type = PM_TOKEN_USTAR;
10725 }
else if (lex_state_beg_p(parser)) {
10726 type = PM_TOKEN_USTAR;
10727 }
else if (ambiguous_operator_p(parser, space_seen)) {
10728 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10731 if (lex_state_operator_p(parser)) {
10732 lex_state_set(parser, PM_LEX_STATE_ARG);
10734 lex_state_set(parser, PM_LEX_STATE_BEG);
10742 if (lex_state_operator_p(parser)) {
10743 lex_state_set(parser, PM_LEX_STATE_ARG);
10744 if (match(parser,
'@')) {
10745 LEX(PM_TOKEN_BANG);
10748 lex_state_set(parser, PM_LEX_STATE_BEG);
10751 if (match(parser,
'=')) {
10752 LEX(PM_TOKEN_BANG_EQUAL);
10755 if (match(parser,
'~')) {
10756 LEX(PM_TOKEN_BANG_TILDE);
10759 LEX(PM_TOKEN_BANG);
10764 current_token_starts_line(parser) &&
10765 (parser->current.end + 5 <= parser->end) &&
10766 memcmp(parser->current.end,
"begin", 5) == 0 &&
10767 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10769 pm_token_type_t
type = lex_embdoc(parser);
10770 if (
type == PM_TOKEN_EOF) {
10774 goto lex_next_token;
10777 if (lex_state_operator_p(parser)) {
10778 lex_state_set(parser, PM_LEX_STATE_ARG);
10780 lex_state_set(parser, PM_LEX_STATE_BEG);
10783 if (match(parser,
'>')) {
10784 LEX(PM_TOKEN_EQUAL_GREATER);
10787 if (match(parser,
'~')) {
10788 LEX(PM_TOKEN_EQUAL_TILDE);
10791 if (match(parser,
'=')) {
10792 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10795 LEX(PM_TOKEN_EQUAL);
10799 if (match(parser,
'<')) {
10801 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10802 !lex_state_end_p(parser) &&
10803 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10805 const uint8_t *end = parser->current.end;
10807 pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
10808 pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
10810 if (match(parser,
'-')) {
10811 indent = PM_HEREDOC_INDENT_DASH;
10813 else if (match(parser,
'~')) {
10814 indent = PM_HEREDOC_INDENT_TILDE;
10817 if (match(parser,
'`')) {
10818 quote = PM_HEREDOC_QUOTE_BACKTICK;
10820 else if (match(parser,
'"')) {
10821 quote = PM_HEREDOC_QUOTE_DOUBLE;
10823 else if (match(parser,
'\'')) {
10824 quote = PM_HEREDOC_QUOTE_SINGLE;
10827 const uint8_t *ident_start = parser->current.end;
10830 if (parser->current.end >= parser->end) {
10831 parser->current.end = end;
10832 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) == 0) {
10833 parser->current.end = end;
10835 if (quote == PM_HEREDOC_QUOTE_NONE) {
10836 parser->current.end += width;
10838 while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end))) {
10839 parser->current.end += width;
10844 while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
10845 if (*parser->current.end ==
'\r' || *parser->current.end ==
'\n')
break;
10846 parser->current.end++;
10850 size_t ident_length = (size_t) (parser->current.end - ident_start);
10851 bool ident_error =
false;
10853 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10854 pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10855 ident_error =
true;
10858 parser->explicit_encoding = NULL;
10860 .mode = PM_LEX_HEREDOC,
10863 .ident_start = ident_start,
10864 .ident_length = ident_length,
10868 .next_start = parser->current.end,
10869 .common_whitespace = NULL,
10870 .line_continuation =
false
10874 if (parser->heredoc_end == NULL) {
10875 const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
10877 if (body_start == NULL) {
10882 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10883 body_start = parser->end;
10887 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
10891 parser->next_start = body_start;
10893 parser->next_start = parser->heredoc_end;
10896 LEX(PM_TOKEN_HEREDOC_START);
10900 if (match(parser,
'=')) {
10901 lex_state_set(parser, PM_LEX_STATE_BEG);
10902 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10905 if (ambiguous_operator_p(parser, space_seen)) {
10906 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10909 if (lex_state_operator_p(parser)) {
10910 lex_state_set(parser, PM_LEX_STATE_ARG);
10912 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10913 lex_state_set(parser, PM_LEX_STATE_BEG);
10916 LEX(PM_TOKEN_LESS_LESS);
10919 if (lex_state_operator_p(parser)) {
10920 lex_state_set(parser, PM_LEX_STATE_ARG);
10922 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10923 lex_state_set(parser, PM_LEX_STATE_BEG);
10926 if (match(parser,
'=')) {
10927 if (match(parser,
'>')) {
10928 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10931 LEX(PM_TOKEN_LESS_EQUAL);
10934 LEX(PM_TOKEN_LESS);
10938 if (match(parser,
'>')) {
10939 if (lex_state_operator_p(parser)) {
10940 lex_state_set(parser, PM_LEX_STATE_ARG);
10942 lex_state_set(parser, PM_LEX_STATE_BEG);
10944 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10947 if (lex_state_operator_p(parser)) {
10948 lex_state_set(parser, PM_LEX_STATE_ARG);
10950 lex_state_set(parser, PM_LEX_STATE_BEG);
10953 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10957 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10958 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10959 LEX(PM_TOKEN_STRING_BEGIN);
10964 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10965 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10966 LEX(PM_TOKEN_BACKTICK);
10969 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10970 if (previous_command_start) {
10971 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10973 lex_state_set(parser, PM_LEX_STATE_ARG);
10976 LEX(PM_TOKEN_BACKTICK);
10979 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10980 LEX(PM_TOKEN_XSTRING_BEGIN);
10985 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10986 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10987 LEX(PM_TOKEN_STRING_BEGIN);
10992 LEX(lex_question_mark(parser));
10996 if (match(parser,
'&')) {
10997 lex_state_set(parser, PM_LEX_STATE_BEG);
10999 if (match(parser,
'=')) {
11000 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
11003 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
11006 if (match(parser,
'=')) {
11007 lex_state_set(parser, PM_LEX_STATE_BEG);
11008 LEX(PM_TOKEN_AMPERSAND_EQUAL);
11011 if (match(parser,
'.')) {
11012 lex_state_set(parser, PM_LEX_STATE_DOT);
11013 LEX(PM_TOKEN_AMPERSAND_DOT);
11016 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
11017 if (lex_state_spcarg_p(parser, space_seen)) {
11018 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
11019 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11021 const uint8_t delim = peek_offset(parser, 1);
11023 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->current.end + 1, parser->end - (parser->current.end + 1))) {
11024 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11028 type = PM_TOKEN_UAMPERSAND;
11029 }
else if (lex_state_beg_p(parser)) {
11030 type = PM_TOKEN_UAMPERSAND;
11031 }
else if (ambiguous_operator_p(parser, space_seen)) {
11032 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11035 if (lex_state_operator_p(parser)) {
11036 lex_state_set(parser, PM_LEX_STATE_ARG);
11038 lex_state_set(parser, PM_LEX_STATE_BEG);
11046 if (match(parser,
'|')) {
11047 if (match(parser,
'=')) {
11048 lex_state_set(parser, PM_LEX_STATE_BEG);
11049 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
11052 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11053 parser->current.end--;
11054 LEX(PM_TOKEN_PIPE);
11057 lex_state_set(parser, PM_LEX_STATE_BEG);
11058 LEX(PM_TOKEN_PIPE_PIPE);
11061 if (match(parser,
'=')) {
11062 lex_state_set(parser, PM_LEX_STATE_BEG);
11063 LEX(PM_TOKEN_PIPE_EQUAL);
11066 if (lex_state_operator_p(parser)) {
11067 lex_state_set(parser, PM_LEX_STATE_ARG);
11069 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11072 LEX(PM_TOKEN_PIPE);
11076 if (lex_state_operator_p(parser)) {
11077 lex_state_set(parser, PM_LEX_STATE_ARG);
11079 if (match(parser,
'@')) {
11080 LEX(PM_TOKEN_UPLUS);
11083 LEX(PM_TOKEN_PLUS);
11086 if (match(parser,
'=')) {
11087 lex_state_set(parser, PM_LEX_STATE_BEG);
11088 LEX(PM_TOKEN_PLUS_EQUAL);
11092 lex_state_beg_p(parser) ||
11093 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11095 lex_state_set(parser, PM_LEX_STATE_BEG);
11097 if (pm_char_is_decimal_digit(peek(parser))) {
11098 parser->current.end++;
11099 pm_token_type_t
type = lex_numeric(parser);
11100 lex_state_set(parser, PM_LEX_STATE_END);
11104 LEX(PM_TOKEN_UPLUS);
11107 if (ambiguous_operator_p(parser, space_seen)) {
11108 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11111 lex_state_set(parser, PM_LEX_STATE_BEG);
11112 LEX(PM_TOKEN_PLUS);
11117 if (lex_state_operator_p(parser)) {
11118 lex_state_set(parser, PM_LEX_STATE_ARG);
11120 if (match(parser,
'@')) {
11121 LEX(PM_TOKEN_UMINUS);
11124 LEX(PM_TOKEN_MINUS);
11127 if (match(parser,
'=')) {
11128 lex_state_set(parser, PM_LEX_STATE_BEG);
11129 LEX(PM_TOKEN_MINUS_EQUAL);
11132 if (match(parser,
'>')) {
11133 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11134 LEX(PM_TOKEN_MINUS_GREATER);
11137 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11138 bool is_beg = lex_state_beg_p(parser);
11139 if (!is_beg && spcarg) {
11140 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11143 if (is_beg || spcarg) {
11144 lex_state_set(parser, PM_LEX_STATE_BEG);
11145 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11148 if (ambiguous_operator_p(parser, space_seen)) {
11149 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11152 lex_state_set(parser, PM_LEX_STATE_BEG);
11153 LEX(PM_TOKEN_MINUS);
11158 bool beg_p = lex_state_beg_p(parser);
11160 if (match(parser,
'.')) {
11161 if (match(parser,
'.')) {
11163 if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) {
11164 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11165 lex_state_set(parser, PM_LEX_STATE_BEG);
11167 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11169 LEX(PM_TOKEN_UDOT_DOT_DOT);
11172 if (parser->enclosure_nesting == 0 && parser_end_of_line_p(parser)) {
11173 pm_parser_warn_token(parser, &parser->current, PM_WARN_DOT_DOT_DOT_EOL);
11176 lex_state_set(parser, PM_LEX_STATE_BEG);
11177 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11180 lex_state_set(parser, PM_LEX_STATE_BEG);
11181 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11184 lex_state_set(parser, PM_LEX_STATE_DOT);
11199 pm_token_type_t
type = lex_numeric(parser);
11200 lex_state_set(parser, PM_LEX_STATE_END);
11206 if (match(parser,
':')) {
11207 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)) {
11208 lex_state_set(parser, PM_LEX_STATE_BEG);
11209 LEX(PM_TOKEN_UCOLON_COLON);
11212 lex_state_set(parser, PM_LEX_STATE_DOT);
11213 LEX(PM_TOKEN_COLON_COLON);
11216 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11217 lex_state_set(parser, PM_LEX_STATE_BEG);
11218 LEX(PM_TOKEN_COLON);
11221 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11222 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->current.end);
11223 parser->current.end++;
11230 parser->explicit_encoding = NULL;
11233 lex_state_set(parser, PM_LEX_STATE_FNAME);
11234 LEX(PM_TOKEN_SYMBOL_BEGIN);
11238 if (lex_state_beg_p(parser)) {
11239 lex_mode_push_regexp(parser,
'\0',
'/');
11240 LEX(PM_TOKEN_REGEXP_BEGIN);
11243 if (match(parser,
'=')) {
11244 lex_state_set(parser, PM_LEX_STATE_BEG);
11245 LEX(PM_TOKEN_SLASH_EQUAL);
11248 if (lex_state_spcarg_p(parser, space_seen)) {
11250 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_4_0) {
11251 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
11253 lex_mode_push_regexp(parser,
'\0',
'/');
11254 LEX(PM_TOKEN_REGEXP_BEGIN);
11257 if (ambiguous_operator_p(parser, space_seen)) {
11258 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11261 if (lex_state_operator_p(parser)) {
11262 lex_state_set(parser, PM_LEX_STATE_ARG);
11264 lex_state_set(parser, PM_LEX_STATE_BEG);
11267 LEX(PM_TOKEN_SLASH);
11271 if (lex_state_operator_p(parser)) {
11272 lex_state_set(parser, PM_LEX_STATE_ARG);
11274 lex_state_set(parser, PM_LEX_STATE_BEG);
11276 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11280 if (lex_state_operator_p(parser)) {
11281 (void) match(parser,
'@');
11282 lex_state_set(parser, PM_LEX_STATE_ARG);
11284 lex_state_set(parser, PM_LEX_STATE_BEG);
11287 LEX(PM_TOKEN_TILDE);
11295 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
11296 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11297 LEX(PM_TOKEN_PERCENT);
11300 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11301 lex_state_set(parser, PM_LEX_STATE_BEG);
11302 LEX(PM_TOKEN_PERCENT_EQUAL);
11304 lex_state_beg_p(parser) ||
11305 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11306 lex_state_spcarg_p(parser, space_seen)
11308 if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) {
11309 if (*parser->current.end >= 0x80) {
11310 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11311 goto lex_next_token;
11314 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11315 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11316 LEX(PM_TOKEN_STRING_BEGIN);
11321 uint8_t delimiter = peek_offset(parser, 1);
11322 if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) {
11323 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11324 goto lex_next_token;
11327 switch (peek(parser)) {
11329 parser->current.end++;
11331 if (parser->current.end < parser->end) {
11332 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11334 lex_mode_push_list_eof(parser);
11337 LEX(PM_TOKEN_PERCENT_LOWER_I);
11340 parser->current.end++;
11342 if (parser->current.end < parser->end) {
11343 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11345 lex_mode_push_list_eof(parser);
11348 LEX(PM_TOKEN_PERCENT_UPPER_I);
11351 parser->current.end++;
11353 if (parser->current.end < parser->end) {
11354 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11355 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11357 lex_mode_push_regexp(parser,
'\0',
'\0');
11360 LEX(PM_TOKEN_REGEXP_BEGIN);
11363 parser->current.end++;
11365 if (parser->current.end < parser->end) {
11366 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11367 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11369 lex_mode_push_string_eof(parser);
11372 LEX(PM_TOKEN_STRING_BEGIN);
11375 parser->current.end++;
11377 if (parser->current.end < parser->end) {
11378 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11379 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11381 lex_mode_push_string_eof(parser);
11384 LEX(PM_TOKEN_STRING_BEGIN);
11387 parser->current.end++;
11389 if (parser->current.end < parser->end) {
11390 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11391 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11392 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11394 lex_mode_push_string_eof(parser);
11397 LEX(PM_TOKEN_SYMBOL_BEGIN);
11400 parser->current.end++;
11402 if (parser->current.end < parser->end) {
11403 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11405 lex_mode_push_list_eof(parser);
11408 LEX(PM_TOKEN_PERCENT_LOWER_W);
11411 parser->current.end++;
11413 if (parser->current.end < parser->end) {
11414 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11416 lex_mode_push_list_eof(parser);
11419 LEX(PM_TOKEN_PERCENT_UPPER_W);
11422 parser->current.end++;
11424 if (parser->current.end < parser->end) {
11425 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11426 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11428 lex_mode_push_string_eof(parser);
11431 LEX(PM_TOKEN_PERCENT_LOWER_X);
11438 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11439 goto lex_next_token;
11443 if (ambiguous_operator_p(parser, space_seen)) {
11444 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11447 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11448 LEX(PM_TOKEN_PERCENT);
11453 pm_token_type_t
type = lex_global_variable(parser);
11457 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
11458 lex_mode_pop(parser);
11461 lex_state_set(parser, PM_LEX_STATE_END);
11467 lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11468 LEX(lex_at_variable(parser));
11471 if (*parser->current.start !=
'_') {
11472 size_t width = char_is_identifier_start(parser, parser->current.start, parser->end - parser->current.start);
11479 if (*parser->current.start >= 0x80) {
11480 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
11481 }
else if (*parser->current.start ==
'\\') {
11482 switch (peek_at(parser, parser->current.start + 1)) {
11484 parser->current.end++;
11485 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11488 parser->current.end++;
11489 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11492 parser->current.end++;
11493 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11496 parser->current.end++;
11497 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11500 if (peek_at(parser, parser->current.start + 2) !=
'\n') {
11501 parser->current.end++;
11502 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11507 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11510 }
else if (char_is_ascii_printable(*parser->current.start)) {
11511 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
11513 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
11516 goto lex_next_token;
11519 parser->current.end = parser->current.start + width;
11522 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11529 ((parser->current.end - parser->current.start) == 7) &&
11530 current_token_starts_line(parser) &&
11531 (memcmp(parser->current.start,
"__END__", 7) == 0) &&
11532 (parser->current.end == parser->end || match_eol(parser))
11537 const uint8_t *cursor = parser->current.end;
11538 while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
11539 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
11542 parser->current.end = parser->end;
11543 parser->current.type = PM_TOKEN___END__;
11544 parser_lex_callback(parser);
11546 parser->data_loc.
start = PM_TOKEN_START(parser, &parser->current);
11547 parser->data_loc.
length = PM_TOKEN_LENGTH(&parser->current);
11552 pm_lex_state_t last_state = parser->lex_state;
11554 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11555 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11556 if (previous_command_start) {
11557 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11559 lex_state_set(parser, PM_LEX_STATE_ARG);
11561 }
else if (parser->lex_state == PM_LEX_STATE_FNAME) {
11562 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11564 lex_state_set(parser, PM_LEX_STATE_END);
11569 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11570 (
type == PM_TOKEN_IDENTIFIER) &&
11571 ((pm_parser_local_depth(parser, &parser->current) != -1) ||
11572 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
11574 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11581 case PM_LEX_LIST: {
11582 if (parser->next_start != NULL) {
11583 parser->current.end = parser->next_start;
11584 parser->next_start = NULL;
11588 parser->current.start = parser->current.end;
11596 if (parser->heredoc_end) {
11597 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11598 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11601 }
else if (lex_mode->as.list.terminator ==
'\n') {
11606 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11608 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));
11611 if (whitespace > 0) {
11612 parser->current.end += whitespace;
11613 if (peek_offset(parser, -1) ==
'\n') {
11615 parser_flush_heredoc_end(parser);
11618 lex_mode->as.list.started =
true;
11619 lex_mode->as.list.separated =
true;
11620 LEX(PM_TOKEN_WORDS_SEP);
11625 if (parser->current.end >= parser->end) {
11634 if (!lex_mode->as.list.started) {
11635 lex_mode->as.list.started =
true;
11636 lex_mode->as.list.separated =
true;
11637 parser->current.type = PM_TOKEN_WORDS_SEP_IMPLICIT;
11638 parser_lex_callback(parser);
11643 const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
11644 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11650 while (breakpoint != NULL) {
11655 if (pm_char_is_whitespace(*breakpoint) && *breakpoint != lex_mode->as.list.terminator) {
11656 parser->current.end = breakpoint;
11657 pm_token_buffer_flush(parser, &token_buffer);
11658 lex_mode->as.list.separated =
false;
11659 LEX(PM_TOKEN_STRING_CONTENT);
11664 if (*breakpoint == lex_mode->as.list.terminator) {
11667 if (lex_mode->as.list.nesting > 0) {
11668 parser->current.end = breakpoint + 1;
11669 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11670 lex_mode->as.list.nesting--;
11676 if (breakpoint > parser->current.start) {
11677 parser->current.end = breakpoint;
11678 pm_token_buffer_flush(parser, &token_buffer);
11679 lex_mode->as.list.separated =
false;
11680 LEX(PM_TOKEN_STRING_CONTENT);
11688 if (!lex_mode->as.list.separated) {
11689 lex_mode->as.list.separated =
true;
11690 parser->current.end = breakpoint;
11691 parser->current.type = PM_TOKEN_WORDS_SEP_IMPLICIT;
11692 parser_lex_callback(parser);
11697 parser->current.end = breakpoint + 1;
11702 if (*breakpoint ==
'\n') {
11703 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11706 lex_mode_pop(parser);
11707 lex_state_set(parser, PM_LEX_STATE_END);
11708 LEX(PM_TOKEN_STRING_END);
11712 if (*breakpoint ==
'\0') {
11713 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1),
true);
11720 if (*breakpoint ==
'\\') {
11721 parser->current.end = breakpoint + 1;
11725 if (parser->current.end == parser->end) {
11730 pm_token_buffer_escape(parser, &token_buffer);
11731 uint8_t peeked = peek(parser);
11739 pm_token_buffer_push_byte(&token_buffer, peeked);
11740 parser->current.end++;
11743 parser->current.end++;
11744 if (peek(parser) !=
'\n') {
11745 pm_token_buffer_push_byte(&token_buffer,
'\r');
11750 pm_token_buffer_push_byte(&token_buffer,
'\n');
11752 if (parser->heredoc_end) {
11756 parser_flush_heredoc_end(parser);
11757 pm_token_buffer_copy(parser, &token_buffer);
11758 LEX(PM_TOKEN_STRING_CONTENT);
11761 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11764 parser->current.end++;
11767 if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
11768 pm_token_buffer_push_byte(&token_buffer, peeked);
11769 parser->current.end++;
11770 }
else if (lex_mode->as.list.interpolation) {
11771 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11773 pm_token_buffer_push_byte(&token_buffer,
'\\');
11774 pm_token_buffer_push_escaped(&token_buffer, parser);
11780 token_buffer.
cursor = parser->current.end;
11781 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11786 if (*breakpoint ==
'#') {
11787 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11794 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11798 if (
type == PM_TOKEN_STRING_CONTENT) {
11799 pm_token_buffer_flush(parser, &token_buffer);
11802 lex_mode->as.list.separated =
false;
11808 assert(*breakpoint == lex_mode->as.list.incrementor);
11809 parser->current.end = breakpoint + 1;
11810 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11811 lex_mode->as.list.nesting++;
11815 if (parser->current.end > parser->current.start) {
11816 pm_token_buffer_flush(parser, &token_buffer);
11817 LEX(PM_TOKEN_STRING_CONTENT);
11822 parser->current.end = parser->end;
11823 pm_token_buffer_flush(parser, &token_buffer);
11824 LEX(PM_TOKEN_STRING_CONTENT);
11826 case PM_LEX_REGEXP: {
11828 if (parser->next_start == NULL) {
11829 parser->current.start = parser->current.end;
11831 parser->current.start = parser->next_start;
11832 parser->current.end = parser->next_start;
11833 parser->next_start = NULL;
11838 if (parser->current.end >= parser->end) {
11848 const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
11849 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11852 while (breakpoint != NULL) {
11853 uint8_t term = lex_mode->as.regexp.terminator;
11854 bool is_terminator = (*breakpoint == term);
11859 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11860 if (term ==
'\n') {
11861 is_terminator =
true;
11867 if (term ==
'\r') {
11868 is_terminator =
false;
11874 if (is_terminator) {
11875 if (lex_mode->as.regexp.nesting > 0) {
11876 parser->current.end = breakpoint + 1;
11877 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11878 lex_mode->as.regexp.nesting--;
11885 if (breakpoint > parser->current.start) {
11886 parser->current.end = breakpoint;
11887 pm_regexp_token_buffer_flush(parser, &token_buffer);
11888 LEX(PM_TOKEN_STRING_CONTENT);
11892 size_t eol_length = match_eol_at(parser, breakpoint);
11894 parser->current.end = breakpoint + eol_length;
11899 if (parser->heredoc_end == NULL) {
11900 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11903 parser->current.end = breakpoint + 1;
11908 parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
11910 lex_mode_pop(parser);
11911 lex_state_set(parser, PM_LEX_STATE_END);
11912 LEX(PM_TOKEN_REGEXP_END);
11917 if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
11918 parser->current.end = breakpoint + 1;
11919 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11920 lex_mode->as.regexp.nesting++;
11924 switch (*breakpoint) {
11927 parser->current.end = breakpoint + 1;
11928 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11931 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11932 parser->current.end = breakpoint + 1;
11933 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11938 parser->current.end = breakpoint;
11939 pm_regexp_token_buffer_escape(parser, &token_buffer);
11946 if (parser->heredoc_end == NULL) {
11947 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
11948 parser->current.end = breakpoint + 1;
11949 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11953 parser->current.end = breakpoint + 1;
11954 parser_flush_heredoc_end(parser);
11955 pm_regexp_token_buffer_flush(parser, &token_buffer);
11956 LEX(PM_TOKEN_STRING_CONTENT);
11961 parser->current.end = breakpoint + 1;
11965 if (parser->current.end == parser->end) {
11970 pm_regexp_token_buffer_escape(parser, &token_buffer);
11971 uint8_t peeked = peek(parser);
11975 parser->current.end++;
11976 if (peek(parser) !=
'\n') {
11977 if (lex_mode->as.regexp.terminator !=
'\r') {
11978 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11980 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11981 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11986 if (parser->heredoc_end) {
11990 parser_flush_heredoc_end(parser);
11991 pm_regexp_token_buffer_copy(parser, &token_buffer);
11992 LEX(PM_TOKEN_STRING_CONTENT);
11995 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11998 parser->current.end++;
12008 if (lex_mode->as.regexp.terminator == peeked) {
12013 case '$':
case ')':
case '*':
case '+':
12014 case '.':
case '>':
case '?':
case ']':
12015 case '^':
case '|':
case '}':
12016 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12022 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12023 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12024 parser->current.end++;
12028 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12029 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12033 token_buffer.
base.
cursor = parser->current.end;
12034 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
12040 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12047 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
12051 if (
type == PM_TOKEN_STRING_CONTENT) {
12052 pm_regexp_token_buffer_flush(parser, &token_buffer);
12058 assert(
false &&
"unreachable");
12063 if (parser->current.end > parser->current.start) {
12064 pm_regexp_token_buffer_flush(parser, &token_buffer);
12065 LEX(PM_TOKEN_STRING_CONTENT);
12070 parser->current.end = parser->end;
12071 pm_regexp_token_buffer_flush(parser, &token_buffer);
12072 LEX(PM_TOKEN_STRING_CONTENT);
12074 case PM_LEX_STRING: {
12076 if (parser->next_start == NULL) {
12077 parser->current.start = parser->current.end;
12079 parser->current.start = parser->next_start;
12080 parser->current.end = parser->next_start;
12081 parser->next_start = NULL;
12086 if (parser->current.end >= parser->end) {
12093 const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
12094 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12100 while (breakpoint != NULL) {
12103 if (lex_mode->as.string.incrementor !=
'\0' && *breakpoint == lex_mode->as.string.incrementor) {
12104 lex_mode->as.string.nesting++;
12105 parser->current.end = breakpoint + 1;
12106 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12110 uint8_t term = lex_mode->as.string.terminator;
12111 bool is_terminator = (*breakpoint == term);
12116 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12117 if (term ==
'\n') {
12118 is_terminator =
true;
12124 if (term ==
'\r') {
12125 is_terminator =
false;
12132 if (is_terminator) {
12135 if (lex_mode->as.string.nesting > 0) {
12136 parser->current.end = breakpoint + 1;
12137 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12138 lex_mode->as.string.nesting--;
12144 if (breakpoint > parser->current.start) {
12145 parser->current.end = breakpoint;
12146 pm_token_buffer_flush(parser, &token_buffer);
12147 LEX(PM_TOKEN_STRING_CONTENT);
12152 size_t eol_length = match_eol_at(parser, breakpoint);
12154 parser->current.end = breakpoint + eol_length;
12159 if (parser->heredoc_end == NULL) {
12160 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
12163 parser->current.end = breakpoint + 1;
12166 if (lex_mode->as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12167 parser->current.end++;
12168 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12169 lex_mode_pop(parser);
12170 LEX(PM_TOKEN_LABEL_END);
12176 if (term ==
'\n' && parser->heredoc_end) {
12177 parser_flush_heredoc_end(parser);
12180 lex_state_set(parser, PM_LEX_STATE_END);
12181 lex_mode_pop(parser);
12182 LEX(PM_TOKEN_STRING_END);
12185 switch (*breakpoint) {
12188 parser->current.end = breakpoint + 1;
12189 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12192 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12193 parser->current.end = breakpoint + 1;
12194 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12201 parser->current.end = breakpoint;
12202 pm_token_buffer_escape(parser, &token_buffer);
12203 token_buffer.
cursor = breakpoint;
12211 if (parser->heredoc_end == NULL) {
12212 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12213 parser->current.end = breakpoint + 1;
12214 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12218 parser->current.end = breakpoint + 1;
12219 parser_flush_heredoc_end(parser);
12220 pm_token_buffer_flush(parser, &token_buffer);
12221 LEX(PM_TOKEN_STRING_CONTENT);
12224 parser->current.end = breakpoint + 1;
12228 if (parser->current.end == parser->end) {
12233 pm_token_buffer_escape(parser, &token_buffer);
12234 uint8_t peeked = peek(parser);
12238 pm_token_buffer_push_byte(&token_buffer,
'\\');
12239 parser->current.end++;
12242 parser->current.end++;
12243 if (peek(parser) !=
'\n') {
12244 if (!lex_mode->as.string.interpolation) {
12245 pm_token_buffer_push_byte(&token_buffer,
'\\');
12247 pm_token_buffer_push_byte(&token_buffer,
'\r');
12252 if (!lex_mode->as.string.interpolation) {
12253 pm_token_buffer_push_byte(&token_buffer,
'\\');
12254 pm_token_buffer_push_byte(&token_buffer,
'\n');
12257 if (parser->heredoc_end) {
12261 parser_flush_heredoc_end(parser);
12262 pm_token_buffer_copy(parser, &token_buffer);
12263 LEX(PM_TOKEN_STRING_CONTENT);
12266 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
12269 parser->current.end++;
12272 if (lex_mode->as.string.incrementor !=
'\0' && peeked == lex_mode->as.string.incrementor) {
12273 pm_token_buffer_push_byte(&token_buffer, peeked);
12274 parser->current.end++;
12275 }
else if (lex_mode->as.string.terminator !=
'\0' && peeked == lex_mode->as.string.terminator) {
12276 pm_token_buffer_push_byte(&token_buffer, peeked);
12277 parser->current.end++;
12278 }
else if (lex_mode->as.string.interpolation) {
12279 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12281 pm_token_buffer_push_byte(&token_buffer,
'\\');
12282 pm_token_buffer_push_escaped(&token_buffer, parser);
12288 token_buffer.
cursor = parser->current.end;
12289 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12293 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12300 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12304 if (
type == PM_TOKEN_STRING_CONTENT) {
12305 pm_token_buffer_flush(parser, &token_buffer);
12311 assert(
false &&
"unreachable");
12315 if (parser->current.end > parser->current.start) {
12316 pm_token_buffer_flush(parser, &token_buffer);
12317 LEX(PM_TOKEN_STRING_CONTENT);
12322 parser->current.end = parser->end;
12323 pm_token_buffer_flush(parser, &token_buffer);
12324 LEX(PM_TOKEN_STRING_CONTENT);
12326 case PM_LEX_HEREDOC: {
12328 if (parser->next_start == NULL) {
12329 parser->current.start = parser->current.end;
12331 parser->current.start = parser->next_start;
12332 parser->current.end = parser->next_start;
12333 parser->heredoc_end = NULL;
12334 parser->next_start = NULL;
12342 bool line_continuation = lex_mode->as.heredoc.line_continuation;
12343 lex_mode->as.heredoc.line_continuation =
false;
12349 if (parser->current.end >= parser->end) {
12350 pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
12351 parser->next_start = lex_mode->as.heredoc.next_start;
12352 parser->heredoc_end = parser->current.end;
12353 lex_state_set(parser, PM_LEX_STATE_END);
12354 lex_mode_pop(parser);
12355 LEX(PM_TOKEN_HEREDOC_END);
12358 const uint8_t *ident_start = heredoc_lex_mode->ident_start;
12359 size_t ident_length = heredoc_lex_mode->ident_length;
12363 if (current_token_starts_line(parser)) {
12364 const uint8_t *start = parser->current.start;
12366 if (!line_continuation && (start + ident_length <= parser->end)) {
12367 const uint8_t *newline = next_newline(start, parser->end - start);
12368 const uint8_t *ident_end = newline;
12369 const uint8_t *terminator_end = newline;
12371 if (newline == NULL) {
12372 terminator_end = parser->end;
12373 ident_end = parser->end;
12376 if (newline[-1] ==
'\r') {
12388 if ((
size_t) (ident_end - start) >= ident_length) {
12389 const uint8_t *terminator_start = ident_end - ident_length;
12390 const uint8_t *cursor = start;
12392 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12393 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12399 (cursor == terminator_start) &&
12400 (memcmp(terminator_start, ident_start, ident_length) == 0)
12402 if (newline != NULL) {
12403 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
12406 parser->current.end = terminator_end;
12407 if (*lex_mode->as.heredoc.next_start ==
'\\') {
12408 parser->next_start = NULL;
12410 parser->next_start = lex_mode->as.heredoc.next_start;
12411 parser->heredoc_end = parser->current.end;
12414 lex_state_set(parser, PM_LEX_STATE_END);
12415 lex_mode_pop(parser);
12416 LEX(PM_TOKEN_HEREDOC_END);
12421 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
12423 heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
12424 lex_mode->as.heredoc.common_whitespace != NULL &&
12425 (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
12426 peek_at(parser, start) !=
'\n'
12428 *lex_mode->as.heredoc.common_whitespace = whitespace;
12435 uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] =
"\r\n\\#";
12437 pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
12438 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12439 breakpoints[3] =
'\0';
12442 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12444 bool was_line_continuation =
false;
12446 while (breakpoint != NULL) {
12447 switch (*breakpoint) {
12450 parser->current.end = breakpoint + 1;
12451 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12454 parser->current.end = breakpoint + 1;
12456 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12457 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12464 pm_token_buffer_escape(parser, &token_buffer);
12465 token_buffer.
cursor = breakpoint;
12469 if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
12470 parser_flush_heredoc_end(parser);
12471 parser->current.end = breakpoint + 1;
12472 pm_token_buffer_flush(parser, &token_buffer);
12473 LEX(PM_TOKEN_STRING_CONTENT);
12476 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12480 const uint8_t *start = breakpoint + 1;
12482 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12485 const uint8_t *newline = next_newline(start, parser->end - start);
12487 if (newline == NULL) {
12488 newline = parser->end;
12489 }
else if (newline[-1] ==
'\r') {
12501 if ((
size_t) (newline - start) >= ident_length) {
12503 const uint8_t *terminator_start = newline - ident_length;
12507 const uint8_t *cursor = start;
12509 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12510 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12516 cursor == terminator_start &&
12517 (memcmp(terminator_start, ident_start, ident_length) == 0)
12519 parser->current.end = breakpoint + 1;
12520 pm_token_buffer_flush(parser, &token_buffer);
12521 LEX(PM_TOKEN_STRING_CONTENT);
12526 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
12533 if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12534 if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12535 *lex_mode->as.heredoc.common_whitespace = whitespace;
12538 parser->current.end = breakpoint + 1;
12539 pm_token_buffer_flush(parser, &token_buffer);
12540 LEX(PM_TOKEN_STRING_CONTENT);
12545 parser->current.end = breakpoint + 1;
12546 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12556 parser->current.end = breakpoint + 1;
12560 if (parser->current.end == parser->end) {
12565 pm_token_buffer_escape(parser, &token_buffer);
12566 uint8_t peeked = peek(parser);
12568 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12571 parser->current.end++;
12572 if (peek(parser) !=
'\n') {
12573 pm_token_buffer_push_byte(&token_buffer,
'\\');
12574 pm_token_buffer_push_byte(&token_buffer,
'\r');
12579 pm_token_buffer_push_byte(&token_buffer,
'\\');
12580 pm_token_buffer_push_byte(&token_buffer,
'\n');
12581 token_buffer.
cursor = parser->current.end + 1;
12582 breakpoint = parser->current.end;
12585 pm_token_buffer_push_byte(&token_buffer,
'\\');
12586 pm_token_buffer_push_escaped(&token_buffer, parser);
12592 parser->current.end++;
12593 if (peek(parser) !=
'\n') {
12594 pm_token_buffer_push_byte(&token_buffer,
'\r');
12602 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12603 const uint8_t *end = parser->current.end;
12605 if (parser->heredoc_end == NULL) {
12606 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
12611 parser->current.end = breakpoint;
12612 pm_token_buffer_flush(parser, &token_buffer);
12616 parser->current.end = end + 1;
12617 lex_mode->as.heredoc.line_continuation =
true;
12618 LEX(PM_TOKEN_STRING_CONTENT);
12621 was_line_continuation =
true;
12622 token_buffer.
cursor = parser->current.end + 1;
12623 breakpoint = parser->current.end;
12626 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12631 token_buffer.
cursor = parser->current.end;
12632 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12636 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12644 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12648 if (
type == PM_TOKEN_STRING_CONTENT) {
12649 pm_token_buffer_flush(parser, &token_buffer);
12655 assert(
false &&
"unreachable");
12658 was_line_continuation =
false;
12661 if (parser->current.end > parser->current.start) {
12662 parser->current.end = parser->end;
12663 pm_token_buffer_flush(parser, &token_buffer);
12664 LEX(PM_TOKEN_STRING_CONTENT);
12669 parser->current.end = parser->end;
12670 pm_token_buffer_flush(parser, &token_buffer);
12671 LEX(PM_TOKEN_STRING_CONTENT);
12675 assert(
false &&
"unreachable");
12693 PM_BINDING_POWER_UNSET = 0,
12694 PM_BINDING_POWER_STATEMENT = 2,
12695 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12696 PM_BINDING_POWER_MODIFIER = 6,
12697 PM_BINDING_POWER_COMPOSITION = 8,
12698 PM_BINDING_POWER_NOT = 10,
12699 PM_BINDING_POWER_MATCH = 12,
12700 PM_BINDING_POWER_DEFINED = 14,
12701 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12702 PM_BINDING_POWER_ASSIGNMENT = 18,
12703 PM_BINDING_POWER_TERNARY = 20,
12704 PM_BINDING_POWER_RANGE = 22,
12705 PM_BINDING_POWER_LOGICAL_OR = 24,
12706 PM_BINDING_POWER_LOGICAL_AND = 26,
12707 PM_BINDING_POWER_EQUALITY = 28,
12708 PM_BINDING_POWER_COMPARISON = 30,
12709 PM_BINDING_POWER_BITWISE_OR = 32,
12710 PM_BINDING_POWER_BITWISE_AND = 34,
12711 PM_BINDING_POWER_SHIFT = 36,
12712 PM_BINDING_POWER_TERM = 38,
12713 PM_BINDING_POWER_FACTOR = 40,
12714 PM_BINDING_POWER_UMINUS = 42,
12715 PM_BINDING_POWER_EXPONENT = 44,
12716 PM_BINDING_POWER_UNARY = 46,
12717 PM_BINDING_POWER_INDEX = 48,
12718 PM_BINDING_POWER_CALL = 50,
12719 PM_BINDING_POWER_MAX = 52
12720} pm_binding_power_t;
12743#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12744#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12745#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12746#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12747#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12751 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12754 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12755 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12756 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12757 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12760 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12761 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12764 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12765 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12768 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12769 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12770 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12771 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12772 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12773 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12774 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12775 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12776 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12777 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12778 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12779 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12780 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12781 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12784 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12787 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12788 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12789 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12790 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12793 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12796 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12799 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12800 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12801 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12802 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12803 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12804 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12807 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12808 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12809 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12810 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12813 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12814 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12817 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12820 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12821 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12824 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12825 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12828 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12829 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12830 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12831 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12834 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12835 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12838 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12839 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12842 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12843 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12844 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12847 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12850 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12851 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12852 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12855#undef BINDING_POWER_ASSIGNMENT
12856#undef LEFT_ASSOCIATIVE
12857#undef RIGHT_ASSOCIATIVE
12858#undef RIGHT_ASSOCIATIVE_UNARY
12865 return parser->current.type ==
type;
12872match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12873 return match1(parser, type1) || match1(parser, type2);
12880match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12881 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12888match4(
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) {
12889 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12896match5(
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) {
12897 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5);
12904match6(
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) {
12905 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
12912match8(
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) {
12913 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);
12924 if (match1(parser,
type)) {
12925 parser_lex(parser);
12936accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12937 if (match2(parser, type1, type2)) {
12938 parser_lex(parser);
12956expect1(
pm_parser_t *parser, pm_token_type_t
type, pm_diagnostic_id_t diag_id) {
12957 if (accept1(parser,
type))
return;
12959 const uint8_t *location = parser->previous.
end;
12960 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12962 parser->previous.
start = location;
12963 parser->previous.
type = 0;
12971expect2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
12972 if (accept2(parser, type1, type2))
return;
12974 const uint8_t *location = parser->previous.
end;
12975 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12977 parser->previous.
start = location;
12978 parser->previous.
type = 0;
12986expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12987 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12988 parser_lex(parser);
12990 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12991 parser->previous.
start = parser->previous.
end;
12992 parser->previous.
type = 0;
13004 if (accept1(parser,
type))
return;
13006 const uint8_t *start = opening->
start;
13007 pm_parser_err(parser, U32(start - parser->start), U32(opening->
end - start), diag_id);
13009 parser->previous.
start = parser->previous.
end;
13010 parser->previous.
type = 0;
13014#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
13015#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
13016#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
13017#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
13028#define PM_PARSE_ACCEPTS_STATEMENT ((uint8_t) 0x10)
13041#define PM_PARSE_ACCEPTS_COMMAND_DEF ((uint8_t) 0x20)
13044parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
13051parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
13052 pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
13053 pm_assert_value_expression(parser, node);
13076token_begins_expression_p(pm_token_type_t
type) {
13078 case PM_TOKEN_EQUAL_GREATER:
13079 case PM_TOKEN_KEYWORD_IN:
13083 case PM_TOKEN_BRACE_RIGHT:
13084 case PM_TOKEN_BRACKET_RIGHT:
13085 case PM_TOKEN_COLON:
13086 case PM_TOKEN_COMMA:
13087 case PM_TOKEN_EMBEXPR_END:
13089 case PM_TOKEN_LAMBDA_BEGIN:
13090 case PM_TOKEN_KEYWORD_DO:
13091 case PM_TOKEN_KEYWORD_DO_BLOCK:
13092 case PM_TOKEN_KEYWORD_DO_LAMBDA:
13093 case PM_TOKEN_KEYWORD_DO_LOOP:
13094 case PM_TOKEN_KEYWORD_END:
13095 case PM_TOKEN_KEYWORD_ELSE:
13096 case PM_TOKEN_KEYWORD_ELSIF:
13097 case PM_TOKEN_KEYWORD_ENSURE:
13098 case PM_TOKEN_KEYWORD_THEN:
13099 case PM_TOKEN_KEYWORD_RESCUE:
13100 case PM_TOKEN_KEYWORD_WHEN:
13101 case PM_TOKEN_NEWLINE:
13102 case PM_TOKEN_PARENTHESIS_RIGHT:
13103 case PM_TOKEN_SEMICOLON:
13109 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13111 case PM_TOKEN_UAMPERSAND:
13115 case PM_TOKEN_UCOLON_COLON:
13116 case PM_TOKEN_UMINUS:
13117 case PM_TOKEN_UMINUS_NUM:
13118 case PM_TOKEN_UPLUS:
13119 case PM_TOKEN_BANG:
13120 case PM_TOKEN_TILDE:
13121 case PM_TOKEN_UDOT_DOT:
13122 case PM_TOKEN_UDOT_DOT_DOT:
13129 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13149token_begins_pattern_p(pm_token_type_t
type) {
13151 token_begins_expression_p(
type) ||
13152 type == PM_TOKEN_USTAR ||
13153 type == PM_TOKEN_USTAR_STAR ||
13154 type == PM_TOKEN_CARET
13166token_begins_argument_p(pm_token_type_t
type) {
13168 token_begins_expression_p(
type) ||
13169 type == PM_TOKEN_UAMPERSAND ||
13170 type == PM_TOKEN_USTAR ||
13171 type == PM_TOKEN_USTAR_STAR
13180parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
13181 if (accept1(parser, PM_TOKEN_USTAR)) {
13183 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));
13184 return UP(pm_splat_node_create(parser, &
operator, expression));
13187 return parse_value_expression(parser, binding_power, flags, diag_id, depth);
13191pm_node_unreference_each(
const pm_node_t *node,
void *data) {
13192 switch (PM_NODE_TYPE(node)) {
13197 case PM_BREAK_NODE:
13199 case PM_REDO_NODE: {
13203 while (index < parser->current_block_exits->size) {
13204 pm_node_t *block_exit = parser->current_block_exits->
nodes[index];
13206 if (block_exit == node) {
13207 if (index + 1 < parser->current_block_exits->
size) {
13209 &parser->current_block_exits->
nodes[index],
13210 &parser->current_block_exits->
nodes[index + 1],
13211 (parser->current_block_exits->
size - index - 1) *
sizeof(
pm_node_t *)
13214 parser->current_block_exits->
size--;
13229 case PM_LOCAL_VARIABLE_READ_NODE:
13230 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13232 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
13234 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13235 if (implicit_parameters->
nodes[index] == node) {
13239 if (index != implicit_parameters->
size - 1) {
13240 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13243 implicit_parameters->
size--;
13262 pm_visit_node(node, pm_node_unreference_each, parser);
13275 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *name_field);
13276 size_t length = constant->length;
13277 uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
13279 memcpy(name, constant->start, length);
13280 name[length] =
'=';
13282 *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
13293 switch (PM_NODE_TYPE(target)) {
13294 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13295 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13296 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13297 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13298 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13299 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13300 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13304 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
13320 switch (PM_NODE_TYPE(target)) {
13321 case PM_ERROR_RECOVERY_NODE:
13323 case PM_SOURCE_ENCODING_NODE:
13324 case PM_FALSE_NODE:
13325 case PM_SOURCE_FILE_NODE:
13326 case PM_SOURCE_LINE_NODE:
13329 case PM_TRUE_NODE: {
13332 return parse_unwriteable_target(parser, target);
13334 case PM_CLASS_VARIABLE_READ_NODE:
13336 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13338 case PM_CONSTANT_PATH_NODE:
13339 if (context_def_p(parser)) {
13340 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13344 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13347 case PM_CONSTANT_READ_NODE:
13348 if (context_def_p(parser)) {
13349 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13353 target->
type = PM_CONSTANT_TARGET_NODE;
13356 case PM_BACK_REFERENCE_READ_NODE:
13357 case PM_NUMBERED_REFERENCE_READ_NODE:
13358 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13359 return UP(pm_error_recovery_node_create_unexpected(parser, target));
13360 case PM_GLOBAL_VARIABLE_READ_NODE:
13362 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13364 case PM_LOCAL_VARIABLE_READ_NODE: {
13365 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13366 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
13367 pm_node_unreference(parser, target);
13371 uint32_t name = cast->
name;
13372 uint32_t depth = cast->
depth;
13373 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13376 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13380 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13382 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
13384 pm_node_unreference(parser, target);
13388 case PM_INSTANCE_VARIABLE_READ_NODE:
13390 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13392 case PM_MULTI_TARGET_NODE:
13393 if (splat_parent) {
13396 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13400 case PM_SPLAT_NODE: {
13409 case PM_CALL_NODE: {
13421 (call->
block == NULL)
13434 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
13436 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
13440 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13441 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13444 parse_write_name(parser, &call->
name);
13445 return UP(pm_call_target_node_create(parser, call));
13452 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13453 return UP(pm_index_target_node_create(parser, call));
13461 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13472 pm_node_t *result = parse_target(parser, target, multiple,
false);
13477 !match1(parser, PM_TOKEN_EQUAL) &&
13478 !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
13479 !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13481 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13493 pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
13495 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13496 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
13507 switch (PM_NODE_TYPE(target)) {
13508 case PM_ERROR_RECOVERY_NODE:
13510 case PM_CLASS_VARIABLE_READ_NODE: {
13514 case PM_CONSTANT_PATH_NODE: {
13517 if (context_def_p(parser)) {
13518 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13521 return parse_shareable_constant_write(parser, node);
13523 case PM_CONSTANT_READ_NODE: {
13526 if (context_def_p(parser)) {
13527 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13530 return parse_shareable_constant_write(parser, node);
13532 case PM_BACK_REFERENCE_READ_NODE:
13533 case PM_NUMBERED_REFERENCE_READ_NODE:
13534 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13536 case PM_GLOBAL_VARIABLE_READ_NODE: {
13540 case PM_LOCAL_VARIABLE_READ_NODE: {
13545 uint32_t depth = local_read->
depth;
13546 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13548 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13549 pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13550 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
13551 pm_node_unreference(parser, target);
13554 pm_locals_unread(&scope->locals, name);
13556 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
13558 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13560 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
13562 pm_node_unreference(parser, target);
13566 case PM_INSTANCE_VARIABLE_READ_NODE: {
13570 case PM_MULTI_TARGET_NODE:
13572 case PM_SPLAT_NODE: {
13580 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
13582 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
13584 case PM_CALL_NODE: {
13596 (call->
block == NULL)
13610 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
13611 pm_parser_local_add_location(parser, &message_loc, 0);
13613 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));
13614 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
13633 pm_arguments_node_arguments_append(parser->arena, arguments, value);
13634 PM_NODE_LENGTH_SET_NODE(call, arguments);
13635 call->
equal_loc = TOK2LOC(parser,
operator);
13637 parse_write_name(parser, &call->
name);
13638 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13647 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13649 call->
arguments = pm_arguments_node_create(parser);
13652 pm_arguments_node_arguments_append(parser->arena, call->
arguments, value);
13653 PM_NODE_LENGTH_SET_NODE(target, value);
13656 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13657 call->
equal_loc = TOK2LOC(parser,
operator);
13661 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13676 pm_node_unreference(parser, value);
13683 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13696 switch (PM_NODE_TYPE(target)) {
13697 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13698 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13699 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13700 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13701 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13702 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13703 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13724parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13725 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13728 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13730 while (accept1(parser, PM_TOKEN_COMMA)) {
13731 if (accept1(parser, PM_TOKEN_USTAR)) {
13736 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13739 pm_token_t star_operator = parser->previous;
13742 if (token_begins_expression_p(parser->current.type)) {
13743 name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13744 name = parse_target(parser, name,
true,
true);
13747 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13748 pm_multi_target_node_targets_append(parser, result, splat);
13750 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
13751 context_push(parser, PM_CONTEXT_MULTI_TARGET);
13752 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13753 target = parse_target(parser, target,
true,
false);
13755 pm_multi_target_node_targets_append(parser, result, target);
13756 context_pop(parser);
13757 }
else if (token_begins_expression_p(parser->current.type)) {
13758 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13759 target = parse_target(parser, target,
true,
false);
13761 pm_multi_target_node_targets_append(parser, result, target);
13762 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13765 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
13766 pm_multi_target_node_targets_append(parser, result, rest);
13779parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13780 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13785 if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
13786 accept1(parser, PM_TOKEN_NEWLINE);
13790 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13791 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13801parse_statements(
pm_parser_t *parser, pm_context_t context, uint16_t depth) {
13804 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13807 if (context_terminator(context, &parser->current))
return NULL;
13813 context_push(parser, context);
13816 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13817 pm_statements_node_body_append(parser, statements, node,
true);
13821 if (parser->recovering) {
13824 if (context_terminator(context, &parser->current)) parser->recovering =
false;
13830 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13833 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13834 if (context_terminator(context, &parser->current))
break;
13844 if (context_terminator(context, &parser->current))
break;
13856 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
13857 parser_lex(parser);
13863 if (match1(parser, PM_TOKEN_EOF)) {
13864 parser->recovering =
true;
13868 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13869 if (context_terminator(context, &parser->current))
break;
13870 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13874 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
13875 parser->previous.
start = parser->previous.
end;
13876 parser->previous.
type = 0;
13880 context_pop(parser);
13882 bool last_value =
true;
13884 case PM_CONTEXT_BEGIN_ENSURE:
13885 case PM_CONTEXT_DEF_ENSURE:
13886 last_value =
false;
13891 pm_void_statements_check(parser, statements, last_value);
13902 pm_static_literal_inspect(&buffer, &parser->line_offsets, parser->start, parser->start_line, parser->encoding, duplicated);
13904 pm_diagnostic_list_append_format(
13905 &parser->metadata_arena,
13906 &parser->warning_list,
13909 PM_WARN_DUPLICATED_HASH_KEY,
13910 (
int) pm_buffer_length(&buffer),
13911 pm_buffer_value(&buffer),
13912 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line
13915 pm_buffer_cleanup(&buffer);
13924 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
true);
13926 if (duplicated != NULL) {
13927 pm_hash_key_duplicated_warn(parser, duplicated, node);
13942 for (
size_t index = 0; index < elements->
size; index++) {
13945 switch (PM_NODE_TYPE(element)) {
13946 case PM_ASSOC_NODE: {
13948 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, key,
true);
13950 if (duplicated != NULL && PM_NODE_START(duplicated) < boundary) {
13951 pm_hash_key_duplicated_warn(parser, duplicated, key);
13956 case PM_ASSOC_SPLAT_NODE: {
13959 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13960 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, boundary);
13979 if ((previous = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
false)) != NULL) {
13980 pm_diagnostic_list_append_format(
13981 &parser->metadata_arena,
13982 &parser->warning_list,
13983 PM_NODE_START(node),
13984 PM_NODE_LENGTH(node),
13985 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13986 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line,
13987 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).
line
13997 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13998 bool contains_keyword_splat =
false;
14003 switch (parser->current.type) {
14004 case PM_TOKEN_USTAR_STAR: {
14005 parser_lex(parser);
14009 if (token_begins_expression_p(parser->current.type)) {
14010 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));
14014 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
14015 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, PM_NODE_START(value));
14018 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
14021 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
14022 contains_keyword_splat =
true;
14025 case PM_TOKEN_LABEL: {
14027 parser_lex(parser);
14029 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
14030 pm_hash_key_static_literals_add(parser, literals, key);
14034 if (token_begins_expression_p(parser->current.type)) {
14035 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14037 if (parser->encoding->isupper_char(label.
start, (label.
end - 1) - label.
start)) {
14038 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
14039 value = UP(pm_constant_read_node_create(parser, &constant));
14044 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14045 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14047 depth = pm_parser_local_depth(parser, &identifier);
14051 value = UP(pm_call_node_variable_call_create(parser, &identifier));
14053 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
14058 value = UP(pm_implicit_node_create(parser, value));
14061 element = UP(pm_assoc_node_create(parser, key, NULL, value));
14065 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));
14069 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
14070 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
14073 pm_hash_key_static_literals_add(parser, literals, key);
14076 if (!pm_symbol_node_label_p(parser, key)) {
14077 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
14078 operator = parser->previous;
14081 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));
14082 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
14087 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
14088 pm_hash_node_elements_append(parser->arena, (
pm_hash_node_t *) node, element);
14094 if (!accept1(parser, PM_TOKEN_COMMA))
break;
14098 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
14102 if (token_begins_expression_p(parser->current.type))
continue;
14108 return contains_keyword_splat;
14113 if (pm_symbol_node_label_p(parser, argument)) {
14117 switch (PM_NODE_TYPE(argument)) {
14118 case PM_CALL_NODE: {
14121 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
14124 if (cast->
block != NULL) {
14132 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
14141 arguments->
arguments = pm_arguments_node_create(parser);
14144 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, argument);
14155 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
14174 call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE) &&
14189 switch (PM_NODE_TYPE(node)) {
14190 case PM_CALL_NODE: {
14195 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)) {
14200 if (pm_constant_path_command_call_p(parser, call)) {
14207 return pm_command_call_value_p(parser, call->
receiver);
14212 case PM_SUPER_NODE: {
14219 !(cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE));
14221 case PM_YIELD_NODE: {
14225 case PM_RESCUE_MODIFIER_NODE:
14227 case PM_DEF_NODE: {
14231 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
14234 return pm_command_call_value_p(parser, body);
14254 switch (PM_NODE_TYPE(node)) {
14256 return pm_constant_path_command_call_p(parser, (
const pm_call_node_t *) node);
14258 return pm_command_call_value_p(parser, node);
14271pm_block_call_p(
const pm_node_t *node) {
14272 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
14303 if (PM_NODE_TYPE_P(node, PM_SUPER_NODE)) {
14315parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
14316 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
14321 match2(parser, terminator, PM_TOKEN_EOF) ||
14322 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14323 context_terminator(parser->current_context->context, &parser->current)
14328 bool parsed_first_argument =
false;
14329 bool parsed_bare_hash =
false;
14330 bool parsed_block_argument =
false;
14331 bool parsed_forwarding_arguments =
false;
14333 while (!match1(parser, PM_TOKEN_EOF)) {
14334 if (parsed_forwarding_arguments) {
14335 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14340 switch (parser->current.type) {
14341 case PM_TOKEN_USTAR_STAR:
14342 case PM_TOKEN_LABEL: {
14343 if (parsed_bare_hash) {
14344 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14348 argument = UP(hash);
14351 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
14353 parse_arguments_append(parser, arguments, argument);
14355 pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14356 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14357 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14359 pm_static_literals_free(&hash_keys);
14360 parsed_bare_hash =
true;
14364 case PM_TOKEN_UAMPERSAND: {
14365 parser_lex(parser);
14369 if (token_begins_expression_p(parser->current.type)) {
14370 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14372 pm_parser_scope_forwarding_block_check(parser, &
operator);
14375 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
14376 if (parsed_block_argument) {
14377 parse_arguments_append(parser, arguments, argument);
14379 arguments->
block = argument;
14382 if (match1(parser, PM_TOKEN_COMMA)) {
14383 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14386 parsed_block_argument =
true;
14389 case PM_TOKEN_USTAR: {
14390 parser_lex(parser);
14393 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14394 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14395 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
14396 if (parsed_bare_hash) {
14397 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14400 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));
14402 if (parsed_bare_hash) {
14403 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);
14406 argument = UP(pm_splat_node_create(parser, &
operator, expression));
14409 parse_arguments_append(parser, arguments, argument);
14412 case PM_TOKEN_UDOT_DOT_DOT: {
14413 if (accepts_forwarding) {
14414 parser_lex(parser);
14416 if (token_begins_expression_p(parser->current.type)) {
14421 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));
14426 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14428 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14431 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
14433 pm_parser_scope_forwarding_all_check(parser, &parser->previous);
14434 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14435 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14438 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->previous));
14439 parse_arguments_append(parser, arguments, argument);
14440 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14442 parsed_forwarding_arguments =
true;
14449 if (argument == NULL) {
14454 uint8_t command_flags = 0;
14455 if (!parsed_first_argument) {
14456 command_flags = PM_PARSE_ACCEPTS_COMMAND_CALL;
14457 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) command_flags |= PM_PARSE_ACCEPTS_COMMAND_DEF;
14460 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | command_flags | PM_PARSE_ACCEPTS_LABEL), PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14463 bool contains_keywords =
false;
14464 bool contains_keyword_splat =
false;
14466 if (argument_allowed_for_bare_hash(parser, argument)) {
14467 if (parsed_bare_hash) {
14468 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14477 if (pm_command_call_value_p(parser, argument) || pm_block_call_p(argument)) {
14478 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->previous.
type));
14482 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
14483 operator = parser->previous;
14487 contains_keywords =
true;
14491 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14494 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));
14495 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
14497 pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
14498 argument = UP(bare_hash);
14501 if (accept1(parser, PM_TOKEN_COMMA) && (
14502 token_begins_expression_p(parser->current.type) ||
14503 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14505 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
14508 pm_static_literals_free(&hash_keys);
14509 parsed_bare_hash =
true;
14512 parse_arguments_append(parser, arguments, argument);
14514 pm_node_flags_t node_flags = 0;
14515 if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14516 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14517 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14523 parsed_first_argument =
true;
14526 if (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_NODE) || parser->recovering)
break;
14531 bool accepted_newline =
false;
14532 if (terminator != PM_TOKEN_EOF) {
14533 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14536 if (parser->previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14540 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14543 if (accepted_newline) {
14544 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14550 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
14553 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14560 if (pm_command_before_comma_p(parser, argument)) {
14561 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14571 if (match1(parser, terminator)) {
14577 if (parsed_forwarding_arguments) {
14578 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14597parse_required_destructured_parameter(
pm_parser_t *parser) {
14598 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14601 pm_multi_target_node_opening_set(parser, node, &parser->previous);
14610 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14611 param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14612 pm_multi_target_node_targets_append(parser, node, param);
14613 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14617 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
14618 param = UP(parse_required_destructured_parameter(parser));
14619 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14623 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14625 value = UP(pm_required_parameter_node_create(parser, &name));
14626 if (pm_parser_parameter_name_check(parser, &name)) {
14627 pm_node_flag_set_repeated_parameter(value);
14629 pm_parser_local_add_token(parser, &name, 1);
14632 param = UP(pm_splat_node_create(parser, &star, value));
14634 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14637 param = UP(pm_required_parameter_node_create(parser, &name));
14638 if (pm_parser_parameter_name_check(parser, &name)) {
14639 pm_node_flag_set_repeated_parameter(param);
14641 pm_parser_local_add_token(parser, &name, 1);
14644 pm_multi_target_node_targets_append(parser, node, param);
14645 }
while (accept1(parser, PM_TOKEN_COMMA));
14647 accept1(parser, PM_TOKEN_NEWLINE);
14648 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14649 pm_multi_target_node_closing_set(parser, node, &parser->previous);
14659 PM_PARAMETERS_NO_CHANGE = 0,
14660 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14661 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14662 PM_PARAMETERS_ORDER_KEYWORDS,
14663 PM_PARAMETERS_ORDER_REST,
14664 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14665 PM_PARAMETERS_ORDER_OPTIONAL,
14666 PM_PARAMETERS_ORDER_NAMED,
14667 PM_PARAMETERS_ORDER_NONE,
14668} pm_parameters_order_t;
14673static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14674 [0] = PM_PARAMETERS_NO_CHANGE,
14675 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14676 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14677 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14678 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14679 [PM_TOKEN_PARENTHESIS_LEFT_GROUPING] = PM_PARAMETERS_ORDER_NAMED,
14680 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14681 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14682 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14683 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14684 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14685 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14697 pm_parameters_order_t state = parameters_ordering[token->type];
14698 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14702 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14703 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14705 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14709 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14710 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14712 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14713 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14715 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14717 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14721 if (state < *current) *current = state;
14726parse_parameters_handle_trailing_comma(
14729 pm_parameters_order_t order,
14731 bool allows_trailing_comma
14733 if (!allows_trailing_comma) {
14734 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14739 if (order >= PM_PARAMETERS_ORDER_NAMED) {
14741 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14743 if (params->
rest == NULL) {
14744 pm_parameters_node_rest_set(params, param);
14746 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14747 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14751 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14756 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
14757 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14768 pm_binding_power_t binding_power,
14769 bool uses_parentheses,
14770 bool allows_trailing_comma,
14771 bool allows_forwarding_parameters,
14772 bool accepts_blocks_in_defaults,
14774 pm_diagnostic_id_t diag_id_forwarding,
14777 pm_do_loop_stack_push(parser,
false);
14780 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14783 bool parsing =
true;
14785 switch (parser->current.type) {
14786 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
14787 update_parameter_state(parser, &parser->current, &order);
14788 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
14790 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14791 pm_parameters_node_requireds_append(parser->arena, params, param);
14793 pm_parameters_node_posts_append(parser->arena, params, param);
14797 case PM_TOKEN_UAMPERSAND:
14798 case PM_TOKEN_AMPERSAND: {
14799 update_parameter_state(parser, &parser->current, &order);
14800 parser_lex(parser);
14805 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14806 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->previous);
14810 bool repeated =
false;
14811 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14812 name = parser->previous;
14813 repeated = pm_parser_parameter_name_check(parser, &name);
14814 pm_parser_local_add_token(parser, &name, 1);
14816 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
14819 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
14821 pm_node_flag_set_repeated_parameter(param);
14825 if (params->
block == NULL) {
14826 pm_parameters_node_block_set(params, param);
14828 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
14829 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14834 case PM_TOKEN_UDOT_DOT_DOT: {
14835 if (!allows_forwarding_parameters) {
14836 pm_parser_err_current(parser, diag_id_forwarding);
14839 bool succeeded = update_parameter_state(parser, &parser->current, &order);
14840 parser_lex(parser);
14842 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
14849 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, keyword_rest)));
14850 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14854 pm_parameters_node_keyword_rest_set(params, UP(param));
14857 case PM_TOKEN_CLASS_VARIABLE:
14858 case PM_TOKEN_IDENTIFIER:
14859 case PM_TOKEN_CONSTANT:
14860 case PM_TOKEN_INSTANCE_VARIABLE:
14861 case PM_TOKEN_GLOBAL_VARIABLE:
14862 case PM_TOKEN_METHOD_NAME: {
14863 parser_lex(parser);
14864 switch (parser->previous.
type) {
14865 case PM_TOKEN_CONSTANT:
14866 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14868 case PM_TOKEN_INSTANCE_VARIABLE:
14869 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14871 case PM_TOKEN_GLOBAL_VARIABLE:
14872 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14874 case PM_TOKEN_CLASS_VARIABLE:
14875 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14877 case PM_TOKEN_METHOD_NAME:
14878 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14883 if (parser->current.type == PM_TOKEN_EQUAL) {
14884 update_parameter_state(parser, &parser->current, &order);
14886 update_parameter_state(parser, &parser->previous, &order);
14890 bool repeated = pm_parser_parameter_name_check(parser, &name);
14891 pm_parser_local_add_token(parser, &name, 1);
14893 if (match1(parser, PM_TOKEN_EQUAL)) {
14895 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14896 parser_lex(parser);
14899 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14901 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14902 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14903 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14908 pm_node_flag_set_repeated_parameter(UP(param));
14910 pm_parameters_node_optionals_append(parser->arena, params, param);
14915 if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14916 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
14919 context_pop(parser);
14924 if (parser->recovering) {
14928 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14931 pm_node_flag_set_repeated_parameter(UP(param));
14933 pm_parameters_node_requireds_append(parser->arena, params, UP(param));
14937 pm_node_flag_set_repeated_parameter(UP(param));
14939 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14944 case PM_TOKEN_LABEL: {
14945 if (!uses_parentheses && !in_block) parser->in_keyword_arg =
true;
14946 update_parameter_state(parser, &parser->current, &order);
14948 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14949 parser_lex(parser);
14955 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)) {
14956 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14957 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14958 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14961 bool repeated = pm_parser_parameter_name_check(parser, &local);
14962 pm_parser_local_add_token(parser, &local, 1);
14964 switch (parser->current.type) {
14965 case PM_TOKEN_COMMA:
14966 case PM_TOKEN_PARENTHESIS_RIGHT:
14967 case PM_TOKEN_PIPE: {
14968 context_pop(parser);
14970 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14972 pm_node_flag_set_repeated_parameter(param);
14975 pm_parameters_node_keywords_append(parser->arena, params, param);
14978 case PM_TOKEN_SEMICOLON:
14979 case PM_TOKEN_NEWLINE: {
14980 context_pop(parser);
14982 if (uses_parentheses) {
14987 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14989 pm_node_flag_set_repeated_parameter(param);
14992 pm_parameters_node_keywords_append(parser->arena, params, param);
14998 if (token_begins_expression_p(parser->current.type)) {
15000 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
15002 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
15003 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));
15004 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
15006 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
15007 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
15010 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
15013 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
15017 pm_node_flag_set_repeated_parameter(param);
15020 context_pop(parser);
15021 pm_parameters_node_keywords_append(parser->arena, params, param);
15026 if (parser->recovering) {
15033 parser->in_keyword_arg =
false;
15036 case PM_TOKEN_USTAR:
15037 case PM_TOKEN_STAR: {
15038 update_parameter_state(parser, &parser->current, &order);
15039 parser_lex(parser);
15043 bool repeated =
false;
15045 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
15046 name = parser->previous;
15047 repeated = pm_parser_parameter_name_check(parser, &name);
15048 pm_parser_local_add_token(parser, &name, 1);
15050 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
15053 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
15055 pm_node_flag_set_repeated_parameter(param);
15058 if (params->
rest == NULL) {
15059 pm_parameters_node_rest_set(params, param);
15061 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
15062 pm_parameters_node_posts_append(parser->arena, params, param);
15067 case PM_TOKEN_STAR_STAR:
15068 case PM_TOKEN_USTAR_STAR: {
15069 pm_parameters_order_t previous_order = order;
15070 update_parameter_state(parser, &parser->current, &order);
15071 parser_lex(parser);
15076 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
15077 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
15078 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
15081 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
15085 bool repeated =
false;
15086 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
15087 name = parser->previous;
15088 repeated = pm_parser_parameter_name_check(parser, &name);
15089 pm_parser_local_add_token(parser, &name, 1);
15091 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
15094 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
15096 pm_node_flag_set_repeated_parameter(param);
15101 pm_parameters_node_keyword_rest_set(params, param);
15103 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
15104 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
15110 if (parser->previous.
type == PM_TOKEN_COMMA) {
15111 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
15121 if (!parsing)
break;
15123 bool accepted_newline =
false;
15124 if (uses_parentheses) {
15125 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
15128 if (accept1(parser, PM_TOKEN_COMMA)) {
15131 if (accepted_newline) {
15132 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
15140 pm_do_loop_stack_pop(parser);
15143 if (PM_NODE_START(params) == PM_NODE_END(params)) {
15156 if (parser->heredoc_end == NULL) {
15160 return parser->line_offsets.
size - 1;
15166 return (
size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
15175token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
15176 const uint8_t *cursor = parser->start + parser->line_offsets.
offsets[newline_index];
15177 const uint8_t *end = token->start;
15181 newline_index == 0 &&
15182 parser->start[0] == 0xef &&
15183 parser->start[1] == 0xbb &&
15184 parser->start[2] == 0xbf
15187 int64_t column = 0;
15188 for (; cursor < end; cursor++) {
15191 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15198 if (break_on_non_space)
return -1;
15211parser_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) {
15213 if (!parser->warn_mismatched_indentation)
return;
15216 size_t closing_newline_index = token_newline_index(parser);
15217 if (opening_newline_index == closing_newline_index)
return;
15222 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15223 if (!if_after_else && (opening_column == -1))
return;
15227 pm_token_t *closing_token = &parser->current;
15230 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15231 if ((closing_column == -1) || (opening_column == closing_column))
return;
15235 if (allow_indent && (closing_column > opening_column))
return;
15238 PM_PARSER_WARN_FORMAT(
15240 PM_TOKEN_START(parser, closing_token),
15241 PM_TOKEN_LENGTH(closing_token),
15242 PM_WARN_INDENTATION_MISMATCH,
15243 (
int) (closing_token->
end - closing_token->
start),
15244 (
const char *) closing_token->
start,
15245 (
int) (opening_token->
end - opening_token->
start),
15246 (
const char *) opening_token->
start,
15247 ((int32_t) opening_newline_index) + parser->start_line
15252 PM_RESCUES_BEGIN = 1,
15259} pm_rescues_type_t;
15269 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15270 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15271 parser_lex(parser);
15273 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
15275 switch (parser->current.type) {
15276 case PM_TOKEN_EQUAL_GREATER: {
15280 parser_lex(parser);
15281 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15283 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15284 reference = parse_target(parser, reference,
false,
false);
15286 pm_rescue_node_reference_set(rescue, reference);
15289 case PM_TOKEN_NEWLINE:
15290 case PM_TOKEN_SEMICOLON:
15291 case PM_TOKEN_KEYWORD_THEN:
15296 if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
15301 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15302 pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
15306 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15310 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15311 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15313 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15314 reference = parse_target(parser, reference,
false,
false);
15316 pm_rescue_node_reference_set(rescue, reference);
15319 }
while (accept1(parser, PM_TOKEN_COMMA));
15324 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15325 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15329 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15333 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15334 pm_accepts_block_stack_push(parser,
true);
15335 pm_context_t context;
15338 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_RESCUE;
break;
15339 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_RESCUE;
break;
15340 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_RESCUE;
break;
15341 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_RESCUE;
break;
15342 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE;
break;
15343 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE;
break;
15344 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE;
break;
15345 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15349 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15351 pm_accepts_block_stack_pop(parser);
15352 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15355 if (current == NULL) {
15356 pm_begin_node_rescue_clause_set(parent_node, rescue);
15358 pm_rescue_node_subsequent_set(current, rescue);
15367 if (current != NULL) {
15370 while (clause != NULL) {
15371 PM_NODE_LENGTH_SET_NODE(clause, current);
15377 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15378 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15379 opening_newline_index = token_newline_index(parser);
15381 else_keyword = parser->current;
15382 opening = &else_keyword;
15384 parser_lex(parser);
15385 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15388 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15389 pm_accepts_block_stack_push(parser,
true);
15390 pm_context_t context;
15393 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ELSE;
break;
15394 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ELSE;
break;
15395 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ELSE;
break;
15396 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ELSE;
break;
15397 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE;
break;
15398 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE;
break;
15399 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE;
break;
15400 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_ELSE;
break;
15403 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15404 pm_accepts_block_stack_pop(parser);
15406 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15409 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
15410 pm_begin_node_else_clause_set(parent_node, else_clause);
15414 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
15417 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15418 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15419 pm_token_t ensure_keyword = parser->current;
15421 parser_lex(parser);
15422 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15425 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15426 pm_accepts_block_stack_push(parser,
true);
15427 pm_context_t context;
15430 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ENSURE;
break;
15431 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ENSURE;
break;
15432 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ENSURE;
break;
15433 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ENSURE;
break;
15434 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE;
break;
15435 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE;
break;
15436 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE;
break;
15437 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15440 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15441 pm_accepts_block_stack_pop(parser);
15443 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15446 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
15447 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15450 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15451 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15452 pm_begin_node_end_keyword_set(parser, parent_node, &parser->current);
15455 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
15465 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
15466 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15469 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
15478parse_block_parameters(
15480 bool allows_trailing_comma,
15482 bool is_lambda_literal,
15483 bool accepts_blocks_in_defaults,
15487 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15488 if (!is_lambda_literal) {
15489 context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
15491 parameters = parse_parameters(
15493 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15495 allows_trailing_comma,
15497 accepts_blocks_in_defaults,
15499 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
15500 (uint16_t) (depth + 1)
15502 if (!is_lambda_literal) {
15503 context_pop(parser);
15508 if (opening != NULL) {
15509 accept1(parser, PM_TOKEN_NEWLINE);
15511 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15513 switch (parser->current.type) {
15514 case PM_TOKEN_CONSTANT:
15515 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15516 parser_lex(parser);
15518 case PM_TOKEN_INSTANCE_VARIABLE:
15519 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15520 parser_lex(parser);
15522 case PM_TOKEN_GLOBAL_VARIABLE:
15523 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15524 parser_lex(parser);
15526 case PM_TOKEN_CLASS_VARIABLE:
15527 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15528 parser_lex(parser);
15531 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15535 bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
15536 pm_parser_local_add_token(parser, &parser->previous, 1);
15539 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
15541 pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
15542 }
while (accept1(parser, PM_TOKEN_COMMA));
15546 return block_parameters;
15554outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15555 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15556 if (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15567static const char *
const pm_numbered_parameter_names[] = {
15568 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15578 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
15582 if (parameters != NULL) {
15584 if (implicit_parameters->
size > 0) {
15587 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15588 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15589 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15590 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15592 assert(
false &&
"unreachable");
15601 if (implicit_parameters->
size == 0) {
15608 uint8_t numbered_parameter = 0;
15609 bool it_parameter =
false;
15611 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15614 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15615 if (it_parameter) {
15616 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15617 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15618 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15619 }
else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
15620 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15621 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
15622 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->
location.
start + 1] -
'0'));
15624 assert(
false &&
"unreachable");
15626 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15627 if (numbered_parameter > 0) {
15628 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15630 it_parameter =
true;
15635 if (numbered_parameter > 0) {
15638 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15639 scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15641 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
15644 if (it_parameter) {
15645 return UP(pm_it_parameters_node_create(parser, opening, closing));
15655parse_block(
pm_parser_t *parser, uint16_t depth) {
15657 accept1(parser, PM_TOKEN_NEWLINE);
15663 bool do_block = opening.
type != PM_TOKEN_BRACE_LEFT && opening.
type != PM_TOKEN_BRACE_LEFT_ARGUMENT;
15664 if (do_block) pm_accepts_block_stack_push(parser,
true);
15665 pm_parser_scope_push(parser,
false);
15669 if (accept1(parser, PM_TOKEN_PIPE)) {
15670 pm_token_t block_parameters_opening = parser->previous;
15671 if (match1(parser, PM_TOKEN_PIPE)) {
15672 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15673 parser->command_start =
true;
15674 parser_lex(parser);
15676 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15677 accept1(parser, PM_TOKEN_NEWLINE);
15678 parser->command_start =
true;
15679 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15682 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
15685 accept1(parser, PM_TOKEN_NEWLINE);
15689 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15690 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
15693 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
15695 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15696 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15697 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)));
15700 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15701 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15702 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
15708 pm_accepts_block_stack_pop(parser);
15709 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
15713 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
15714 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
15716 pm_parser_scope_pop(parser);
15717 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
15732parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool full_arguments, uint8_t flags, uint16_t depth) {
15737 !token_begins_expression_p(parser->current.type) &&
15738 !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)
15743 bool found =
false;
15744 bool parsed_command_args =
false;
15746 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15748 arguments->
opening_loc = TOK2LOC(parser, &parser->previous);
15750 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15751 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15753 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
15761 if (!full_arguments && parser->previous.
type == PM_TOKEN_COMMA) {
15762 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15765 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15766 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
15767 parser->previous.
start = parser->previous.
end;
15768 parser->previous.
type = 0;
15771 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15773 }
else if ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && token_begins_argument_p(parser->current.type) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
15775 parsed_command_args =
true;
15785 bool lookahead_delimiter = match5(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_BRACKET_LEFT_ARRAY);
15786 if (lookahead_delimiter) pm_accepts_block_stack_pop(parser);
15787 pm_accepts_block_stack_push(parser,
false);
15788 if (lookahead_delimiter) pm_accepts_block_stack_push(parser,
true);
15793 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
15798 if (parser->previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15799 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15807 bool lookahead_brace = match2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT);
15808 if (lookahead_brace) pm_accepts_block_stack_pop(parser);
15809 pm_accepts_block_stack_pop(parser);
15810 if (lookahead_brace) pm_accepts_block_stack_push(parser,
true);
15816 if (full_arguments) {
15819 if (accept2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT)) {
15821 block = parse_block(parser, (uint16_t) (depth + 1));
15822 pm_arguments_validate_block(parser, arguments, block);
15823 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15825 block = parse_block(parser, (uint16_t) (depth + 1));
15826 }
else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
15828 block = parse_block(parser, (uint16_t) (depth + 1));
15831 if (block != NULL) {
15833 arguments->
block = UP(block);
15835 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
15837 if (arguments->
block != NULL) {
15839 arguments->
arguments = pm_arguments_node_create(parser);
15841 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, arguments->
block);
15843 arguments->
block = UP(block);
15857 bool in_sclass =
false;
15858 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15859 switch (context_node->context) {
15860 case PM_CONTEXT_BEGIN_ELSE:
15861 case PM_CONTEXT_BEGIN_ENSURE:
15862 case PM_CONTEXT_BEGIN_RESCUE:
15863 case PM_CONTEXT_BEGIN:
15864 case PM_CONTEXT_CASE_IN:
15865 case PM_CONTEXT_CASE_WHEN:
15866 case PM_CONTEXT_DEFAULT_PARAMS:
15867 case PM_CONTEXT_DEFINED:
15868 case PM_CONTEXT_ELSE:
15869 case PM_CONTEXT_ELSIF:
15870 case PM_CONTEXT_EMBEXPR:
15871 case PM_CONTEXT_FOR_INDEX:
15872 case PM_CONTEXT_FOR:
15873 case PM_CONTEXT_IF:
15874 case PM_CONTEXT_LOOP_PREDICATE:
15875 case PM_CONTEXT_MAIN:
15876 case PM_CONTEXT_MULTI_TARGET:
15877 case PM_CONTEXT_PARENS:
15878 case PM_CONTEXT_POSTEXE:
15879 case PM_CONTEXT_PREDICATE:
15880 case PM_CONTEXT_PREEXE:
15881 case PM_CONTEXT_RESCUE_MODIFIER:
15882 case PM_CONTEXT_TERNARY:
15883 case PM_CONTEXT_UNLESS:
15884 case PM_CONTEXT_UNTIL:
15885 case PM_CONTEXT_WHILE:
15889 case PM_CONTEXT_SCLASS_ELSE:
15890 case PM_CONTEXT_SCLASS_ENSURE:
15891 case PM_CONTEXT_SCLASS_RESCUE:
15892 case PM_CONTEXT_SCLASS:
15895 case PM_CONTEXT_CLASS_ELSE:
15896 case PM_CONTEXT_CLASS_ENSURE:
15897 case PM_CONTEXT_CLASS_RESCUE:
15898 case PM_CONTEXT_CLASS:
15899 case PM_CONTEXT_MODULE_ELSE:
15900 case PM_CONTEXT_MODULE_ENSURE:
15901 case PM_CONTEXT_MODULE_RESCUE:
15902 case PM_CONTEXT_MODULE:
15904 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15906 case PM_CONTEXT_BLOCK_BRACES:
15907 case PM_CONTEXT_BLOCK_ELSE:
15908 case PM_CONTEXT_BLOCK_ENSURE:
15909 case PM_CONTEXT_BLOCK_KEYWORDS:
15910 case PM_CONTEXT_BLOCK_RESCUE:
15911 case PM_CONTEXT_BLOCK_PARAMETERS:
15912 case PM_CONTEXT_DEF_ELSE:
15913 case PM_CONTEXT_DEF_ENSURE:
15914 case PM_CONTEXT_DEF_PARAMS:
15915 case PM_CONTEXT_DEF_RESCUE:
15916 case PM_CONTEXT_DEF:
15917 case PM_CONTEXT_LAMBDA_BRACES:
15918 case PM_CONTEXT_LAMBDA_DO_END:
15919 case PM_CONTEXT_LAMBDA_ELSE:
15920 case PM_CONTEXT_LAMBDA_ENSURE:
15921 case PM_CONTEXT_LAMBDA_RESCUE:
15925 case PM_CONTEXT_NONE:
15926 case PM_CONTEXT_MAXIMUM:
15928 assert(
false &&
"unreachable");
15932 if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
15933 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15943 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15944 switch (context_node->context) {
15945 case PM_CONTEXT_BLOCK_BRACES:
15946 case PM_CONTEXT_BLOCK_KEYWORDS:
15947 case PM_CONTEXT_BLOCK_ELSE:
15948 case PM_CONTEXT_BLOCK_ENSURE:
15949 case PM_CONTEXT_BLOCK_PARAMETERS:
15950 case PM_CONTEXT_BLOCK_RESCUE:
15951 case PM_CONTEXT_DEFINED:
15952 case PM_CONTEXT_FOR:
15953 case PM_CONTEXT_LAMBDA_BRACES:
15954 case PM_CONTEXT_LAMBDA_DO_END:
15955 case PM_CONTEXT_LAMBDA_ELSE:
15956 case PM_CONTEXT_LAMBDA_ENSURE:
15957 case PM_CONTEXT_LAMBDA_RESCUE:
15958 case PM_CONTEXT_LOOP_PREDICATE:
15959 case PM_CONTEXT_UNTIL:
15960 case PM_CONTEXT_WHILE:
15964 case PM_CONTEXT_POSTEXE:
15966 if (context_node->context == PM_CONTEXT_POSTEXE) {
15967 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
15972 case PM_CONTEXT_DEF:
15973 case PM_CONTEXT_DEF_PARAMS:
15974 case PM_CONTEXT_DEF_ELSE:
15975 case PM_CONTEXT_DEF_ENSURE:
15976 case PM_CONTEXT_DEF_RESCUE:
15977 case PM_CONTEXT_MAIN:
15978 case PM_CONTEXT_PREEXE:
15979 case PM_CONTEXT_SCLASS:
15980 case PM_CONTEXT_SCLASS_ELSE:
15981 case PM_CONTEXT_SCLASS_ENSURE:
15982 case PM_CONTEXT_SCLASS_RESCUE:
15992 assert(parser->current_block_exits != NULL);
15993 pm_node_list_append(parser->arena, parser->current_block_exits, node);
15995 case PM_CONTEXT_BEGIN_ELSE:
15996 case PM_CONTEXT_BEGIN_ENSURE:
15997 case PM_CONTEXT_BEGIN_RESCUE:
15998 case PM_CONTEXT_BEGIN:
15999 case PM_CONTEXT_CASE_IN:
16000 case PM_CONTEXT_CASE_WHEN:
16001 case PM_CONTEXT_CLASS_ELSE:
16002 case PM_CONTEXT_CLASS_ENSURE:
16003 case PM_CONTEXT_CLASS_RESCUE:
16004 case PM_CONTEXT_CLASS:
16005 case PM_CONTEXT_DEFAULT_PARAMS:
16006 case PM_CONTEXT_ELSE:
16007 case PM_CONTEXT_ELSIF:
16008 case PM_CONTEXT_EMBEXPR:
16009 case PM_CONTEXT_FOR_INDEX:
16010 case PM_CONTEXT_IF:
16011 case PM_CONTEXT_MODULE_ELSE:
16012 case PM_CONTEXT_MODULE_ENSURE:
16013 case PM_CONTEXT_MODULE_RESCUE:
16014 case PM_CONTEXT_MODULE:
16015 case PM_CONTEXT_MULTI_TARGET:
16016 case PM_CONTEXT_PARENS:
16017 case PM_CONTEXT_PREDICATE:
16018 case PM_CONTEXT_RESCUE_MODIFIER:
16019 case PM_CONTEXT_TERNARY:
16020 case PM_CONTEXT_UNLESS:
16024 case PM_CONTEXT_NONE:
16025 case PM_CONTEXT_MAXIMUM:
16027 assert(
false &&
"unreachable");
16039 pm_node_list_t *previous_block_exits = parser->current_block_exits;
16040 parser->current_block_exits = current_block_exits;
16041 return previous_block_exits;
16055 switch (PM_NODE_TYPE(block_exit)) {
16056 case PM_BREAK_NODE:
type =
"break";
break;
16057 case PM_NEXT_NODE:
type =
"next";
break;
16058 case PM_REDO_NODE:
type =
"redo";
break;
16059 default: assert(
false &&
"unreachable");
type =
"";
break;
16062 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
16065 parser->current_block_exits = previous_block_exits;
16074 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
16078 parser->current_block_exits = previous_block_exits;
16079 }
else if (previous_block_exits != NULL) {
16085 pm_node_list_concat(parser->arena, previous_block_exits, parser->current_block_exits);
16086 parser->current_block_exits = previous_block_exits;
16091 flush_block_exits(parser, previous_block_exits);
16096parse_predicate(
pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context,
pm_token_t *then_keyword, uint16_t depth) {
16097 context_push(parser, PM_CONTEXT_PREDICATE);
16098 pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
16099 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));
16102 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16104 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
16105 predicate_closed =
true;
16106 *then_keyword = parser->previous;
16109 if (!predicate_closed) {
16110 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
16113 context_pop(parser);
16118parse_conditional(
pm_parser_t *parser, pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
16120 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
16125 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, context, &then_keyword, (uint16_t) (depth + 1));
16128 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
16129 pm_accepts_block_stack_push(parser,
true);
16130 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
16131 pm_accepts_block_stack_pop(parser);
16132 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16138 case PM_CONTEXT_IF:
16139 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
16141 case PM_CONTEXT_UNLESS:
16142 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
16145 assert(
false &&
"unreachable");
16153 if (context == PM_CONTEXT_IF) {
16154 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
16155 if (parser_end_of_line_p(parser)) {
16156 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
16159 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16161 parser_lex(parser);
16163 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
16164 pm_accepts_block_stack_push(parser,
true);
16166 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
16167 pm_accepts_block_stack_pop(parser);
16168 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16170 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
16176 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
16177 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16178 opening_newline_index = token_newline_index(parser);
16180 parser_lex(parser);
16183 pm_accepts_block_stack_push(parser,
true);
16184 pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
16185 pm_accepts_block_stack_pop(parser);
16187 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16188 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
16189 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
16191 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
16194 case PM_CONTEXT_IF:
16195 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
16197 case PM_CONTEXT_UNLESS:
16201 assert(
false &&
"unreachable");
16205 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
16206 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
16211 case PM_CONTEXT_IF: {
16213 bool recursing =
true;
16215 while (recursing) {
16216 switch (PM_NODE_TYPE(current)) {
16218 pm_if_node_end_keyword_loc_set(parser, (
pm_if_node_t *) current, &parser->previous);
16220 recursing = current != NULL;
16223 pm_else_node_end_keyword_loc_set(parser, (
pm_else_node_t *) current, &parser->previous);
16234 case PM_CONTEXT_UNLESS:
16235 pm_unless_node_end_keyword_loc_set(parser, (
pm_unless_node_t *) parent, &parser->previous);
16238 assert(
false &&
"unreachable");
16242 pop_block_exits(parser, previous_block_exits);
16250#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16251 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16252 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16253 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_BLOCK: case PM_TOKEN_KEYWORD_DO_LAMBDA: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
16254 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16255 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16256 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16257 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16258 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16259 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16260 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16266#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16267 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16268 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16269 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16270 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16271 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16272 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16273 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16280#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16281 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16282 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16283 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_XSTRING_BEGIN: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16284 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16285 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16286 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16287 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16288 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16294#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16295 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16296 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16297 case PM_TOKEN_CLASS_VARIABLE
16303#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16304 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16305 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16306 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16310PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16318 if (explicit_encoding != NULL) {
16319 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
16322 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16323 }
else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
16328 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16339parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16340 switch (parser->current.type) {
16347 case PM_TOKEN_STRING_CONTENT: {
16348 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16349 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
16351 parser_lex(parser);
16360 case PM_TOKEN_EMBEXPR_BEGIN: {
16363 parser->explicit_encoding = NULL;
16365 pm_lex_state_t state = parser->lex_state;
16366 int brace_nesting = parser->brace_nesting;
16368 parser->brace_nesting = 0;
16369 lex_state_set(parser, PM_LEX_STATE_BEG);
16370 parser_lex(parser);
16375 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
16376 statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
16379 parser->brace_nesting = brace_nesting;
16380 lex_state_set(parser, state);
16381 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16386 if (statements != NULL && statements->
body.
size == 1) {
16387 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16390 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
16399 case PM_TOKEN_EMBVAR: {
16402 parser->explicit_encoding = NULL;
16404 lex_state_set(parser, PM_LEX_STATE_BEG);
16405 parser_lex(parser);
16410 switch (parser->current.type) {
16413 case PM_TOKEN_BACK_REFERENCE:
16414 parser_lex(parser);
16415 variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
16419 case PM_TOKEN_NUMBERED_REFERENCE:
16420 parser_lex(parser);
16421 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16425 case PM_TOKEN_GLOBAL_VARIABLE:
16426 parser_lex(parser);
16427 variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
16431 case PM_TOKEN_INSTANCE_VARIABLE:
16432 parser_lex(parser);
16433 variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
16437 case PM_TOKEN_CLASS_VARIABLE:
16438 parser_lex(parser);
16439 variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
16445 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16446 variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16450 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
16453 parser_lex(parser);
16454 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16464static const uint8_t *
16465parse_operator_symbol_name(
const pm_token_t *name) {
16466 switch (name->
type) {
16467 case PM_TOKEN_TILDE:
16468 case PM_TOKEN_BANG:
16469 if (name->
end[-1] ==
'@')
return name->
end - 1;
16478 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
16479 const uint8_t *end = parse_operator_symbol_name(&parser->current);
16481 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16482 parser_lex(parser);
16484 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, end);
16485 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16496parse_symbol(
pm_parser_t *parser, pm_lex_state_t next_state, uint16_t depth) {
16498 parser_lex(parser);
16500 const pm_token_t opening = parser->previous;
16502 if (lex_mode.mode != PM_LEX_STRING) {
16503 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16505 switch (parser->current.type) {
16506 case PM_CASE_OPERATOR:
16507 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16508 case PM_TOKEN_IDENTIFIER:
16509 case PM_TOKEN_CONSTANT:
16510 case PM_TOKEN_INSTANCE_VARIABLE:
16511 case PM_TOKEN_METHOD_NAME:
16512 case PM_TOKEN_CLASS_VARIABLE:
16513 case PM_TOKEN_GLOBAL_VARIABLE:
16514 case PM_TOKEN_NUMBERED_REFERENCE:
16515 case PM_TOKEN_BACK_REFERENCE:
16516 case PM_CASE_KEYWORD:
16517 parser_lex(parser);
16520 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16524 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
16525 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16526 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16531 if (lex_mode.as.string.interpolation) {
16533 if (match1(parser, PM_TOKEN_STRING_END)) {
16534 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16535 parser_lex(parser);
16537 .
type = PM_TOKEN_STRING_CONTENT,
16538 .start = parser->previous.
start,
16539 .end = parser->previous.
start
16542 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
16546 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16550 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16551 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16552 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16554 return UP(pm_string_node_to_symbol_node(parser, (
pm_string_node_t *) part, &opening, &parser->previous));
16558 if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16560 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16561 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16562 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16566 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16567 if (match1(parser, PM_TOKEN_EOF)) {
16568 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16570 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16573 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16580 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16581 content = parser->current;
16582 unescaped = parser->current_string;
16583 parser_lex(parser);
16594 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16596 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16597 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16599 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
16600 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16602 if (next_state != PM_LEX_STATE_NONE) {
16603 lex_state_set(parser, next_state);
16606 parser_lex(parser);
16607 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16609 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16613 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.
end, .end = parser->previous.
end };
16614 pm_string_shared_init(&unescaped, content.
start, content.
end);
16617 if (next_state != PM_LEX_STATE_NONE) {
16618 lex_state_set(parser, next_state);
16621 if (match1(parser, PM_TOKEN_EOF)) {
16622 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16624 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16627 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
false)));
16635parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16636 switch (parser->current.type) {
16637 case PM_CASE_OPERATOR:
16638 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
16639 case PM_CASE_KEYWORD:
16640 case PM_TOKEN_CONSTANT:
16641 case PM_TOKEN_IDENTIFIER:
16642 case PM_TOKEN_METHOD_NAME: {
16643 parser_lex(parser);
16645 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16646 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16647 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16651 case PM_TOKEN_SYMBOL_BEGIN:
16652 return parse_symbol(parser, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16654 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16655 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16666parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16667 switch (parser->current.type) {
16668 case PM_CASE_OPERATOR:
16669 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16670 case PM_CASE_KEYWORD:
16671 case PM_TOKEN_CONSTANT:
16672 case PM_TOKEN_IDENTIFIER:
16673 case PM_TOKEN_METHOD_NAME: {
16674 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16675 parser_lex(parser);
16677 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16678 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16679 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16683 case PM_TOKEN_SYMBOL_BEGIN:
16684 return parse_symbol(parser, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16685 case PM_TOKEN_BACK_REFERENCE:
16686 parser_lex(parser);
16687 return UP(pm_back_reference_read_node_create(parser, &parser->previous));
16688 case PM_TOKEN_NUMBERED_REFERENCE:
16689 parser_lex(parser);
16690 return UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16691 case PM_TOKEN_GLOBAL_VARIABLE:
16692 parser_lex(parser);
16693 return UP(pm_global_variable_read_node_create(parser, &parser->previous));
16695 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16696 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16706 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
16708 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
16710 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16711 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth,
false));
16714 pm_scope_t *current_scope = parser->current_scope;
16715 if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16716 if (is_numbered_param) {
16721 uint8_t maximum = (uint8_t) (parser->previous.
start[1] -
'0');
16722 for (uint8_t number = 1; number <= maximum; number++) {
16723 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16726 if (!match1(parser, PM_TOKEN_EQUAL)) {
16727 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
16730 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0,
false));
16731 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16734 }
else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.
start, parser->previous.
end)) {
16735 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16736 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16750 pm_node_flags_t flags = 0;
16752 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.
end[-1] !=
'!') && (parser->previous.
end[-1] !=
'?')) {
16753 pm_node_t *node = parse_variable(parser);
16754 if (node != NULL)
return node;
16755 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16758 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
16759 pm_node_flag_set(UP(node), flags);
16770parse_method_definition_name(
pm_parser_t *parser) {
16771 switch (parser->current.type) {
16772 case PM_CASE_KEYWORD:
16773 case PM_TOKEN_CONSTANT:
16774 case PM_TOKEN_METHOD_NAME:
16775 parser_lex(parser);
16776 return parser->previous;
16777 case PM_TOKEN_IDENTIFIER:
16778 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
16779 parser_lex(parser);
16780 return parser->previous;
16781 case PM_CASE_OPERATOR:
16782 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16783 parser_lex(parser);
16784 return parser->previous;
16786 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
16787 return (
pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end };
16798 if (string->
type != PM_STRING_OWNED) {
16799 size_t length = pm_string_length(
string);
16800 writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(
string), length,
PRISM_ALIGNOF(uint8_t));
16801 pm_string_constant_init(
string, (
const char *) writable, length);
16803 writable = (uint8_t *) string->
source;
16809 size_t dest_length = pm_string_length(
string);
16810 const uint8_t *source_cursor = writable;
16811 const uint8_t *source_end = source_cursor + dest_length;
16816 size_t trimmed_whitespace = 0;
16822 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16823 if (*source_cursor ==
'\t') {
16824 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16825 if (trimmed_whitespace > common_whitespace)
break;
16827 trimmed_whitespace++;
16834 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
16835 string->length = dest_length;
16845 const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->
content_loc);
16846 return pm_memchr(cursor,
'\\', string_node->
content_loc.
length, parser->encoding_changed, parser->encoding) == NULL;
16858 bool dedent_next =
true;
16862 size_t write_index = 0;
16869 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16870 nodes->
nodes[write_index++] = node;
16871 dedent_next =
false;
16877 parse_heredoc_dedent_string(parser->arena, &string_node->
unescaped, common_whitespace);
16880 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16882 nodes->
nodes[write_index++] = node;
16886 dedent_next =
true;
16889 nodes->
size = write_index;
16896parse_strings_empty_content(
const uint8_t *location) {
16897 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16905 assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
16906 bool concating =
false;
16908 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16914 assert(lex_mode->mode == PM_LEX_STRING);
16915 bool lex_interpolation = lex_mode->as.string.interpolation;
16916 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
16919 parser_lex(parser);
16921 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16922 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16926 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
16927 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->previous);
16931 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16935 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
16936 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
start);
16939 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16940 }
else if (!lex_interpolation) {
16946 if (match1(parser, PM_TOKEN_EOF)) {
16947 unescaped = PM_STRING_EMPTY;
16948 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
16950 unescaped = parser->current_string;
16951 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16952 content = parser->previous;
16966 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16968 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16969 pm_node_list_append(parser->arena, &parts, part);
16972 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16973 pm_node_list_append(parser->arena, &parts, part);
16974 parser_lex(parser);
16975 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16977 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16978 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16979 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16980 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
true)));
16981 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16982 }
else if (match1(parser, PM_TOKEN_EOF)) {
16983 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16984 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16985 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16986 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16988 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.
type));
16989 parser->previous.
start = parser->previous.
end;
16990 parser->previous.
type = 0;
16991 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16993 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
17000 const pm_encoding_t *explicit_encoding = parser->explicit_encoding;
17001 parser_lex(parser);
17003 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
17004 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
17005 pm_node_flag_set(node, parse_unescaped_encoding(parser, explicit_encoding));
17011 if (!accept1(parser, PM_TOKEN_STRING_END)) {
17012 const uint8_t *location = parser->previous.
end;
17013 if (location > parser->start && location[-1] ==
'\n') location--;
17014 pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
17016 parser->previous.
start = parser->previous.
end;
17017 parser->previous.
type = 0;
17019 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
17020 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, explicit_encoding, &content, &unescaped,
true)));
17021 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
17026 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
17027 pm_node_flag_set(part, parse_unescaped_encoding(parser, explicit_encoding));
17028 pm_node_list_append(parser->arena, &parts, part);
17030 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
17031 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
17032 pm_node_list_append(parser->arena, &parts, part);
17036 if (accept1(parser, PM_TOKEN_LABEL_END)) {
17037 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
17038 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
17039 }
else if (match1(parser, PM_TOKEN_EOF)) {
17040 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
17041 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
17043 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
17044 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
17054 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
17055 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
17056 pm_node_list_append(parser->arena, &parts, part);
17060 if (accept1(parser, PM_TOKEN_LABEL_END)) {
17061 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
17062 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
17063 }
else if (match1(parser, PM_TOKEN_EOF)) {
17064 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
17065 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
17067 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
17068 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
17072 if (current == NULL) {
17076 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
17087 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
17088 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
17094 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
17095 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
17100 pm_interpolated_string_node_append(parser, container, current);
17101 current = UP(container);
17111#define PM_PARSE_PATTERN_SINGLE 0
17112#define PM_PARSE_PATTERN_TOP 1
17113#define PM_PARSE_PATTERN_MULTI 2
17126 if (peek_at(parser, parser->start + location->
start) ==
'_')
return;
17128 if (!pm_constant_id_set_insert(parser->arena, captures, capture)) {
17129 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
17140 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
17142 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17143 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
17149 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
17157 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
17158 opening = parser->previous;
17159 accept1(parser, PM_TOKEN_NEWLINE);
17161 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17162 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17163 accept1(parser, PM_TOKEN_NEWLINE);
17164 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17167 closing = parser->previous;
17169 parser_lex(parser);
17170 opening = parser->previous;
17171 accept1(parser, PM_TOKEN_NEWLINE);
17173 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17174 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17175 accept1(parser, PM_TOKEN_NEWLINE);
17176 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17179 closing = parser->previous;
17185 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
17192 switch (PM_NODE_TYPE(inner)) {
17193 case PM_ARRAY_PATTERN_NODE: {
17197 PM_NODE_START_SET_NODE(pattern_node, node);
17198 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17201 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17202 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17204 return UP(pattern_node);
17209 case PM_FIND_PATTERN_NODE: {
17213 PM_NODE_START_SET_NODE(pattern_node, node);
17214 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17217 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17218 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17220 return UP(pattern_node);
17225 case PM_HASH_PATTERN_NODE: {
17229 PM_NODE_START_SET_NODE(pattern_node, node);
17230 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17233 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17234 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17236 return UP(pattern_node);
17248 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17249 pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
17250 return UP(pattern_node);
17258 assert(parser->previous.
type == PM_TOKEN_USTAR);
17265 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17266 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17269 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17270 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17273 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17274 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17275 name = UP(pm_local_variable_target_node_create(
17279 (uint32_t) (depth == -1 ? 0 : depth)
17284 return pm_splat_node_create(parser, &
operator, name);
17292 assert(parser->current.type == PM_TOKEN_USTAR_STAR);
17293 parser_lex(parser);
17298 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17299 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
17302 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17303 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17306 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17307 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17310 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17311 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17312 value = UP(pm_local_variable_target_node_create(
17316 (uint32_t) (depth == -1 ? 0 : depth)
17320 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
17328pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17329 ptrdiff_t length = end - start;
17330 if (length == 0)
return false;
17333 size_t width = char_is_identifier_start(parser, start, end - start);
17334 if (width == 0)
return false;
17337 if (parser->encoding_changed) {
17338 if (parser->encoding->isupper_char(start, length))
return false;
17340 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17345 const uint8_t *cursor = start + width;
17346 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17347 return cursor == end;
17357 const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
17358 const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
17360 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
17363 if (pm_slice_is_valid_local(parser, start, end)) {
17364 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17366 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
17368 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
17369 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
17374 pm_parser_local_add(parser, constant_id, start, end, 0);
17377 parse_pattern_capture(parser, captures, constant_id, value_loc);
17382 (uint32_t) (depth == -1 ? 0 : depth)
17385 return UP(pm_implicit_node_create(parser, UP(target)));
17394 if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, keys, node,
true) != NULL) {
17395 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17408 switch (PM_NODE_TYPE(first_node)) {
17409 case PM_ASSOC_SPLAT_NODE:
17410 case PM_NO_KEYWORDS_PARAMETER_NODE:
17413 case PM_INTERPOLATED_SYMBOL_NODE:
17414 case PM_SYMBOL_NODE: {
17415 if (pm_symbol_node_label_p(parser, first_node)) {
17416 if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
17417 pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17419 parse_pattern_hash_key(parser, &keys, first_node);
17429 if (!token_begins_pattern_p(parser->current.type)) {
17430 if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
17431 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17433 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
17438 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17441 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17442 pm_node_list_append(parser->arena, &assocs, assoc);
17451 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;
17452 pm_parser_err_node(parser, first_node, diag_id);
17454 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
17455 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17457 pm_node_list_append(parser->arena, &assocs, assoc);
17463 while (accept1(parser, PM_TOKEN_COMMA)) {
17469 if (!token_begins_pattern_p(parser->current.type)) {
17471 if (rest != NULL) {
17472 pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17478 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17479 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17481 if (rest == NULL) {
17484 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17485 pm_node_list_append(parser->arena, &assocs, assoc);
17490 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17491 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17493 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17494 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17495 }
else if (!pm_symbol_node_label_p(parser, key)) {
17496 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17498 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
17499 key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17501 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17503 pm_token_t label = { .
type = PM_TOKEN_LABEL, .start = parser->previous.
end, .end = parser->previous.
end };
17504 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
17507 parse_pattern_hash_key(parser, &keys, key);
17515 if (!token_begins_pattern_p(parser->current.type)) {
17516 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
17517 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17519 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
17522 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17525 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
17527 if (rest != NULL) {
17528 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17531 pm_node_list_append(parser->arena, &assocs, assoc);
17538 pm_static_literals_free(&keys);
17547 switch (parser->current.type) {
17548 case PM_TOKEN_IDENTIFIER:
17549 case PM_TOKEN_METHOD_NAME: {
17550 parser_lex(parser);
17551 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17554 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17555 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17558 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17559 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17560 return UP(pm_local_variable_target_node_create(
17564 (uint32_t) (depth == -1 ? 0 : depth)
17567 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17569 parser_lex(parser);
17571 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17574 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
17579 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17581 accept1(parser, PM_TOKEN_NEWLINE);
17582 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17585 switch (PM_NODE_TYPE(inner)) {
17586 case PM_ARRAY_PATTERN_NODE: {
17589 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17590 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17592 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17593 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17595 return UP(pattern_node);
17600 case PM_FIND_PATTERN_NODE: {
17603 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17604 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17606 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17607 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17609 return UP(pattern_node);
17619 pm_array_pattern_node_requireds_append(parser->arena, node, inner);
17622 case PM_TOKEN_BRACE_LEFT_HASH: {
17623 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17624 parser->pattern_matching_newlines =
false;
17628 parser_lex(parser);
17630 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17633 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
17637 switch (parser->current.type) {
17638 case PM_TOKEN_LABEL:
17639 parser_lex(parser);
17640 first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
17642 case PM_TOKEN_USTAR_STAR:
17643 first_node = parse_pattern_keyword_rest(parser, captures);
17645 case PM_TOKEN_STRING_BEGIN:
17646 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));
17649 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
17650 parser_lex(parser);
17652 first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
17657 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17659 accept1(parser, PM_TOKEN_NEWLINE);
17660 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
17663 PM_NODE_START_SET_TOKEN(parser, node, &opening);
17664 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
17670 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17673 case PM_TOKEN_UDOT_DOT:
17674 case PM_TOKEN_UDOT_DOT_DOT: {
17676 parser_lex(parser);
17680 switch (parser->current.type) {
17681 case PM_CASE_PRIMITIVE: {
17682 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));
17683 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17686 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17687 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17688 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17692 case PM_CASE_PRIMITIVE: {
17693 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));
17696 if (pm_symbol_node_label_p(parser, node))
return node;
17699 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17700 pm_parser_err_node(parser, node, diag_id);
17701 return UP(pm_error_recovery_node_create_unexpected(parser, node));
17705 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17711 switch (parser->current.type) {
17712 case PM_CASE_PRIMITIVE: {
17713 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));
17714 return UP(pm_range_node_create(parser, node, &
operator, right));
17717 return UP(pm_range_node_create(parser, node, &
operator, NULL));
17723 case PM_TOKEN_CARET: {
17724 parser_lex(parser);
17729 switch (parser->current.type) {
17730 case PM_TOKEN_IDENTIFIER: {
17731 parser_lex(parser);
17732 pm_node_t *variable = UP(parse_variable(parser));
17734 if (variable == NULL) {
17735 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
17736 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
17739 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17741 case PM_TOKEN_INSTANCE_VARIABLE: {
17742 parser_lex(parser);
17743 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
17745 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17747 case PM_TOKEN_CLASS_VARIABLE: {
17748 parser_lex(parser);
17749 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
17751 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17753 case PM_TOKEN_GLOBAL_VARIABLE: {
17754 parser_lex(parser);
17755 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
17757 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17759 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
17760 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17761 parser->pattern_matching_newlines =
false;
17764 parser_lex(parser);
17766 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));
17767 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17769 accept1(parser, PM_TOKEN_NEWLINE);
17770 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
17771 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->previous));
17776 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17777 pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17778 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17782 case PM_TOKEN_UCOLON_COLON: {
17784 parser_lex(parser);
17786 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17789 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
17791 case PM_TOKEN_CONSTANT: {
17793 parser_lex(parser);
17795 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
17796 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17799 pm_parser_err_current(parser, diag_id);
17800 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17812parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
17815 switch (PM_NODE_TYPE(node)) {
17816 case PM_LOCAL_VARIABLE_TARGET_NODE:
17819 if (peek_at(parser, parser->start + PM_NODE_START(node)) !=
'_') {
17820 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17823 case PM_ARRAY_PATTERN_NODE:
17824 case PM_ASSOC_NODE:
17825 case PM_ASSOC_SPLAT_NODE:
17826 case PM_CAPTURE_PATTERN_NODE:
17827 case PM_FIND_PATTERN_NODE:
17828 case PM_HASH_PATTERN_NODE:
17829 case PM_IMPLICIT_NODE:
17830 case PM_PARENTHESES_NODE:
17831 case PM_SPLAT_NODE:
17845 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
17855 bool alternation =
false;
17857 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
17858 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->size) {
17859 parse_pattern_alternation_error(parser, node);
17862 switch (parser->current.type) {
17863 case PM_TOKEN_IDENTIFIER:
17864 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17865 case PM_TOKEN_BRACE_LEFT_HASH:
17866 case PM_TOKEN_CARET:
17867 case PM_TOKEN_CONSTANT:
17868 case PM_TOKEN_UCOLON_COLON:
17869 case PM_TOKEN_UDOT_DOT:
17870 case PM_TOKEN_UDOT_DOT_DOT:
17871 case PM_CASE_PRIMITIVE: {
17872 if (!alternation) {
17873 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17876 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17878 if (captures->size) parse_pattern_alternation_error(parser, right);
17879 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17884 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
17885 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17888 parser_lex(parser);
17890 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17891 accept1(parser, PM_TOKEN_NEWLINE);
17892 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17893 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
17895 if (!alternation) {
17898 if (captures->size) parse_pattern_alternation_error(parser, right);
17899 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17905 pm_parser_err_current(parser, diag_id);
17906 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17908 if (!alternation) {
17911 if (captures->size) parse_pattern_alternation_error(parser, right);
17912 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
17922 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17924 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17926 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17929 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17930 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17933 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17934 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17939 (uint32_t) (depth == -1 ? 0 : depth)
17942 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17955 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
17956 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
17957 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17962 bool leading_rest =
false;
17963 bool trailing_rest =
false;
17965 switch (parser->current.type) {
17966 case PM_TOKEN_LABEL: {
17967 parser_lex(parser);
17968 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17969 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17971 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17972 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17977 case PM_TOKEN_USTAR_STAR: {
17978 node = parse_pattern_keyword_rest(parser, captures);
17979 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17981 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17982 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17987 case PM_TOKEN_STRING_BEGIN: {
17990 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17992 if (pm_symbol_node_label_p(parser, node)) {
17993 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17995 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17996 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
18002 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
18005 case PM_TOKEN_USTAR: {
18006 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
18007 parser_lex(parser);
18008 node = UP(parse_pattern_rest(parser, captures));
18009 leading_rest =
true;
18015 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
18021 if (pm_symbol_node_label_p(parser, node)) {
18022 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
18025 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
18030 pm_node_list_append(parser->arena, &nodes, node);
18033 while (accept1(parser, PM_TOKEN_COMMA)) {
18039 if (!token_begins_pattern_p(parser->current.type)) {
18044 if (trailing_rest) {
18045 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
18048 node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
18049 pm_node_list_append(parser->arena, &nodes, node);
18050 trailing_rest =
true;
18054 if (accept1(parser, PM_TOKEN_USTAR)) {
18055 node = UP(parse_pattern_rest(parser, captures));
18060 if (trailing_rest) {
18061 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
18064 trailing_rest =
true;
18066 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
18069 pm_node_list_append(parser->arena, &nodes, node);
18076 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
18077 node = UP(pm_find_pattern_node_create(parser, &nodes));
18079 if (nodes.
size == 2) {
18080 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
18083 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
18085 if (leading_rest && trailing_rest) {
18086 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
18091 }
else if (leading_rest) {
18094 node = UP(pm_array_pattern_node_rest_create(parser, node));
18106parse_negative_numeric(
pm_node_t *node) {
18107 switch (PM_NODE_TYPE(node)) {
18108 case PM_INTEGER_NODE: {
18115 case PM_FLOAT_NODE: {
18122 case PM_RATIONAL_NODE: {
18129 case PM_IMAGINARY_NODE:
18135 assert(
false &&
"unreachable");
18146pm_parser_err_prefix(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
18148 case PM_ERR_HASH_KEY: {
18149 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.
type));
18152 case PM_ERR_HASH_VALUE:
18153 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
18154 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
18157 case PM_ERR_UNARY_RECEIVER: {
18158 const char *human = (parser->current.type == PM_TOKEN_EOF ?
"end-of-input" : pm_token_str(parser->current.type));
18159 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.
start[0]);
18162 case PM_ERR_UNARY_DISALLOWED:
18163 case PM_ERR_EXPECT_ARGUMENT: {
18164 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
18168 pm_parser_err_previous(parser, diag_id);
18178#define CONTEXT_NONE 0
18179#define CONTEXT_THROUGH_ENSURE 1
18180#define CONTEXT_THROUGH_ELSE 2
18183 int context = CONTEXT_NONE;
18185 while (context_node != NULL) {
18186 switch (context_node->context) {
18187 case PM_CONTEXT_BEGIN_RESCUE:
18188 case PM_CONTEXT_BLOCK_RESCUE:
18189 case PM_CONTEXT_CLASS_RESCUE:
18190 case PM_CONTEXT_DEF_RESCUE:
18191 case PM_CONTEXT_LAMBDA_RESCUE:
18192 case PM_CONTEXT_MODULE_RESCUE:
18193 case PM_CONTEXT_SCLASS_RESCUE:
18194 case PM_CONTEXT_DEFINED:
18195 case PM_CONTEXT_RESCUE_MODIFIER:
18198 case PM_CONTEXT_CLASS:
18199 case PM_CONTEXT_DEF:
18200 case PM_CONTEXT_DEF_PARAMS:
18201 case PM_CONTEXT_MAIN:
18202 case PM_CONTEXT_MODULE:
18203 case PM_CONTEXT_PREEXE:
18204 case PM_CONTEXT_SCLASS:
18207 if (context == CONTEXT_NONE) {
18208 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
18209 }
else if (context == CONTEXT_THROUGH_ENSURE) {
18210 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
18211 }
else if (context == CONTEXT_THROUGH_ELSE) {
18212 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
18215 case PM_CONTEXT_BEGIN_ELSE:
18216 case PM_CONTEXT_BLOCK_ELSE:
18217 case PM_CONTEXT_CLASS_ELSE:
18218 case PM_CONTEXT_DEF_ELSE:
18219 case PM_CONTEXT_LAMBDA_ELSE:
18220 case PM_CONTEXT_MODULE_ELSE:
18221 case PM_CONTEXT_SCLASS_ELSE:
18224 context = CONTEXT_THROUGH_ELSE;
18226 case PM_CONTEXT_BEGIN_ENSURE:
18227 case PM_CONTEXT_BLOCK_ENSURE:
18228 case PM_CONTEXT_CLASS_ENSURE:
18229 case PM_CONTEXT_DEF_ENSURE:
18230 case PM_CONTEXT_LAMBDA_ENSURE:
18231 case PM_CONTEXT_MODULE_ENSURE:
18232 case PM_CONTEXT_SCLASS_ENSURE:
18235 context = CONTEXT_THROUGH_ENSURE;
18237 case PM_CONTEXT_NONE:
18238 case PM_CONTEXT_MAXIMUM:
18240 assert(
false &&
"unreachable");
18242 case PM_CONTEXT_BEGIN:
18243 case PM_CONTEXT_BLOCK_BRACES:
18244 case PM_CONTEXT_BLOCK_KEYWORDS:
18245 case PM_CONTEXT_BLOCK_PARAMETERS:
18246 case PM_CONTEXT_CASE_IN:
18247 case PM_CONTEXT_CASE_WHEN:
18248 case PM_CONTEXT_DEFAULT_PARAMS:
18249 case PM_CONTEXT_ELSE:
18250 case PM_CONTEXT_ELSIF:
18251 case PM_CONTEXT_EMBEXPR:
18252 case PM_CONTEXT_FOR_INDEX:
18253 case PM_CONTEXT_FOR:
18254 case PM_CONTEXT_IF:
18255 case PM_CONTEXT_LAMBDA_BRACES:
18256 case PM_CONTEXT_LAMBDA_DO_END:
18257 case PM_CONTEXT_LOOP_PREDICATE:
18258 case PM_CONTEXT_MULTI_TARGET:
18259 case PM_CONTEXT_PARENS:
18260 case PM_CONTEXT_POSTEXE:
18261 case PM_CONTEXT_PREDICATE:
18262 case PM_CONTEXT_TERNARY:
18263 case PM_CONTEXT_UNLESS:
18264 case PM_CONTEXT_UNTIL:
18265 case PM_CONTEXT_WHILE:
18271 context_node = context_node->prev;
18275#undef CONTEXT_ENSURE
18286 while (context_node != NULL) {
18287 switch (context_node->context) {
18288 case PM_CONTEXT_DEF:
18289 case PM_CONTEXT_DEF_PARAMS:
18290 case PM_CONTEXT_DEFINED:
18291 case PM_CONTEXT_DEF_ENSURE:
18292 case PM_CONTEXT_DEF_RESCUE:
18293 case PM_CONTEXT_DEF_ELSE:
18297 case PM_CONTEXT_CLASS:
18298 case PM_CONTEXT_CLASS_ENSURE:
18299 case PM_CONTEXT_CLASS_RESCUE:
18300 case PM_CONTEXT_CLASS_ELSE:
18301 case PM_CONTEXT_MAIN:
18302 case PM_CONTEXT_MODULE:
18303 case PM_CONTEXT_MODULE_ENSURE:
18304 case PM_CONTEXT_MODULE_RESCUE:
18305 case PM_CONTEXT_MODULE_ELSE:
18306 case PM_CONTEXT_SCLASS:
18307 case PM_CONTEXT_SCLASS_RESCUE:
18308 case PM_CONTEXT_SCLASS_ENSURE:
18309 case PM_CONTEXT_SCLASS_ELSE:
18312 pm_parser_err_node(parser, UP(node), PM_ERR_INVALID_YIELD);
18314 case PM_CONTEXT_NONE:
18315 case PM_CONTEXT_MAXIMUM:
18317 assert(
false &&
"unreachable");
18319 case PM_CONTEXT_BEGIN:
18320 case PM_CONTEXT_BEGIN_ELSE:
18321 case PM_CONTEXT_BEGIN_ENSURE:
18322 case PM_CONTEXT_BEGIN_RESCUE:
18323 case PM_CONTEXT_BLOCK_BRACES:
18324 case PM_CONTEXT_BLOCK_KEYWORDS:
18325 case PM_CONTEXT_BLOCK_ELSE:
18326 case PM_CONTEXT_BLOCK_ENSURE:
18327 case PM_CONTEXT_BLOCK_PARAMETERS:
18328 case PM_CONTEXT_BLOCK_RESCUE:
18329 case PM_CONTEXT_CASE_IN:
18330 case PM_CONTEXT_CASE_WHEN:
18331 case PM_CONTEXT_DEFAULT_PARAMS:
18332 case PM_CONTEXT_ELSE:
18333 case PM_CONTEXT_ELSIF:
18334 case PM_CONTEXT_EMBEXPR:
18335 case PM_CONTEXT_FOR_INDEX:
18336 case PM_CONTEXT_FOR:
18337 case PM_CONTEXT_IF:
18338 case PM_CONTEXT_LAMBDA_BRACES:
18339 case PM_CONTEXT_LAMBDA_DO_END:
18340 case PM_CONTEXT_LAMBDA_ELSE:
18341 case PM_CONTEXT_LAMBDA_ENSURE:
18342 case PM_CONTEXT_LAMBDA_RESCUE:
18343 case PM_CONTEXT_LOOP_PREDICATE:
18344 case PM_CONTEXT_MULTI_TARGET:
18345 case PM_CONTEXT_PARENS:
18346 case PM_CONTEXT_POSTEXE:
18347 case PM_CONTEXT_PREDICATE:
18348 case PM_CONTEXT_PREEXE:
18349 case PM_CONTEXT_RESCUE_MODIFIER:
18350 case PM_CONTEXT_TERNARY:
18351 case PM_CONTEXT_UNLESS:
18352 case PM_CONTEXT_UNTIL:
18353 case PM_CONTEXT_WHILE:
18359 context_node = context_node->prev;
18368parse_case(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18369 size_t opening_newline_index = token_newline_index(parser);
18370 parser_lex(parser);
18376 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18378 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18379 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18381 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18383 }
else if (!token_begins_expression_p(parser->current.type)) {
18386 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));
18387 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18390 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18391 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18392 parser_lex(parser);
18393 pop_block_exits(parser, previous_block_exits);
18394 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18395 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->previous));
18402 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18403 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
18409 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18410 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18411 parser_lex(parser);
18414 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18417 if (accept1(parser, PM_TOKEN_USTAR)) {
18419 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));
18421 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18422 pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
18424 if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE))
break;
18426 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));
18427 pm_when_node_conditions_append(parser->arena, when_node, condition);
18431 if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE))
break;
18435 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18436 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18437 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE) && parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
18438 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18441 pm_when_clause_static_literals_add(parser, &literals, condition);
18443 }
while (accept1(parser, PM_TOKEN_COMMA));
18445 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18446 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18447 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18450 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18451 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18454 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18455 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18456 if (statements != NULL) {
18457 pm_when_node_statements_set(when_node, statements);
18461 pm_case_node_condition_append(parser->arena, case_node, UP(when_node));
18467 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18470 pm_static_literals_free(&literals);
18471 node = UP(case_node);
18473 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
18477 if (predicate == NULL) {
18478 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18483 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18484 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18486 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
18487 parser->pattern_matching_newlines =
true;
18489 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18490 parser->command_start =
false;
18491 parser_lex(parser);
18496 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));
18498 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
18503 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18505 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));
18506 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18507 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18509 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));
18510 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18517 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18518 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18519 then_keyword = parser->previous;
18522 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18523 then_keyword = parser->previous;
18529 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18532 statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
18537 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
18538 pm_case_match_node_condition_append(parser->arena, case_node, condition);
18544 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18547 node = UP(case_node);
18550 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18551 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18555 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18556 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
18558 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
18561 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18562 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18568 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18569 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18571 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18572 pm_case_node_end_keyword_loc_set(parser, (
pm_case_node_t *) node, &parser->previous);
18574 pm_case_match_node_end_keyword_loc_set(parser, (
pm_case_match_node_t *) node, &parser->previous);
18577 pop_block_exits(parser, previous_block_exits);
18586parse_class(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18587 size_t opening_newline_index = token_newline_index(parser);
18588 parser_lex(parser);
18590 pm_token_t class_keyword = parser->previous;
18591 pm_do_loop_stack_push(parser,
false);
18594 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18596 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18598 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));
18600 pm_parser_scope_push(parser,
true);
18601 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18602 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
18606 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18607 pm_accepts_block_stack_push(parser,
true);
18608 statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18609 pm_accepts_block_stack_pop(parser);
18612 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18613 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18614 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)));
18616 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18619 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18622 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18624 pm_parser_scope_pop(parser);
18625 pm_do_loop_stack_pop(parser);
18627 flush_block_exits(parser, previous_block_exits);
18628 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->previous));
18631 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));
18633 if (name.
type != PM_TOKEN_CONSTANT) {
18634 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18640 if (match1(parser, PM_TOKEN_LESS)) {
18641 inheritance_operator = parser->current;
18642 lex_state_set(parser, PM_LEX_STATE_BEG);
18644 parser->command_start =
true;
18645 parser_lex(parser);
18647 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));
18652 pm_parser_scope_push(parser,
true);
18654 if (inheritance_operator.
start != NULL) {
18655 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18657 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18661 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18662 pm_accepts_block_stack_push(parser,
true);
18663 statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18664 pm_accepts_block_stack_pop(parser);
18667 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18668 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18669 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)));
18671 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18674 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18676 if (context_def_p(parser)) {
18677 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18681 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18683 pm_parser_scope_pop(parser);
18684 pm_do_loop_stack_pop(parser);
18686 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18687 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18688 if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18689 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18693 pop_block_exits(parser, previous_block_exits);
18694 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
18701parse_def(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18703 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18706 size_t opening_newline_index = token_newline_index(parser);
18714 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18715 parser_lex(parser);
18719 bool valid_name =
true;
18721 switch (parser->current.type) {
18722 case PM_CASE_OPERATOR:
18723 pm_parser_scope_push(parser,
true);
18724 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18725 parser_lex(parser);
18727 name = parser->previous;
18729 case PM_TOKEN_IDENTIFIER: {
18730 parser_lex(parser);
18732 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18733 receiver = parse_variable_call(parser);
18735 pm_parser_scope_push(parser,
true);
18736 lex_state_set(parser, PM_LEX_STATE_FNAME);
18737 parser_lex(parser);
18739 operator = parser->previous;
18740 name = parse_method_definition_name(parser);
18742 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
18743 pm_parser_scope_push(parser,
true);
18745 name = parser->previous;
18750 case PM_TOKEN_INSTANCE_VARIABLE:
18751 case PM_TOKEN_CLASS_VARIABLE:
18752 case PM_TOKEN_GLOBAL_VARIABLE:
18753 valid_name =
false;
18755 case PM_TOKEN_CONSTANT:
18756 case PM_TOKEN_KEYWORD_NIL:
18757 case PM_TOKEN_KEYWORD_SELF:
18758 case PM_TOKEN_KEYWORD_TRUE:
18759 case PM_TOKEN_KEYWORD_FALSE:
18760 case PM_TOKEN_KEYWORD___FILE__:
18761 case PM_TOKEN_KEYWORD___LINE__:
18762 case PM_TOKEN_KEYWORD___ENCODING__: {
18763 pm_parser_scope_push(parser,
true);
18764 parser_lex(parser);
18768 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18769 lex_state_set(parser, PM_LEX_STATE_FNAME);
18770 parser_lex(parser);
18771 operator = parser->previous;
18773 switch (identifier.
type) {
18774 case PM_TOKEN_CONSTANT:
18775 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18777 case PM_TOKEN_INSTANCE_VARIABLE:
18778 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18780 case PM_TOKEN_CLASS_VARIABLE:
18781 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18783 case PM_TOKEN_GLOBAL_VARIABLE:
18784 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18786 case PM_TOKEN_KEYWORD_NIL:
18787 receiver = UP(pm_nil_node_create(parser, &identifier));
18789 case PM_TOKEN_KEYWORD_SELF:
18790 receiver = UP(pm_self_node_create(parser, &identifier));
18792 case PM_TOKEN_KEYWORD_TRUE:
18793 receiver = UP(pm_true_node_create(parser, &identifier));
18795 case PM_TOKEN_KEYWORD_FALSE:
18796 receiver = UP(pm_false_node_create(parser, &identifier));
18798 case PM_TOKEN_KEYWORD___FILE__:
18799 receiver = UP(pm_source_file_node_create(parser, &identifier));
18801 case PM_TOKEN_KEYWORD___LINE__:
18802 receiver = UP(pm_source_line_node_create(parser, &identifier));
18804 case PM_TOKEN_KEYWORD___ENCODING__:
18805 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18811 name = parse_method_definition_name(parser);
18814 PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.
type));
18821 case PM_TOKEN_PARENTHESIS_LEFT: {
18825 context_pop(parser);
18826 parser_lex(parser);
18829 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));
18831 accept1(parser, PM_TOKEN_NEWLINE);
18832 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18835 lex_state_set(parser, PM_LEX_STATE_FNAME);
18836 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18838 operator = parser->previous;
18839 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18843 pm_parser_scope_push(parser,
true);
18844 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18845 name = parse_method_definition_name(parser);
18849 pm_parser_scope_push(parser,
true);
18850 name = parse_method_definition_name(parser);
18858 bool accept_endless_def =
true;
18859 switch (parser->current.type) {
18860 case PM_TOKEN_PARENTHESIS_LEFT: {
18861 parser_lex(parser);
18862 lparen = parser->previous;
18864 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18868 bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
18869 params = parse_parameters(
18871 PM_BINDING_POWER_DEFINED,
18873 allow_trailing_comma,
18877 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18878 (uint16_t) (depth + 1)
18882 lex_state_set(parser, PM_LEX_STATE_BEG);
18883 parser->command_start =
true;
18885 context_pop(parser);
18886 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18887 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
18888 parser->previous.
start = parser->previous.
end;
18889 parser->previous.
type = 0;
18892 rparen = parser->previous;
18895 case PM_CASE_PARAMETER: {
18898 if (parser->current.type == PM_TOKEN_LABEL) {
18899 lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
18902 params = parse_parameters(
18904 PM_BINDING_POWER_DEFINED,
18910 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18911 (uint16_t) (depth + 1)
18916 accept_endless_def =
false;
18918 context_pop(parser);
18923 context_pop(parser);
18932 if (accept1(parser, PM_TOKEN_EQUAL)) {
18933 if (token_is_setter_name(&name)) {
18934 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18936 if (!accept_endless_def) {
18937 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18940 parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
18941 parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
18943 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");
18945 equal = parser->previous;
18947 context_push(parser, PM_CONTEXT_DEF);
18948 pm_do_loop_stack_push(parser,
false);
18949 statements = UP(pm_statements_node_create(parser));
18953 uint8_t allow_flags = (flags & PM_PARSE_ACCEPTS_COMMAND_DEF) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18965 pm_accepts_block_stack_push(parser,
true);
18966 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));
18973 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18974 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18975 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18982 while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18983 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18985 pm_token_t rescue_keyword = parser->previous;
18989 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));
18990 context_pop(parser);
18992 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18995 pm_accepts_block_stack_pop(parser);
19000 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(parser, statement)) {
19001 PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19004 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
19005 pm_do_loop_stack_pop(parser);
19006 context_pop(parser);
19008 if (lparen.
start == NULL) {
19009 lex_state_set(parser, PM_LEX_STATE_BEG);
19010 parser->command_start =
true;
19011 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
19013 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19016 pm_accepts_block_stack_push(parser,
true);
19017 pm_do_loop_stack_push(parser,
false);
19019 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19020 pm_accepts_block_stack_push(parser,
true);
19021 statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
19022 pm_accepts_block_stack_pop(parser);
19025 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19026 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19027 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)));
19029 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19032 pm_accepts_block_stack_pop(parser);
19033 pm_do_loop_stack_pop(parser);
19035 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
19036 end_keyword = parser->previous;
19040 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
19041 pm_parser_scope_pop(parser);
19046 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
19048 flush_block_exits(parser, previous_block_exits);
19050 return UP(pm_def_node_create(
19059 NTOK2PTR(
operator),
19063 NTOK2PTR(end_keyword)
19071parse_module(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19073 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19075 size_t opening_newline_index = token_newline_index(parser);
19076 parser_lex(parser);
19077 pm_token_t module_keyword = parser->previous;
19079 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));
19084 if (PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
19085 pop_block_exits(parser, previous_block_exits);
19088 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19091 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19094 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19095 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
19101 name = parser->previous;
19102 if (name.
type != PM_TOKEN_CONSTANT) {
19103 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19106 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)) {
19107 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
19110 pm_parser_scope_push(parser,
true);
19111 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19114 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19115 pm_accepts_block_stack_push(parser,
true);
19116 statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19117 pm_accepts_block_stack_pop(parser);
19120 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19121 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19122 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)));
19124 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19128 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
19130 pm_parser_scope_pop(parser);
19131 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
19133 if (context_def_p(parser)) {
19134 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19137 pop_block_exits(parser, previous_block_exits);
19139 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
19147parse_parentheses(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19149 pm_node_flags_t paren_flags = 0;
19152 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19154 parser_lex(parser);
19156 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19157 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19158 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19165 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
19169 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT) && opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19170 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19173 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19174 pop_block_exits(parser, previous_block_exits);
19175 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
19180 context_push(parser, PM_CONTEXT_PARENS);
19181 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
19182 context_pop(parser);
19187 bool terminator_found =
false;
19189 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19190 terminator_found =
true;
19191 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19192 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
19193 terminator_found =
true;
19196 if (terminator_found) {
19198 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19199 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19200 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19208 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19209 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19210 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19213 parser_lex(parser);
19214 pop_block_exits(parser, previous_block_exits);
19216 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19222 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
19225 multi_target = pm_multi_target_node_create(parser);
19226 pm_multi_target_node_targets_append(parser, multi_target, statement);
19229 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
19230 multi_target->
rparen_loc = TOK2LOC(parser, &parser->previous);
19231 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
19232 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
19235 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
19236 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19237 accept1(parser, PM_TOKEN_NEWLINE);
19239 result = UP(multi_target);
19242 if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
19244 }
else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match2(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_COMMA)) {
19248 }
else if (flags & PM_PARSE_ACCEPTS_STATEMENT) {
19252 if (pm_binding_powers[parser->current.type].binary && !match1(parser, PM_TOKEN_EQUAL)) {
19253 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19255 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
19258 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19259 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
19262 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19272 pm_statements_node_body_append(parser, statements, statement,
true);
19274 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19280 context_push(parser, PM_CONTEXT_PARENS);
19281 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19284 pm_statements_node_body_append(parser, statements, statement,
true);
19288 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
19289 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19294 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
19295 pm_statements_node_body_append(parser, statements, node,
true);
19299 if (parser->recovering) {
19302 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering =
false;
19308 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE))
break;
19312 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19313 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
19314 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
19315 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19317 }
else if (!match1(parser, PM_TOKEN_EOF)) {
19320 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19324 context_pop(parser);
19325 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19334 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19336 pm_multi_target_node_targets_append(parser, multi_target, statement);
19338 statement = UP(multi_target);
19342 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
19343 const uint8_t *offset = parser->start + PM_NODE_END(statement);
19344 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
19345 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
19347 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
19350 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
19354 pop_block_exits(parser, previous_block_exits);
19355 pm_void_statements_check(parser, statements,
true);
19356 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19365parse_splat(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19369 if (token_begins_expression_p(parser->current.type)) {
19370 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19373 return UP(pm_splat_node_create(parser, &
operator, name));
19381 pm_hash_key_static_literals_add(parser, &hash_keys, key);
19384 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
19385 operator = parser->previous;
19388 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));
19389 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
19390 pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
19392 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19393 parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
19396 pm_static_literals_free(&hash_keys);
19401parse_array(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19402 pm_array_node_t *array = pm_array_node_create(parser, &parser->current);
19403 parser_lex(parser);
19405 bool parsed_bare_hash =
false;
19406 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
19407 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
19411 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19417 if (accept1(parser, PM_TOKEN_COMMA)) {
19420 if (accepted_newline) {
19421 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
19426 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
19427 parser->previous.
start = parser->previous.
end;
19428 parser->previous.
type = 0;
19435 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
19439 if (accept1(parser, PM_TOKEN_USTAR)) {
19443 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
19444 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
19446 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));
19449 element = UP(pm_splat_node_create(parser, &
operator, expression));
19450 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
19451 if (parsed_bare_hash) {
19452 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
19455 element = UP(pm_keyword_hash_node_create(parser));
19458 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)) {
19459 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19462 pm_static_literals_free(&hash_keys);
19463 parsed_bare_hash =
true;
19465 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));
19467 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
19468 if (parsed_bare_hash) {
19469 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
19472 element = UP(parse_array_keyword_hash(parser, element, flags, depth));
19473 parsed_bare_hash =
true;
19477 pm_array_node_elements_append(parser->arena, array, element);
19478 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
19481 accept1(parser, PM_TOKEN_NEWLINE);
19483 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19484 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
19485 parser->previous.
start = parser->previous.
end;
19486 parser->previous.
type = 0;
19489 pm_array_node_close_set(parser, array, &parser->previous);
19497 parser_lex(parser);
19499 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
19501 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
19502 pm_static_literals_free(&hash_keys);
19504 accept1(parser, PM_TOKEN_NEWLINE);
19507 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
19508 pm_hash_node_closing_loc_set(parser, node, &parser->previous);
19513parse_heredoc(
pm_parser_t *parser, uint16_t depth) {
19514 assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
19517 size_t common_whitespace = (size_t) -1;
19518 parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
19520 parser_lex(parser);
19526 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19529 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19530 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
19532 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19533 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19535 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19538 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
19539 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
19546 node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19547 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19552 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
19556 cast->
closing_loc = TOK2LOC(parser, &parser->current);
19559 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19561 cast->
base.
type = PM_X_STRING_NODE;
19564 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19565 parse_heredoc_dedent_string(parser->arena, &cast->
unescaped, common_whitespace);
19569 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19575 pm_node_list_append(parser->arena, &parts, part);
19577 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19578 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19579 pm_node_list_append(parser->arena, &parts, part);
19585 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19587 cast->
parts = parts;
19589 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19590 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
19597 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19598 pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
19606 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19608 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19614 parse_heredoc_dedent(parser, nodes, common_whitespace);
19622 pm_lex_mode_t *whitespace_mode = parser->lex_modes.current;
19624 if (whitespace_mode->mode == PM_LEX_HEREDOC && whitespace_mode->as.heredoc.common_whitespace == &common_whitespace) {
19625 whitespace_mode->as.heredoc.common_whitespace = NULL;
19627 whitespace_mode = whitespace_mode->prev;
19628 }
while (whitespace_mode != NULL);
19630 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19631 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19638parse_begin(
pm_parser_t *parser, uint16_t depth) {
19640 size_t opening_newline_index = token_newline_index(parser);
19641 parser_lex(parser);
19643 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19646 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19649 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19650 pm_accepts_block_stack_push(parser,
true);
19651 begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19652 pm_accepts_block_stack_pop(parser);
19653 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19656 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19657 parse_rescues(parser, opening_newline_index, &begin_keyword, node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19658 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
19660 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->previous);
19661 pm_begin_node_end_keyword_set(parser, node, &parser->previous);
19662 pop_block_exits(parser, previous_block_exits);
19667parse_defined(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19669 parser_lex(parser);
19675 context_push(parser, PM_CONTEXT_DEFINED);
19676 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19678 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
19679 lparen = parser->previous;
19681 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19682 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
19685 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));
19687 if (!parser->recovering) {
19688 accept1(parser, PM_TOKEN_NEWLINE);
19689 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19690 rparen = parser->previous;
19694 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19697 context_pop(parser);
19698 return pm_defined_node_create(parser, NTOK2PTR(lparen), expression, NTOK2PTR(rparen), &keyword);
19702parse_for(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19704 size_t opening_newline_index = token_newline_index(parser);
19705 parser_lex(parser);
19708 context_push(parser, PM_CONTEXT_FOR_INDEX);
19711 if (accept1(parser, PM_TOKEN_USTAR)) {
19712 index = parse_splat(parser, flags, depth);
19713 }
else if (token_begins_expression_p(parser->current.type)) {
19714 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19716 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19717 index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
19721 if (match1(parser, PM_TOKEN_COMMA)) {
19722 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19724 index = parse_target(parser, index,
false,
false);
19727 context_pop(parser);
19728 pm_do_loop_stack_push(parser,
true);
19730 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19733 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));
19734 pm_do_loop_stack_pop(parser);
19737 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19738 do_keyword = parser->previous;
19740 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19741 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
19746 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19747 statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19750 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19751 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19753 return pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous);
19757parse_lambda(
pm_parser_t *parser, uint16_t depth) {
19758 int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
19759 parser->lambda_enclosure_nesting = parser->enclosure_nesting;
19762 size_t opening_newline_index = token_newline_index(parser);
19763 parser_lex(parser);
19765 pm_parser_scope_push(parser,
false);
19768 switch (parser->current.type) {
19769 case PM_TOKEN_PARENTHESIS_LEFT: {
19771 parser_lex(parser);
19773 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19774 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
19776 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
19779 accept1(parser, PM_TOKEN_NEWLINE);
19780 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19782 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
19785 case PM_CASE_PARAMETER: {
19786 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
19790 block_parameters = NULL;
19798 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
19799 opening = parser->previous;
19801 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
19802 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
19805 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
19811 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
19812 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
19820 pm_enclosure_frame_push(parser);
19821 expect1(parser, PM_TOKEN_KEYWORD_DO_LAMBDA, PM_ERR_LAMBDA_OPEN);
19822 opening = parser->previous;
19828 parser->lambda_enclosure_nesting = -1;
19830 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19831 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
19834 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19835 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
19836 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)));
19838 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
19841 pm_enclosure_frame_pop(parser);
19845 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
19846 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
19850 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
19851 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->previous);
19853 pm_parser_scope_pop(parser);
19854 return pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->previous, parameters, body);
19858parse_regexp(
pm_parser_t *parser, uint16_t depth) {
19860 parser_lex(parser);
19862 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19867 .
type = PM_TOKEN_STRING_CONTENT,
19868 .start = parser->previous.
end,
19869 .end = parser->previous.
end
19872 parser_lex(parser);
19875 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
19881 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19888 parser_lex(parser);
19893 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19900 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19901 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
19909 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19911 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
19912 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
19916 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19919 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
19924 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19930 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19931 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19932 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
19937 if (match1(parser, PM_TOKEN_EOF)) {
19938 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19939 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19941 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19944 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19945 return UP(interpolated);
19949parse_alias(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19950 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
19951 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
19955 parser_lex(parser);
19957 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
19958 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
19960 switch (PM_NODE_TYPE(new_name)) {
19961 case PM_BACK_REFERENCE_READ_NODE:
19962 case PM_NUMBERED_REFERENCE_READ_NODE:
19963 case PM_GLOBAL_VARIABLE_READ_NODE: {
19964 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)) {
19965 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
19966 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
19968 }
else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
19969 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19970 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19973 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
19975 case PM_SYMBOL_NODE:
19976 case PM_INTERPOLATED_SYMBOL_NODE: {
19977 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)) {
19978 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19979 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19984 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
19989parse_until(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19991 size_t opening_newline_index = token_newline_index(parser);
19993 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
19994 pm_do_loop_stack_push(parser,
true);
19996 parser_lex(parser);
19997 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));
19999 pm_do_loop_stack_pop(parser);
20000 context_pop(parser);
20003 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20004 do_keyword = parser->previous;
20006 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20010 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20011 pm_accepts_block_stack_push(parser,
true);
20012 statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20013 pm_accepts_block_stack_pop(parser);
20014 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20017 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20018 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
20020 return pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0);
20024parse_while(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20026 size_t opening_newline_index = token_newline_index(parser);
20028 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20029 pm_do_loop_stack_push(parser,
true);
20031 parser_lex(parser);
20032 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));
20034 pm_do_loop_stack_pop(parser);
20035 context_pop(parser);
20038 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20039 do_keyword = parser->previous;
20041 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20045 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20046 pm_accepts_block_stack_push(parser,
true);
20047 statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20048 pm_accepts_block_stack_pop(parser);
20049 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20052 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20053 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
20055 return pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0);
20059parse_xstring(
pm_parser_t *parser, uint16_t depth) {
20061 parser_lex(parser);
20067 if (match1(parser, PM_TOKEN_STRING_END)) {
20072 .
type = PM_TOKEN_STRING_CONTENT,
20073 .start = parser->previous.
end,
20074 .end = parser->previous.
end
20077 parser_lex(parser);
20078 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
20083 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20090 parser_lex(parser);
20092 if (match1(parser, PM_TOKEN_STRING_END)) {
20093 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
20094 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
20095 parser_lex(parser);
20101 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20103 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20104 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
20106 pm_interpolated_xstring_node_append(parser->arena, node, part);
20111 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20115 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20116 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20117 pm_interpolated_xstring_node_append(parser->arena, node, part);
20122 if (match1(parser, PM_TOKEN_EOF)) {
20123 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20124 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20126 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20128 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
20134parse_multi_target(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t binding_power, uint16_t depth) {
20135 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
20138 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20144parse_identifier(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20146 parser_lex(parser);
20148 pm_node_t *node = parse_variable_call(parser);
20150 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
20158 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
20161 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
20170 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
20172 PM_NODE_LENGTH_SET_LOCATION(call, end);
20180 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && token_begins_argument_p(parser->current.type)) ||
20181 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
20182 match1(parser, PM_TOKEN_BRACE_LEFT)
20185 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20186 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
20188 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20192 pm_node_unreference(parser, node);
20198 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
20200 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
20201 pm_node_unreference(parser, node);
20204 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20212 return parse_multi_target(parser, node, binding_power, depth);
20216parse_uninterpolated_symbol_array(
pm_parser_t *parser) {
20218 parser_lex(parser);
20223 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20224 accept1(parser, PM_TOKEN_WORDS_SEP);
20225 if (match1(parser, PM_TOKEN_STRING_END))
break;
20229 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20231 if (current == NULL) {
20232 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20233 parser_lex(parser);
20234 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20235 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20236 parser_lex(parser);
20238 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20241 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20242 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20243 parser_lex(parser);
20246 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20247 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20250 current = UP(interpolated);
20252 assert(
false &&
"unreachable");
20257 pm_array_node_elements_append(parser->arena, array, current);
20260 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20265 if (match1(parser, PM_TOKEN_EOF)) {
20266 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20267 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20269 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20271 pm_array_node_close_set(parser, array, &closing);
20277parse_interpolated_symbol_array(
pm_parser_t *parser, uint16_t depth) {
20278 parser_lex(parser);
20286 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20287 switch (parser->current.type) {
20288 case PM_TOKEN_WORDS_SEP: {
20291 parser->explicit_encoding = NULL;
20293 if (current == NULL) {
20300 pm_array_node_elements_append(parser->arena, array, current);
20304 parser_lex(parser);
20307 case PM_TOKEN_STRING_CONTENT: {
20308 if (current == NULL) {
20313 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20314 parser_lex(parser);
20315 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20319 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20320 parser_lex(parser);
20323 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20330 .
type = PM_TOKEN_STRING_CONTENT,
20335 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20336 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20337 parser_lex(parser);
20340 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20341 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20343 current = UP(interpolated);
20345 assert(
false &&
"unreachable");
20350 case PM_TOKEN_EMBVAR: {
20351 bool start_location_set =
false;
20352 if (current == NULL) {
20356 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
20357 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20364 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
20365 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
20366 PM_NODE_START_SET_NODE(interpolated, current);
20367 start_location_set =
true;
20368 current = UP(interpolated);
20375 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20377 if (!start_location_set) {
20378 PM_NODE_START_SET_NODE(current, part);
20382 case PM_TOKEN_EMBEXPR_BEGIN: {
20383 bool start_location_set =
false;
20384 if (current == NULL) {
20388 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
20389 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20396 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
20397 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
20398 PM_NODE_START_SET_NODE(interpolated, current);
20399 start_location_set =
true;
20400 current = UP(interpolated);
20401 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20405 assert(
false &&
"unreachable");
20408 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20410 if (!start_location_set) {
20411 PM_NODE_START_SET_NODE(current, part);
20416 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
20417 parser_lex(parser);
20424 pm_array_node_elements_append(parser->arena, array, current);
20428 if (match1(parser, PM_TOKEN_EOF)) {
20429 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20430 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20432 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
20434 pm_array_node_close_set(parser, array, &closing);
20440parse_uninterpolated_string_array(
pm_parser_t *parser) {
20442 parser_lex(parser);
20447 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20448 accept1(parser, PM_TOKEN_WORDS_SEP);
20449 if (match1(parser, PM_TOKEN_STRING_END))
break;
20453 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20454 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20457 if (current == NULL) {
20459 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20461 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20463 pm_interpolated_string_node_append(parser, interpolated, current);
20464 pm_interpolated_string_node_append(parser, interpolated,
string);
20465 current = UP(interpolated);
20467 assert(
false &&
"unreachable");
20469 parser_lex(parser);
20473 pm_array_node_elements_append(parser->arena, array, current);
20476 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20481 if (match1(parser, PM_TOKEN_EOF)) {
20482 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20483 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20485 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20488 pm_array_node_close_set(parser, array, &closing);
20493parse_interpolated_string_array(
pm_parser_t *parser, uint16_t depth) {
20495 parser_lex(parser);
20500 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20501 switch (parser->current.type) {
20502 case PM_TOKEN_WORDS_SEP: {
20505 parser->explicit_encoding = NULL;
20507 if (current == NULL) {
20514 pm_array_node_elements_append(parser->arena, array, current);
20518 parser_lex(parser);
20521 case PM_TOKEN_STRING_CONTENT: {
20522 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20523 pm_node_flag_set(
string, parse_unescaped_encoding(parser, parser->explicit_encoding));
20524 parser_lex(parser);
20526 if (current == NULL) {
20532 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20537 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20543 pm_interpolated_string_node_append(parser, interpolated, current);
20544 pm_interpolated_string_node_append(parser, interpolated,
string);
20545 current = UP(interpolated);
20547 assert(
false &&
"unreachable");
20552 case PM_TOKEN_EMBVAR: {
20553 if (current == NULL) {
20557 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
20558 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20564 pm_interpolated_string_node_append(parser, interpolated, current);
20565 current = UP(interpolated);
20572 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20576 case PM_TOKEN_EMBEXPR_BEGIN: {
20577 if (current == NULL) {
20581 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
20582 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20588 pm_interpolated_string_node_append(parser, interpolated, current);
20589 current = UP(interpolated);
20590 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20594 assert(
false &&
"unreachable");
20597 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20602 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
20603 parser_lex(parser);
20610 pm_array_node_elements_append(parser->arena, array, current);
20614 if (match1(parser, PM_TOKEN_EOF)) {
20615 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20616 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20618 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
20621 pm_array_node_close_set(parser, array, &closing);
20626parse_jump(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20627 parser_lex(parser);
20632 if (token_begins_expression_p(parser->current.type) || match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)) {
20633 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
20635 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
20637 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
20640 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
20641 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.
type));
20650 if (parser->previous.
type == PM_TOKEN_COMMA && match1(parser, PM_TOKEN_EOF)) {
20651 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
20658 if (arguments.
block != NULL) {
20659 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20660 pm_node_unreference(parser, arguments.
block);
20661 arguments.
block = NULL;
20665 switch (keyword.
type) {
20666 case PM_TOKEN_KEYWORD_BREAK: {
20668 if (!parser->partial_script) ensure_valid_jump(parser, node);
20671 case PM_TOKEN_KEYWORD_NEXT: {
20673 if (!parser->partial_script) ensure_valid_jump(parser, node);
20676 case PM_TOKEN_KEYWORD_RETURN: {
20678 ensure_valid_return(parser, node);
20682 assert(
false &&
"unreachable");
20683 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20688parse_not(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20690 parser_lex(parser);
20701 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
20702 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
20703 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
20705 accept1(parser, PM_TOKEN_NEWLINE);
20706 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
20709 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
20712 accept1(parser, PM_TOKEN_NEWLINE);
20714 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20717 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20718 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20720 arguments.
opening_loc = TOK2LOC(parser, &lparen);
20721 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));
20723 if (!parser->recovering) {
20724 accept1(parser, PM_TOKEN_NEWLINE);
20725 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20726 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
20736 uint8_t operand_flags = (flags & PM_PARSE_IN_ENDLESS_DEF)
20737 ? (uint8_t) (flags & (PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_IN_ENDLESS_DEF))
20738 : PM_PARSE_ACCEPTS_COMMAND_CALL;
20739 receiver = parse_expression(parser, PM_BINDING_POWER_NOT, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | operand_flags), PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
20742 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
20746parse_preexe(
pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
20748 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20750 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20751 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
20755 parser_lex(parser);
20757 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
20759 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
20761 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
20762 pm_context_t context = parser->current_context->context;
20763 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
20764 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
20767 flush_block_exits(parser, previous_block_exits);
20768 return pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
20772parse_postexe(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20773 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20774 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
20778 parser_lex(parser);
20780 if (context_def_p(parser)) {
20781 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
20784 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
20786 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
20788 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
20789 return pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
20793parse_undef(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20794 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20795 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
20798 parser_lex(parser);
20799 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
20800 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20802 if (!PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20803 pm_undef_node_append(parser->arena, undef, name);
20805 while (match1(parser, PM_TOKEN_COMMA)) {
20806 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
20807 parser_lex(parser);
20809 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20810 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20814 pm_undef_node_append(parser->arena, undef, name);
20822parse_yield(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20824 parser_lex(parser);
20827 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
20832 if (arguments.
block != NULL) {
20833 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20834 pm_node_unreference(parser, arguments.
block);
20835 arguments.
block = NULL;
20839 if (!parser->parsing_eval && !parser->partial_script) ensure_valid_yield(parser, node);
20846 pm_node_t *node = UP(pm_string_node_create_current_string(
20849 .type = PM_TOKEN_STRING_BEGIN,
20850 .start = parser->current.start,
20851 .end = parser->current.start + 1
20854 .type = PM_TOKEN_STRING_CONTENT,
20855 .start = parser->current.start + 1,
20856 .end = parser->current.end
20861 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
20865 parser_lex(parser);
20869 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
20870 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
20877parse_constant(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20879 parser_lex(parser);
20884 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
20885 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && token_begins_argument_p(parser->current.type)) ||
20886 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
20887 match1(parser, PM_TOKEN_BRACE_LEFT)
20890 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20891 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
20894 return parse_multi_target(parser, UP(pm_constant_read_node_create(parser, &parser->previous)), binding_power, depth);
20898parse_constant_path_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
20900 parser_lex(parser);
20902 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
20903 return parse_multi_target(parser, UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous)), binding_power, depth);
20907parse_unary_plus(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20908 if (binding_power > PM_BINDING_POWER_UNARY) {
20909 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20911 parser_lex(parser);
20914 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));
20915 return pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20919parse_unary_minus(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20920 if (binding_power > PM_BINDING_POWER_UNARY) {
20921 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20923 parser_lex(parser);
20926 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));
20927 return pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20931parse_unary_minus_number(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20933 parser_lex(parser);
20935 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));
20937 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20938 pm_token_t exponent_operator = parser->previous;
20939 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));
20940 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20941 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20943 switch (PM_NODE_TYPE(node)) {
20944 case PM_INTEGER_NODE:
20945 case PM_FLOAT_NODE:
20946 case PM_RATIONAL_NODE:
20947 case PM_IMAGINARY_NODE:
20948 parse_negative_numeric(node);
20951 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20960parse_unary_star(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
20961 parser_lex(parser);
20966 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20967 pm_parser_err_prefix(parser, diag_id);
20968 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20971 pm_node_t *splat = parse_splat(parser, flags, depth);
20973 if (match1(parser, PM_TOKEN_COMMA)) {
20974 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20976 return parse_target_validate(parser, splat,
true);
20981parse_super(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20983 parser_lex(parser);
20986 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20991 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
20993 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
20996 return UP(pm_super_node_create(parser, &keyword, &arguments));
21000parse_range(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
21002 parser_lex(parser);
21004 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));
21009 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
21010 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
21013 return pm_range_node_create(parser, NULL, &
operator, right);
21017parse_bang(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
21018 if (binding_power > PM_BINDING_POWER_UNARY) {
21019 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
21022 parser_lex(parser);
21025 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));
21026 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
21027 return pm_call_node_unary_create(parser, &
operator, receiver,
"!");
21031parse_tilde(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
21032 if (binding_power > PM_BINDING_POWER_UNARY) {
21033 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
21036 parser_lex(parser);
21039 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));
21040 return pm_call_node_unary_create(parser, &
operator, receiver,
"~");
21047parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
21048 switch (parser->current.type) {
21049 case PM_TOKEN_BRACKET_LEFT_ARRAY:
21050 return UP(parse_array(parser, flags, depth));
21051 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
21052 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
21053 return parse_parentheses(parser, binding_power, flags, depth);
21054 case PM_TOKEN_BRACE_LEFT_HASH:
21055 return UP(parse_hash(parser, depth));
21056 case PM_TOKEN_CHARACTER_LITERAL:
21057 return parse_char(parser, depth);
21058 case PM_TOKEN_CONSTANT:
21059 return parse_constant(parser, binding_power, flags, depth);
21060 case PM_TOKEN_UCOLON_COLON:
21061 return parse_constant_path_prefix(parser, binding_power, depth);
21062 case PM_TOKEN_UDOT_DOT:
21063 case PM_TOKEN_UDOT_DOT_DOT:
21064 return UP(parse_range(parser, flags, depth));
21065 case PM_TOKEN_FLOAT:
21066 parser_lex(parser);
21067 return UP(pm_float_node_create(parser, &parser->previous));
21068 case PM_TOKEN_FLOAT_IMAGINARY:
21069 parser_lex(parser);
21070 return UP(pm_float_node_imaginary_create(parser, &parser->previous));
21071 case PM_TOKEN_FLOAT_RATIONAL:
21072 parser_lex(parser);
21073 return UP(pm_float_node_rational_create(parser, &parser->previous));
21074 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
21075 parser_lex(parser);
21076 return UP(pm_float_node_rational_imaginary_create(parser, &parser->previous));
21077 case PM_TOKEN_IDENTIFIER:
21078 case PM_TOKEN_METHOD_NAME:
21079 return parse_identifier(parser, binding_power, flags, depth);
21080 case PM_TOKEN_HEREDOC_START:
21081 return parse_heredoc(parser, depth);
21082 case PM_TOKEN_CLASS_VARIABLE:
21083 parser_lex(parser);
21084 return parse_multi_target(parser, UP(pm_class_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
21085 case PM_TOKEN_NUMBERED_REFERENCE:
21086 parser_lex(parser);
21087 return parse_multi_target(parser, UP(pm_numbered_reference_read_node_create(parser, &parser->previous)), binding_power, depth);
21088 case PM_TOKEN_GLOBAL_VARIABLE:
21089 parser_lex(parser);
21090 return parse_multi_target(parser, UP(pm_global_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
21091 case PM_TOKEN_BACK_REFERENCE:
21092 parser_lex(parser);
21093 return parse_multi_target(parser, UP(pm_back_reference_read_node_create(parser, &parser->previous)), binding_power, depth);
21094 case PM_TOKEN_INSTANCE_VARIABLE:
21095 parser_lex(parser);
21096 return parse_multi_target(parser, UP(pm_instance_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
21097 case PM_TOKEN_INTEGER: {
21098 pm_node_flags_t base = parser->integer.base;
21099 parser_lex(parser);
21100 return UP(pm_integer_node_create(parser, base, &parser->previous));
21102 case PM_TOKEN_INTEGER_IMAGINARY: {
21103 pm_node_flags_t base = parser->integer.base;
21104 parser_lex(parser);
21105 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
21107 case PM_TOKEN_INTEGER_RATIONAL: {
21108 pm_node_flags_t base = parser->integer.base;
21109 parser_lex(parser);
21110 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
21112 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
21113 pm_node_flags_t base = parser->integer.base;
21114 parser_lex(parser);
21115 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
21117 case PM_TOKEN_KEYWORD___ENCODING__:
21118 parser_lex(parser);
21119 return UP(pm_source_encoding_node_create(parser, &parser->previous));
21120 case PM_TOKEN_KEYWORD___FILE__:
21121 parser_lex(parser);
21122 return UP(pm_source_file_node_create(parser, &parser->previous));
21123 case PM_TOKEN_KEYWORD___LINE__:
21124 parser_lex(parser);
21125 return UP(pm_source_line_node_create(parser, &parser->previous));
21126 case PM_TOKEN_KEYWORD_ALIAS:
21127 return parse_alias(parser, binding_power, flags, depth);
21128 case PM_TOKEN_KEYWORD_CASE:
21129 return parse_case(parser, flags, depth);
21130 case PM_TOKEN_KEYWORD_BEGIN:
21131 return UP(parse_begin(parser, depth));
21132 case PM_TOKEN_KEYWORD_BEGIN_UPCASE:
21133 return UP(parse_preexe(parser, binding_power, depth));
21134 case PM_TOKEN_KEYWORD_BREAK:
21135 case PM_TOKEN_KEYWORD_NEXT:
21136 case PM_TOKEN_KEYWORD_RETURN:
21137 return parse_jump(parser, flags, depth);
21138 case PM_TOKEN_KEYWORD_SUPER:
21139 return parse_super(parser, flags, depth);
21140 case PM_TOKEN_KEYWORD_YIELD:
21141 return UP(parse_yield(parser, flags, depth));
21142 case PM_TOKEN_KEYWORD_CLASS:
21143 return parse_class(parser, flags, depth);
21144 case PM_TOKEN_KEYWORD_DEF:
21145 return parse_def(parser, flags, depth);
21146 case PM_TOKEN_KEYWORD_DEFINED:
21147 return UP(parse_defined(parser, flags, depth));
21148 case PM_TOKEN_KEYWORD_END_UPCASE:
21149 return UP(parse_postexe(parser, binding_power, flags, depth));
21150 case PM_TOKEN_KEYWORD_FALSE:
21151 parser_lex(parser);
21152 return UP(pm_false_node_create(parser, &parser->previous));
21153 case PM_TOKEN_KEYWORD_FOR:
21154 return UP(parse_for(parser, flags, depth));
21155 case PM_TOKEN_KEYWORD_IF:
21156 if (parser_end_of_line_p(parser)) {
21157 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
21160 size_t opening_newline_index = token_newline_index(parser);
21161 bool if_after_else = parser->previous.
type == PM_TOKEN_KEYWORD_ELSE;
21162 parser_lex(parser);
21164 return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
21165 case PM_TOKEN_KEYWORD_UNDEF:
21166 return UP(parse_undef(parser, binding_power, flags, depth));
21167 case PM_TOKEN_KEYWORD_NOT:
21168 return parse_not(parser, binding_power, flags, depth);
21169 case PM_TOKEN_KEYWORD_UNLESS: {
21170 size_t opening_newline_index = token_newline_index(parser);
21171 parser_lex(parser);
21173 return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
21175 case PM_TOKEN_KEYWORD_MODULE:
21176 return parse_module(parser, flags, depth);
21177 case PM_TOKEN_KEYWORD_NIL:
21178 parser_lex(parser);
21179 return UP(pm_nil_node_create(parser, &parser->previous));
21180 case PM_TOKEN_KEYWORD_REDO: {
21181 parser_lex(parser);
21183 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
21184 if (!parser->partial_script) ensure_valid_jump(parser, node);
21188 case PM_TOKEN_KEYWORD_RETRY: {
21189 parser_lex(parser);
21191 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
21192 ensure_valid_retry(parser, node);
21196 case PM_TOKEN_KEYWORD_SELF:
21197 parser_lex(parser);
21198 return UP(pm_self_node_create(parser, &parser->previous));
21199 case PM_TOKEN_KEYWORD_TRUE:
21200 parser_lex(parser);
21201 return UP(pm_true_node_create(parser, &parser->previous));
21202 case PM_TOKEN_KEYWORD_UNTIL:
21203 return UP(parse_until(parser, flags, depth));
21204 case PM_TOKEN_KEYWORD_WHILE:
21205 return UP(parse_while(parser, flags, depth));
21206 case PM_TOKEN_PERCENT_LOWER_I:
21207 return UP(parse_uninterpolated_symbol_array(parser));
21208 case PM_TOKEN_PERCENT_UPPER_I:
21209 return UP(parse_interpolated_symbol_array(parser, depth));
21210 case PM_TOKEN_PERCENT_LOWER_W:
21211 return UP(parse_uninterpolated_string_array(parser));
21212 case PM_TOKEN_PERCENT_UPPER_W:
21213 return UP(parse_interpolated_string_array(parser, depth));
21214 case PM_TOKEN_REGEXP_BEGIN:
21215 return parse_regexp(parser, depth);
21216 case PM_TOKEN_XSTRING_BEGIN:
21217 case PM_TOKEN_PERCENT_LOWER_X:
21218 return parse_xstring(parser, depth);
21219 case PM_TOKEN_USTAR:
21220 return parse_unary_star(parser, binding_power, flags, diag_id, depth);
21221 case PM_TOKEN_BANG:
21222 return UP(parse_bang(parser, binding_power, flags, depth));
21223 case PM_TOKEN_TILDE:
21224 return UP(parse_tilde(parser, binding_power, flags, depth));
21225 case PM_TOKEN_UMINUS:
21226 return UP(parse_unary_minus(parser, binding_power, flags, depth));
21227 case PM_TOKEN_UMINUS_NUM:
21228 return UP(parse_unary_minus_number(parser, flags, depth));
21229 case PM_TOKEN_MINUS_GREATER:
21230 return UP(parse_lambda(parser, depth));
21231 case PM_TOKEN_UPLUS:
21232 return UP(parse_unary_plus(parser, binding_power, flags, depth));
21233 case PM_TOKEN_STRING_BEGIN:
21234 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
21235 case PM_TOKEN_SYMBOL_BEGIN:
21236 return parse_symbol(parser, PM_LEX_STATE_END, (uint16_t) (depth + 1));
21238 pm_context_t recoverable = context_recoverable(parser, &parser->current);
21240 if (recoverable != PM_CONTEXT_NONE) {
21241 parser->recovering =
true;
21246 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
21247 pm_parser_err_prefix(parser, diag_id);
21253 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
21254 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
21258 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
21260 pm_parser_err_prefix(parser, diag_id);
21263 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
21269parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth);
21279parse_rescue_modifier_terminator(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
21280 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
21281 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21282 parser_lex(parser);
21283 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));
21294 if (match1(parser, PM_TOKEN_COMMA) && pm_command_before_comma_p(parser, value)) {
21295 pm_parser_err_current(parser, PM_ERR_INVALID_COMMA);
21309parse_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) {
21312 uint8_t command_flags = (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT)
21313 ? (uint8_t) (flags & PM_PARSE_ACCEPTS_COMMAND_CALL)
21314 : (previous_binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0);
21315 if (command_flags) command_flags |= PM_PARSE_ACCEPTS_COMMAND_DEF;
21317 pm_node_t *value = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | command_flags), diag_id, (uint16_t) (depth + 1));
21322 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
21323 parse_write_value_comma_check(parser, value);
21330 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(parser, value) || pm_block_call_p(value))) {
21331 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21332 parser_lex(parser);
21333 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));
21338 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21339 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21342 parser_lex(parser);
21347 bool statement_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21348 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21350 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21351 context_pop(parser);
21356 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21357 parse_rescue_modifier_terminator(parser, flags, depth);
21360 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21372 switch (PM_NODE_TYPE(node)) {
21373 case PM_BEGIN_NODE: {
21378 case PM_LOCAL_VARIABLE_WRITE_NODE: {
21380 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
21383 case PM_PARENTHESES_NODE: {
21385 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
21388 case PM_STATEMENTS_NODE: {
21393 parse_assignment_value_local(parser, statement);
21415parse_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) {
21416 bool statement_level = (previous_binding_power == PM_BINDING_POWER_STATEMENT) || (flags & PM_PARSE_ACCEPTS_STATEMENT);
21418 bool permitted =
true;
21419 if (!statement_level && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
21424 uint8_t command_call_flag = (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT)
21425 ? (uint8_t) (flags & PM_PARSE_ACCEPTS_COMMAND_CALL)
21426 : ((previous_binding_power < PM_BINDING_POWER_MODIFIER || statement_level) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0);
21431 if (command_call_flag && binding_power != PM_BINDING_POWER_MULTI_ASSIGNMENT + 1) {
21432 command_call_flag |= PM_PARSE_ACCEPTS_COMMAND_DEF;
21435 pm_node_t *value = parse_starred_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | command_call_flag), diag_id, (uint16_t) (depth + 1));
21436 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
21438 parse_assignment_value_local(parser, value);
21439 bool single_value =
true;
21441 parse_write_value_comma_check(parser, value);
21446 if (statement_level && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
21447 single_value =
false;
21450 pm_array_node_elements_append(parser->arena, array, value);
21453 while (accept1(parser, PM_TOKEN_COMMA)) {
21454 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
21456 pm_array_node_elements_append(parser->arena, array, element);
21457 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
21459 parse_assignment_value_local(parser, element);
21467 if (single_value && pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(parser, value) || pm_block_call_p(value))) {
21468 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21469 parser_lex(parser);
21470 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));
21475 bool multiple_assignment = (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1));
21476 if ((single_value || multiple_assignment) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21477 bool command_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21486 if (multiple_assignment && command_value)
return value;
21488 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21491 parser_lex(parser);
21497 bool statement_value = multiple_assignment || command_value;
21498 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21500 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21501 context_pop(parser);
21506 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21507 parse_rescue_modifier_terminator(parser, flags, depth);
21510 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21529parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth) {
21534 if (match1(parser, PM_TOKEN_USTAR)) {
21536 parser_lex(parser);
21537 value = parse_splat(parser, flags, depth);
21544 value = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, flags | PM_PARSE_ACCEPTS_STATEMENT | PM_PARSE_ACCEPTS_COMMAND_DEF, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21545 multiple = match1(parser, PM_TOKEN_COMMA) || PM_NODE_TYPE_P(value, PM_MULTI_TARGET_NODE);
21549 pm_node_t *target = parse_targets_validate(parser, value, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21556 if (!match1(parser, PM_TOKEN_EQUAL)) {
21557 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
21562 parser_lex(parser);
21564 pm_node_t *values = parse_assignment_values(parser, PM_BINDING_POWER_STATEMENT, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21565 value = parse_write(parser, target, &
operator, values);
21572 if (!PM_NODE_TYPE_P(value, PM_MATCH_REQUIRED_NODE) && !PM_NODE_TYPE_P(value, PM_MATCH_PREDICATE_NODE)) {
21573 parse_rescue_modifier_terminator(parser, flags, depth);
21581 return parse_expression(parser, PM_BINDING_POWER_DEFINED, flags, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21594 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
21595 pm_node_unreference(parser, UP(call_node->
arguments));
21599 if (call_node->
block != NULL) {
21600 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
21601 pm_node_unreference(parser, UP(call_node->
block));
21602 call_node->
block = NULL;
21607pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21610 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21611 uint8_t value = escape_hexadecimal_digit(*cursor);
21614 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21615 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21619 pm_buffer_append_byte(unescaped, value);
21621 pm_buffer_append_string(unescaped,
"\\x", 2);
21628pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21629 uint8_t value = (uint8_t) (*cursor -
'0');
21632 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21633 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21636 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21637 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21642 pm_buffer_append_byte(unescaped, value);
21648 const uint8_t *start = cursor - 1;
21651 if (cursor >= end) {
21652 pm_buffer_append_string(unescaped,
"\\u", 2);
21656 if (*cursor !=
'{') {
21657 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21658 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21660 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21661 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21664 return cursor + length;
21669 while (cursor < end && *cursor ==
' ') cursor++;
21671 if (cursor >= end)
break;
21672 if (*cursor ==
'}') {
21677 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21681 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21683 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21691pm_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) {
21692 const uint8_t *end = source + length;
21693 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21696 if (++cursor >= end) {
21697 pm_buffer_append_byte(unescaped,
'\\');
21703 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21705 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21706 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21709 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
21712 pm_buffer_append_byte(unescaped,
'\\');
21716 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->encoding_changed, parser->encoding);
21717 if (next_cursor == NULL)
break;
21719 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21720 cursor = next_cursor;
21723 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21755 const uint8_t *source = pm_string_source(capture);
21756 size_t length = pm_string_length(capture);
21767 const uint8_t *cursor = pm_memchr(source,
'\\', length, parser->encoding_changed, parser->encoding);
21768 if (PRISM_UNLIKELY(cursor != NULL)) {
21769 pm_named_capture_escape(parser, &unescaped, source, length, cursor, name_data->
shared ? NULL : &call->receiver->location);
21776 if (pm_buffer_length(&unescaped) == 0)
return;
21778 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21779 length = pm_buffer_length(&unescaped);
21782 const uint8_t *start;
21783 const uint8_t *end;
21788 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21789 pm_buffer_cleanup(&unescaped);
21793 if (name_data->
shared) {
21797 end = source + length;
21798 name = pm_parser_constant_id_raw(parser, start, end);
21802 start = parser->start + PM_NODE_START(call->
receiver);
21803 end = parser->start + PM_NODE_END(call->
receiver);
21805 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
21806 memcpy(memory, source, length);
21807 name = pm_parser_constant_id_owned(parser, memory, length);
21814 if (name != 0 && pm_constant_id_set_insert(parser->arena, names, name)) {
21817 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21820 if (pm_local_is_keyword((
const char *) source, length)) {
21821 pm_buffer_cleanup(&unescaped);
21827 pm_parser_local_add(parser, name, start, end, 0);
21832 if (name_data->
match == NULL) {
21833 name_data->
match = pm_match_write_node_create(parser, call);
21838 pm_token_t token = { .type = 0, .start = start, .end = end };
21840 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &token_loc, name, depth == -1 ? 0 : (uint32_t) depth));
21841 pm_node_list_append(parser->arena, &name_data->
match->
targets, target);
21844 pm_buffer_cleanup(&unescaped);
21861 pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content), extended_mode, parse_regular_expression_named_capture, &name_data);
21863 if (name_data.
match != NULL) {
21864 return UP(name_data.
match);
21872 context_push(parser, PM_CONTEXT_TERNARY);
21874 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21877 parser_lex(parser);
21879 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));
21881 if (parser->recovering) {
21889 pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
21891 context_pop(parser);
21892 pop_block_exits(parser, previous_block_exits);
21893 return pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21896 accept1(parser, PM_TOKEN_NEWLINE);
21897 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21900 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));
21902 context_pop(parser);
21903 pop_block_exits(parser, previous_block_exits);
21904 return pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21908parse_constant_path_infix(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
21910 parser_lex(parser);
21912 switch (parser->current.type) {
21913 case PM_TOKEN_CONSTANT: {
21914 parser_lex(parser);
21918 (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21919 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && token_begins_argument_p(parser->current.type))
21930 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21931 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21935 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21938 return parse_multi_target(parser, path, previous_binding_power, depth);
21940 case PM_CASE_OPERATOR:
21941 case PM_CASE_KEYWORD:
21942 case PM_TOKEN_IDENTIFIER:
21943 case PM_TOKEN_METHOD_NAME: {
21944 parser_lex(parser);
21950 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21952 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21953 return parse_multi_target(parser, UP(call), previous_binding_power, depth);
21955 case PM_TOKEN_PARENTHESIS_LEFT: {
21959 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21961 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21964 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21965 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21970parse_match(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
21979 parser_lex(parser);
21981 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));
21984 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &
operator, argument, 0);
21989 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21996 bool interpolated =
false;
21997 size_t total_length = 0;
22001 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
22002 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
22004 interpolated =
true;
22009 if (!interpolated && total_length > 0) {
22010 void *memory =
xmalloc(total_length);
22011 if (!memory) abort();
22013 uint8_t *cursor = memory;
22016 size_t length = pm_string_length(unescaped);
22018 memcpy(cursor, pm_string_source(unescaped), length);
22023 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
22025 result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
22026 pm_string_cleanup(&owned);
22028 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
22039 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
22041 if (name_data.
match != NULL) {
22042 result = UP(name_data.
match);
22050parse_equal(
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) {
22053 switch (PM_NODE_TYPE(node)) {
22054 case PM_CALL_NODE: {
22060 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22061 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
22065 case PM_CASE_WRITABLE: {
22069 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
22070 pm_parser_local_add_location(parser, &node->
location, 0);
22073 parser_lex(parser);
22074 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));
22076 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
22077 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
22080 return parse_write(parser, node, &
operator, value);
22082 case PM_SPLAT_NODE: {
22084 pm_multi_target_node_targets_append(parser, multi_target, node);
22086 parser_lex(parser);
22087 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));
22088 return parse_write(parser, UP(multi_target), &
operator, value);
22090 case PM_SOURCE_ENCODING_NODE:
22091 case PM_FALSE_NODE:
22092 case PM_SOURCE_FILE_NODE:
22093 case PM_SOURCE_LINE_NODE:
22096 case PM_TRUE_NODE: {
22099 parser_lex(parser);
22100 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
22101 return parse_unwriteable_write(parser, node, &
operator, value);
22107 parser_lex(parser);
22108 pm_parser_err_token(parser, &
operator, PM_ERR_EXPRESSION_NOT_WRITABLE);
22114parse_and_equal(
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) {
22117 switch (PM_NODE_TYPE(node)) {
22118 case PM_BACK_REFERENCE_READ_NODE:
22119 case PM_NUMBERED_REFERENCE_READ_NODE:
22120 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
22122 case PM_GLOBAL_VARIABLE_READ_NODE: {
22123 parser_lex(parser);
22125 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22126 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &
operator, value));
22130 case PM_CLASS_VARIABLE_READ_NODE: {
22131 parser_lex(parser);
22133 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22138 case PM_CONSTANT_PATH_NODE: {
22139 parser_lex(parser);
22141 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22144 return parse_shareable_constant_write(parser, write);
22146 case PM_CONSTANT_READ_NODE: {
22147 parser_lex(parser);
22149 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22152 if (context_def_p(parser)) {
22153 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
22156 return parse_shareable_constant_write(parser, write);
22158 case PM_INSTANCE_VARIABLE_READ_NODE: {
22159 parser_lex(parser);
22161 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22166 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
22168 parser_lex(parser);
22170 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22171 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &
operator, value, name, 0));
22173 pm_node_unreference(parser, node);
22176 case PM_LOCAL_VARIABLE_READ_NODE: {
22177 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
22179 pm_node_unreference(parser, node);
22183 parser_lex(parser);
22185 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22186 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &
operator, value, cast->
name, cast->
depth));
22190 case PM_CALL_NODE: {
22196 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22199 parser_lex(parser);
22201 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22202 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22209 parser_lex(parser);
22214 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22215 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22216 return UP(pm_index_and_write_node_create(parser, cast, &
operator, value));
22220 if (pm_call_node_writable_p(parser, cast)) {
22221 parse_write_name(parser, &cast->
name);
22223 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22226 parse_call_operator_write(parser, cast, &
operator);
22227 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22228 return UP(pm_call_and_write_node_create(parser, cast, &
operator, value));
22230 case PM_MULTI_WRITE_NODE: {
22231 parser_lex(parser);
22233 pm_parser_err_token(parser, &
operator, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
22237 parser_lex(parser);
22242 pm_parser_err_token(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
22248parse_or_equal(
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) {
22251 switch (PM_NODE_TYPE(node)) {
22252 case PM_BACK_REFERENCE_READ_NODE:
22253 case PM_NUMBERED_REFERENCE_READ_NODE:
22254 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
22256 case PM_GLOBAL_VARIABLE_READ_NODE: {
22257 parser_lex(parser);
22259 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22260 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &
operator, value));
22264 case PM_CLASS_VARIABLE_READ_NODE: {
22265 parser_lex(parser);
22267 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22272 case PM_CONSTANT_PATH_NODE: {
22273 parser_lex(parser);
22275 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22278 return parse_shareable_constant_write(parser, write);
22280 case PM_CONSTANT_READ_NODE: {
22281 parser_lex(parser);
22283 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22286 if (context_def_p(parser)) {
22287 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
22290 return parse_shareable_constant_write(parser, write);
22292 case PM_INSTANCE_VARIABLE_READ_NODE: {
22293 parser_lex(parser);
22295 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22300 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
22302 parser_lex(parser);
22304 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22305 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &
operator, value, name, 0));
22307 pm_node_unreference(parser, node);
22310 case PM_LOCAL_VARIABLE_READ_NODE: {
22311 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
22312 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
22313 pm_node_unreference(parser, node);
22317 parser_lex(parser);
22319 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22320 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &
operator, value, cast->
name, cast->
depth));
22324 case PM_CALL_NODE: {
22330 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22333 parser_lex(parser);
22335 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22336 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22343 parser_lex(parser);
22348 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22349 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22350 return UP(pm_index_or_write_node_create(parser, cast, &
operator, value));
22354 if (pm_call_node_writable_p(parser, cast)) {
22355 parse_write_name(parser, &cast->
name);
22357 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22360 parse_call_operator_write(parser, cast, &
operator);
22361 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22362 return UP(pm_call_or_write_node_create(parser, cast, &
operator, value));
22364 case PM_MULTI_WRITE_NODE: {
22365 parser_lex(parser);
22366 pm_parser_err_token(parser, &
operator, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
22370 parser_lex(parser);
22375 pm_parser_err_token(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
22381parse_operator_equal(
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) {
22384 switch (PM_NODE_TYPE(node)) {
22385 case PM_BACK_REFERENCE_READ_NODE:
22386 case PM_NUMBERED_REFERENCE_READ_NODE:
22387 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
22389 case PM_GLOBAL_VARIABLE_READ_NODE: {
22390 parser_lex(parser);
22392 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22393 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &
operator, value));
22397 case PM_CLASS_VARIABLE_READ_NODE: {
22398 parser_lex(parser);
22400 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22405 case PM_CONSTANT_PATH_NODE: {
22406 parser_lex(parser);
22408 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22411 return parse_shareable_constant_write(parser, write);
22413 case PM_CONSTANT_READ_NODE: {
22414 parser_lex(parser);
22416 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22419 if (context_def_p(parser)) {
22420 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
22423 return parse_shareable_constant_write(parser, write);
22425 case PM_INSTANCE_VARIABLE_READ_NODE: {
22426 parser_lex(parser);
22428 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22433 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
22435 parser_lex(parser);
22437 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22438 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &
operator, value, name, 0));
22440 pm_node_unreference(parser, node);
22443 case PM_LOCAL_VARIABLE_READ_NODE: {
22444 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
22445 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
22446 pm_node_unreference(parser, node);
22450 parser_lex(parser);
22452 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22453 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &
operator, value, cast->
name, cast->
depth));
22457 case PM_CALL_NODE: {
22458 parser_lex(parser);
22464 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22467 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22468 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22476 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22477 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22478 return UP(pm_index_operator_write_node_create(parser, cast, &
operator, value));
22482 if (pm_call_node_writable_p(parser, cast)) {
22483 parse_write_name(parser, &cast->
name);
22485 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22488 parse_call_operator_write(parser, cast, &
operator);
22489 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22490 return UP(pm_call_operator_write_node_create(parser, cast, &
operator, value));
22492 case PM_MULTI_WRITE_NODE: {
22493 parser_lex(parser);
22494 pm_parser_err_token(parser, &
operator, PM_ERR_OPERATOR_MULTI_ASSIGN);
22498 parser_lex(parser);
22503 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
22509parse_call(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
22511 parser_lex(parser);
22516 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
22517 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22518 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
22521 switch (PM_NODE_TYPE(node)) {
22522 case PM_RESCUE_MODIFIER_NODE: {
22525 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22529 case PM_AND_NODE: {
22531 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22532 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22538 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22539 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22549 switch (parser->current.type) {
22550 case PM_CASE_OPERATOR:
22551 case PM_CASE_KEYWORD:
22552 case PM_TOKEN_CONSTANT:
22553 case PM_TOKEN_IDENTIFIER:
22554 case PM_TOKEN_METHOD_NAME: {
22555 parser_lex(parser);
22556 message = parser->previous;
22560 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
22561 message = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
22565 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22566 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
22569 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
22572 match1(parser, PM_TOKEN_COMMA)
22574 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22581parse_aref(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
22582 parser_lex(parser);
22585 arguments.
opening_loc = TOK2LOC(parser, &parser->previous);
22587 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22588 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
22589 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22592 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
22596 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22597 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22598 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22605 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22606 block = parse_block(parser, (uint16_t) (depth + 1));
22607 pm_arguments_validate_block(parser, &arguments, block);
22608 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22609 block = parse_block(parser, (uint16_t) (depth + 1));
22612 if (block != NULL) {
22613 if (arguments.
block != NULL) {
22614 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
22616 arguments.
arguments = pm_arguments_node_create(parser);
22618 pm_arguments_node_arguments_append(parser->arena, arguments.
arguments, arguments.
block);
22621 arguments.
block = UP(block);
22624 return UP(pm_call_node_aref_create(parser, node, &arguments));
22628parse_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) {
22631 switch (token.type) {
22632 case PM_TOKEN_EQUAL:
22633 return parse_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22634 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL:
22635 return parse_and_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22636 case PM_TOKEN_PIPE_PIPE_EQUAL:
22637 return parse_or_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22638 case PM_TOKEN_AMPERSAND_EQUAL:
22639 case PM_TOKEN_CARET_EQUAL:
22640 case PM_TOKEN_GREATER_GREATER_EQUAL:
22641 case PM_TOKEN_LESS_LESS_EQUAL:
22642 case PM_TOKEN_MINUS_EQUAL:
22643 case PM_TOKEN_PERCENT_EQUAL:
22644 case PM_TOKEN_PIPE_EQUAL:
22645 case PM_TOKEN_PLUS_EQUAL:
22646 case PM_TOKEN_SLASH_EQUAL:
22647 case PM_TOKEN_STAR_EQUAL:
22648 case PM_TOKEN_STAR_STAR_EQUAL:
22649 return parse_operator_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22650 case PM_TOKEN_AMPERSAND_AMPERSAND:
22651 case PM_TOKEN_KEYWORD_AND: {
22652 parser_lex(parser);
22654 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));
22655 return UP(pm_and_node_create(parser, node, &token, right));
22657 case PM_TOKEN_KEYWORD_OR:
22658 case PM_TOKEN_PIPE_PIPE: {
22659 parser_lex(parser);
22661 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));
22662 return UP(pm_or_node_create(parser, node, &token, right));
22664 case PM_TOKEN_EQUAL_TILDE:
22665 return parse_match(parser, node, binding_power, flags, depth);
22666 case PM_TOKEN_UAMPERSAND:
22667 case PM_TOKEN_USTAR:
22668 case PM_TOKEN_USTAR_STAR:
22671 case PM_TOKEN_BANG_EQUAL:
22672 case PM_TOKEN_BANG_TILDE:
22673 case PM_TOKEN_EQUAL_EQUAL:
22674 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
22675 case PM_TOKEN_LESS_EQUAL_GREATER:
22676 case PM_TOKEN_CARET:
22677 case PM_TOKEN_PIPE:
22678 case PM_TOKEN_AMPERSAND:
22679 case PM_TOKEN_GREATER_GREATER:
22680 case PM_TOKEN_LESS_LESS:
22681 case PM_TOKEN_MINUS:
22682 case PM_TOKEN_PLUS:
22683 case PM_TOKEN_PERCENT:
22684 case PM_TOKEN_SLASH:
22685 case PM_TOKEN_STAR:
22686 case PM_TOKEN_STAR_STAR: {
22687 parser_lex(parser);
22689 switch (PM_NODE_TYPE(node)) {
22690 case PM_RESCUE_MODIFIER_NODE: {
22693 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22697 case PM_AND_NODE: {
22699 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22700 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22706 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22707 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22715 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));
22716 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
22718 case PM_TOKEN_GREATER:
22719 case PM_TOKEN_GREATER_EQUAL:
22720 case PM_TOKEN_LESS:
22721 case PM_TOKEN_LESS_EQUAL: {
22722 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
22723 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
22726 parser_lex(parser);
22727 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));
22728 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
22730 case PM_TOKEN_AMPERSAND_DOT:
22732 return parse_call(parser, node, previous_binding_power, flags, depth);
22733 case PM_TOKEN_DOT_DOT:
22734 case PM_TOKEN_DOT_DOT_DOT: {
22735 parser_lex(parser);
22738 if (token_begins_expression_p(parser->current.type)) {
22739 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22742 return UP(pm_range_node_create(parser, node, &token, right));
22744 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
22746 parser_lex(parser);
22748 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));
22749 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
22751 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
22753 parser_lex(parser);
22755 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));
22756 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
22758 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
22759 parser_lex(parser);
22761 pm_statements_node_body_append(parser, statements, node,
true);
22763 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));
22764 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));
22766 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
22767 parser_lex(parser);
22769 pm_statements_node_body_append(parser, statements, node,
true);
22771 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));
22772 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));
22774 case PM_TOKEN_QUESTION_MARK:
22775 return UP(parse_ternary(parser, node, flags, depth));
22776 case PM_TOKEN_COLON_COLON:
22777 return parse_constant_path_infix(parser, node, previous_binding_power, flags, depth);
22778 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22779 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
22780 parser_lex(parser);
22781 accept1(parser, PM_TOKEN_NEWLINE);
22783 pm_node_t *value = parse_rescue_modifier_value(parser, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), previous_binding_power == PM_BINDING_POWER_STATEMENT, (uint16_t) (depth + 1));
22784 context_pop(parser);
22786 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
22788 case PM_TOKEN_BRACKET_LEFT:
22789 return parse_aref(parser, node, previous_binding_power, flags, depth);
22790 case PM_TOKEN_KEYWORD_IN: {
22791 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22792 parser->pattern_matching_newlines =
true;
22795 parser->command_start =
false;
22796 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22797 parser_lex(parser);
22800 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));
22802 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22804 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
22806 case PM_TOKEN_EQUAL_GREATER: {
22807 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22808 parser->pattern_matching_newlines =
true;
22811 parser->command_start =
false;
22812 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22813 parser_lex(parser);
22816 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));
22818 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22820 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
22823 assert(
false &&
"unreachable");
22828#undef PM_PARSE_PATTERN_SINGLE
22829#undef PM_PARSE_PATTERN_TOP
22830#undef PM_PARSE_PATTERN_MULTI
22846 pm_binding_power_t left = pm_binding_powers[parser->current.type].
left;
22848 switch (PM_NODE_TYPE(node)) {
22849 case PM_MULTI_WRITE_NODE:
22850 case PM_RETURN_NODE:
22851 case PM_BREAK_NODE:
22853 return left > PM_BINDING_POWER_MODIFIER;
22854 case PM_CLASS_VARIABLE_WRITE_NODE:
22855 case PM_CONSTANT_PATH_WRITE_NODE:
22856 case PM_CONSTANT_WRITE_NODE:
22857 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22858 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22859 case PM_LOCAL_VARIABLE_WRITE_NODE:
22860 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
22861 case PM_CALL_NODE: {
22864 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
22865 return left > PM_BINDING_POWER_MODIFIER;
22871 if (pm_command_call_value_p(parser, node)) {
22872 return left > PM_BINDING_POWER_COMPOSITION;
22878 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22880 case PM_SUPER_NODE:
22881 case PM_YIELD_NODE:
22884 if (pm_command_call_value_p(parser, node)) {
22885 return left > PM_BINDING_POWER_COMPOSITION;
22890 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22895 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(parser, node);
22896 case PM_RESCUE_MODIFIER_NODE:
22900 if (left > PM_BINDING_POWER_MODIFIER) {
22903 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
22920parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
22921 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
22922 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22923 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
22926 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
22931 switch (PM_NODE_TYPE(node)) {
22932 case PM_ERROR_RECOVERY_NODE:
22934 case PM_PRE_EXECUTION_NODE:
22936 case PM_POST_EXECUTION_NODE:
22937 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22938 case PM_ALIAS_METHOD_NODE:
22939 case PM_UNDEF_NODE:
22940 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
22945 case PM_SUPER_NODE:
22946 case PM_YIELD_NODE:
22948 if (parse_expression_terminator(parser, node)) {
22952 case PM_SYMBOL_NODE:
22953 if (pm_symbol_node_label_p(parser, node)) {
22964 pm_token_type_t current_token_type;
22967 current_token_type = parser->current.type,
22968 current_binding_powers = pm_binding_powers[current_token_type],
22969 binding_power <= current_binding_powers.
left &&
22970 current_binding_powers.
binary
22972 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
22973 if (parse_expression_terminator(parser, node))
return node;
22977 if (current_binding_powers.
nonassoc) {
22985 if (next_binding_powers.
nonassoc && next_binding_powers.
left == current_binding_powers.
left) {
22986 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));
22997 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22998 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22999 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));
23003 if (PM_BINDING_POWER_TERM <= next_binding_powers.
left) {
23006 }
else if (current_binding_powers.
left <= next_binding_powers.
left) {
23011 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
23020 switch (node->
type) {
23021 case PM_CALL_NODE: {
23035 cast->
block == NULL &&
23045 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
23048 flags &= (uint8_t) ~(PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF);
23053 case PM_CONSTANT_PATH_NODE:
23056 flags &= (uint8_t) ~(PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF);
23061 if (context_terminator(parser->current_context->context, &parser->current)) {
23064 !next_binding_powers.
binary ||
23065 binding_power > next_binding_powers.
left ||
23066 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
23082 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
23083 if (statements == NULL) {
23084 statements = pm_statements_node_create(parser);
23088 pm_arguments_node_arguments_append(
23091 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
23094 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
23097 pm_parser_constant_id_constant(parser,
"print", 5)
23101 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
23102 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
23103 if (statements == NULL) {
23104 statements = pm_statements_node_create(parser);
23108 pm_arguments_node_arguments_append(
23111 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
23114 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
23115 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
23119 pm_parser_constant_id_constant(parser,
"$F", 2),
23123 pm_statements_node_body_prepend(parser->arena, statements, UP(write));
23127 pm_arguments_node_arguments_append(
23130 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
23133 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
23135 pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
23137 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
23139 UP(pm_true_node_synthesized_create(parser))
23142 pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
23143 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
23147 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
23149 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
23153 statements = wrapped_statements;
23167 if (parser->current_scope == NULL) {
23168 pm_parser_scope_push(parser,
true);
23172 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
23174 parser_lex(parser);
23177 if (statements != NULL && !parser->parsing_eval) {
23181 assert(statements->
body.
size > 0);
23182 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
23186 pm_locals_order(parser, &parser->current_scope->locals, &locals,
true);
23187 pm_parser_scope_pop(parser);
23192 statements = wrap_statements(parser, statements);
23194 flush_block_exits(parser, previous_block_exits);
23200 if (statements == NULL) {
23201 statements = pm_statements_node_create(parser);
23205 return UP(pm_program_node_create(parser, &locals, statements));
23222pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
23223 size_t little_length = strlen(little);
23225 for (
const char *max = big + big_length - little_length; big <= max; big++) {
23226 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
23233#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
23241pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
23242 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
23243 pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
23254 const char *switches = pm_strnstr(engine,
" -", length);
23255 if (switches == NULL)
return;
23258 options->shebang_callback(
23260 (
const uint8_t *) (switches + 1),
23261 length - ((
size_t) (switches - engine)) - 1,
23262 options->shebang_callback_data
23265 size_t encoding_length;
23266 if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
23267 const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
23268 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23271 parser->command_line = next_options.command_line;
23272 parser->frozen_string_literal = next_options.frozen_string_literal;
23280 assert(arena != NULL);
23281 assert(source != NULL);
23285 .metadata_arena = { 0 },
23287 .lex_state = PM_LEX_STATE_BEG,
23288 .enclosure_nesting = 0,
23289 .lambda_enclosure_nesting = -1,
23290 .brace_nesting = 0,
23291 .do_loop_stack = 0,
23292 .accepts_block_stack = 0,
23295 .stack = {{ .mode = PM_LEX_DEFAULT }},
23296 .current = &parser->lex_modes.stack[0],
23299 .end = source + size,
23300 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
23301 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
23302 .next_start = NULL,
23303 .heredoc_end = NULL,
23305 .comment_list = { 0 },
23306 .magic_comment_list = { 0 },
23307 .warning_list = { 0 },
23308 .error_list = { 0 },
23309 .current_scope = NULL,
23310 .current_context = NULL,
23311 .encoding = PM_ENCODING_UTF_8_ENTRY,
23312 .encoding_changed_callback = NULL,
23313 .encoding_comment_start = source,
23314 .lex_callback = { 0 },
23315 .filepath = PM_STRING_EMPTY,
23316 .constant_pool = { 0 },
23317 .line_offsets = { 0 },
23319 .current_string = PM_STRING_EMPTY,
23321 .explicit_encoding = NULL,
23323 .parsing_eval =
false,
23324 .partial_script =
false,
23325 .attach_comments =
false,
23326 .command_start =
true,
23327 .recovering =
false,
23328 .continuable =
true,
23329 .encoding_locked =
false,
23330 .encoding_changed =
false,
23331 .pattern_matching_newlines =
false,
23332 .in_keyword_arg =
false,
23333 .current_block_exits = NULL,
23334 .semantic_token_seen =
false,
23336 .warn_mismatched_indentation =
true
23344 if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
23345 if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
23352 uint32_t constant_size = ((uint32_t) size) / 120;
23353 pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
23358 size_t newline_size = size / 22;
23359 pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
23362 if (options != NULL) {
23364 if (pm_string_length(&options->filepath) > 0) {
23365 parser->filepath = options->filepath;
23369 parser->start_line = options->line;
23372 size_t encoding_length = pm_string_length(&options->encoding);
23373 if (encoding_length > 0) {
23374 const uint8_t *encoding_source = pm_string_source(&options->encoding);
23375 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23379 parser->encoding_locked = options->encoding_locked;
23382 parser->frozen_string_literal = options->frozen_string_literal;
23385 parser->command_line = options->command_line;
23388 parser->version = options->version;
23391 parser->partial_script = options->partial_script;
23394 parser->attach_comments = options->attach_comments;
23397 parser->parsing_eval = options->scopes_count > 0;
23398 if (parser->parsing_eval) parser->warn_mismatched_indentation =
false;
23400 for (
size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
23402 pm_parser_scope_push(parser, scope_index == 0);
23406 parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
23408 for (
size_t local_index = 0; local_index < scope->locals_count; local_index++) {
23409 const pm_string_t *local = pm_options_scope_local(scope, local_index);
23411 const uint8_t *source = pm_string_source(local);
23412 size_t length = pm_string_length(local);
23414 uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
23415 memcpy(allocated, source, length);
23416 pm_parser_local_add_owned(parser, allocated, length);
23423 if (parser->version == PM_OPTIONS_VERSION_UNSET) {
23424 parser->version = PM_OPTIONS_VERSION_LATEST;
23427 pm_accepts_block_stack_push(parser,
true);
23430 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
23431 parser->current.end += 3;
23432 parser->encoding_comment_start += 3;
23434 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
23435 parser->encoding = PM_ENCODING_UTF_8_ENTRY;
23436 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
23443 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
23460 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
23461 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
23463 if (length > 2 && parser->current.end[0] ==
'#' && parser->current.end[1] ==
'!') {
23464 const char *engine;
23466 if ((engine = pm_strnstr((
const char *) parser->start,
"ruby", length)) != NULL) {
23467 if (newline != NULL) {
23468 parser->encoding_comment_start = newline + 1;
23470 if (options == NULL || options->main_script) {
23471 pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
23475 if (options != NULL && options->main_script && options->shebang_callback != NULL) {
23476 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->start)));
23479 search_shebang =
false;
23480 }
else if (options != NULL && options->main_script && !parser->parsing_eval) {
23481 search_shebang =
true;
23487 if (search_shebang) {
23490 bool found_shebang =
false;
23494 const uint8_t *cursor = parser->start;
23498 const uint8_t *newline = next_newline(cursor, parser->end - cursor);
23500 while (newline != NULL) {
23501 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
23503 cursor = newline + 1;
23504 newline = next_newline(cursor, parser->end - cursor);
23506 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
23507 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
23508 const char *engine;
23509 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
23510 found_shebang =
true;
23512 if (newline != NULL) {
23513 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
23514 parser->encoding_comment_start = newline + 1;
23517 if (options != NULL && options->shebang_callback != NULL) {
23518 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
23526 if (found_shebang) {
23527 parser->previous = (
pm_token_t) { .
type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23528 parser->current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23530 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
23531 pm_line_offset_list_clear(&parser->line_offsets);
23538 parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
23551 if (parser == NULL) abort();
23553 pm_parser_init(arena, parser, source, size, options);
23562 pm_string_cleanup(&parser->filepath);
23563 pm_arena_cleanup(&parser->metadata_arena);
23565 while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
23566 lex_mode_pop(parser);
23575 pm_parser_cleanup(parser);
23585pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
23587 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
23588 case PM_ERR_BEGIN_UPCASE_BRACE:
23589 case PM_ERR_CLASS_VARIABLE_BARE:
23590 case PM_ERR_END_UPCASE_BRACE:
23591 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
23592 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
23593 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
23594 case PM_ERR_EXPRESSION_NOT_WRITABLE:
23595 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
23596 case PM_ERR_FLOAT_PARSE:
23597 case PM_ERR_GLOBAL_VARIABLE_BARE:
23598 case PM_ERR_HASH_KEY:
23599 case PM_ERR_HEREDOC_IDENTIFIER:
23600 case PM_ERR_INSTANCE_VARIABLE_BARE:
23601 case PM_ERR_INVALID_BLOCK_EXIT:
23602 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
23603 case PM_ERR_INVALID_FLOAT_EXPONENT:
23604 case PM_ERR_INVALID_NUMBER_BINARY:
23605 case PM_ERR_INVALID_NUMBER_DECIMAL:
23606 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
23607 case PM_ERR_INVALID_NUMBER_OCTAL:
23608 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
23609 case PM_ERR_NO_LOCAL_VARIABLE:
23610 case PM_ERR_PARAMETER_ORDER:
23611 case PM_ERR_STATEMENT_UNDEF:
23612 case PM_ERR_VOID_EXPRESSION:
23655 if (parser->error_list.size == 0) {
23656 parser->continuable =
false;
23660 if (!parser->continuable)
return;
23662 size_t source_length = (size_t) (parser->end - parser->start);
23665 bool has_non_stray_error =
false;
23667 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)) {
23668 has_non_stray_error =
true;
23676 size_t non_stray_min_start = SIZE_MAX;
23679 size_t error_start = (size_t) error->location.start;
23680 size_t error_end = error_start + (size_t) error->location.length;
23681 bool at_eof = error_end >= source_length;
23684 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
23685 parser->continuable =
false;
23690 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
23691 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
23692 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
23701 if (non_stray_min_start < error_start)
continue;
23708 if (at_eof && error_start > 0) {
23710 if (error->location.length == 1) {
23711 const uint8_t *
byte = parser->start + error_start;
23712 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
23713 parser->continuable =
false;
23723 if (has_non_stray_error)
continue;
23730 if (error->location.length == 1) {
23731 const uint8_t *
byte = parser->start + error_start;
23732 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
23736 parser->continuable =
false;
23746 pm_node_t *node = parse_program(parser);
23747 pm_parse_continuable(parser);
23748 if (parser->attach_comments) pm_comments_attach(parser, node);
23760 bool eof = pm_source_stream_read(source);
23765 while (!eof && tmp->error_list.size > 0) {
23766 eof = pm_source_stream_read(source);
23769 pm_arena_cleanup(arena);
23771 tmp =
pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
23779#undef PM_CASE_KEYWORD
23780#undef PM_CASE_OPERATOR
23781#undef PM_CASE_WRITABLE
23782#undef PM_STRING_EMPTY
23787#ifndef PRISM_EXCLUDE_SERIALIZATION
23791 pm_buffer_append_string(buffer,
"PRISM", 5);
23795 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23803 pm_serialize_header(buffer);
23804 pm_serialize_content(parser, node, buffer);
23805 pm_buffer_append_byte(buffer,
'\0');
23813pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23815 pm_options_read(&options, data);
23819 pm_parser_init(&arena, &parser, source, size, &options);
23823 pm_serialize_header(buffer);
23824 pm_serialize_content(&parser, node, buffer);
23825 pm_buffer_append_byte(buffer,
'\0');
23827 pm_parser_cleanup(&parser);
23828 pm_arena_cleanup(&arena);
23829 pm_options_cleanup(&options);
23841 pm_options_read(&options, data);
23843 pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
23844 pm_serialize_header(buffer);
23845 pm_serialize_content(parser, node, buffer);
23846 pm_buffer_append_byte(buffer,
'\0');
23849 pm_arena_cleanup(&arena);
23850 pm_options_cleanup(&options);
23864 pm_options_read(&options, data);
23868 pm_parser_init(&arena, &parser, source, size, &options);
23872 int8_t result = -1;
23873 if (parser.error_list.size > 0) {
23874 const char *encoding_name = parser.encoding->name;
23875 pm_buffer_append_string(buffer, encoding_name, strlen(encoding_name));
23876 pm_buffer_append_byte(buffer,
'\0');
23878 result = (int8_t) pm_errors_format(&parser, buffer, format_type);
23881 pm_parser_cleanup(&parser);
23882 pm_arena_cleanup(&arena);
23883 pm_options_cleanup(&options);
23892pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23894 pm_options_read(&options, data);
23898 pm_parser_init(&arena, &parser, source, size, &options);
23901 pm_serialize_header(buffer);
23902 pm_serialize_encoding(parser.encoding, buffer);
23903 pm_buffer_append_varsint(buffer, parser.start_line);
23904 pm_serialize_line_offset_list(&parser.line_offsets, buffer);
23905 pm_serialize_comment_list(&parser.comment_list, buffer);
23907 pm_parser_cleanup(&parser);
23908 pm_arena_cleanup(&arena);
23909 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.
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_NODISCARD PRISM_EXPORTED_FUNCTION 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.
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.
A Ruby keyword, along with the lex state that it transitions to and the token types that it produces.
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.
State for processing named capture groups found during regexp parsing.
bool shared
Whether the content being parsed points into the original source.
pm_constant_id_set_t names
The set of capture names found so far.
pm_call_node_t * call
The call node wrapping the regular expression node (for =~).
pm_match_write_node_t * match
The match write node being built, or NULL if no captures found yet.
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_string_t unescaped
RegularExpressionNode::unescaped.
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.
enum pm_string_t::@118 type
The type of the string.
size_t length
The length of the string in bytes of memory.
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 content_loc
SymbolNode::content_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.