5#include "prism/internal/allocator.h"
6#include "prism/internal/arena.h"
7#include "prism/internal/bit.h"
8#include "prism/internal/buffer.h"
9#include "prism/internal/char.h"
10#include "prism/internal/comments.h"
11#include "prism/internal/constant_pool.h"
12#include "prism/internal/diagnostic.h"
13#include "prism/internal/encoding.h"
14#include "prism/internal/integer.h"
15#include "prism/internal/isinf.h"
16#include "prism/internal/line_offset_list.h"
17#include "prism/internal/list.h"
18#include "prism/internal/magic_comments.h"
19#include "prism/internal/memchr.h"
20#include "prism/internal/node.h"
21#include "prism/internal/options.h"
22#include "prism/internal/parser.h"
23#include "prism/internal/regexp.h"
24#include "prism/internal/serialize.h"
25#include "prism/internal/source.h"
26#include "prism/internal/static_literals.h"
27#include "prism/internal/stringy.h"
28#include "prism/internal/strncasecmp.h"
29#include "prism/internal/strpbrk.h"
30#include "prism/internal/tokens.h"
50#ifndef PRISM_DEPTH_MAXIMUM
51 #define PRISM_DEPTH_MAXIMUM 10000
58#define PM_CONCATENATE(left, right) left ## right
65#if defined(_Static_assert)
66# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message)
68# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
75#if defined(__GNUC__) || defined(__clang__)
77 #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
80 #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
83 #define PRISM_LIKELY(x) (x)
86 #define PRISM_UNLIKELY(x) (x)
101#define PM_TAB_WHITESPACE_SIZE 8
104#define MIN(a,b) (((a)<(b))?(a):(b))
105#define MAX(a,b) (((a)>(b))?(a):(b))
111#define U32(value_) ((uint32_t) (value_))
113#define FL PM_NODE_FLAGS
114#define UP PM_NODE_UPCAST
116#define PM_LOCATION_START(location_) ((location_)->start)
117#define PM_LOCATION_END(location_) ((location_)->start + (location_)->length)
119#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
120#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
121#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
122#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
124#define PM_NODE_START(node_) (UP(node_)->location.start)
125#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
126#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
127#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
129#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
130#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
132#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
133#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
134#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
135#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
136#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
146pm_location_init(uint32_t start, uint32_t length) {
151#define PM_LOCATION_INIT(start_, length_) pm_location_init((start_), (length_))
152#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
153#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
154#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
156#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
157#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
158#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
159#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
161#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
162#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
163#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
174lex_mode_incrementor(
const uint8_t start) {
191lex_mode_terminator(
const uint8_t start) {
213 lex_mode.prev = parser->lex_modes.current;
214 parser->lex_modes.index++;
216 if (parser->lex_modes.index > PM_LEX_STACK_SIZE - 1) {
218 if (parser->lex_modes.current == NULL)
return false;
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];
233lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
234 uint8_t incrementor = lex_mode_incrementor(delimiter);
235 uint8_t terminator = lex_mode_terminator(delimiter);
241 .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 return lex_mode_push(parser, lex_mode);
282 return 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 return 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 return lex_mode_push(parser, lex_mode);
373 return 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
707pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
709 if (scope == NULL)
return false;
712 .previous = parser->current_scope,
714 .parameters = PM_SCOPE_PARAMETERS_NONE,
715 .implicit_parameters = { 0 },
716 .shareable_constant = parser->current_scope == NULL ? PM_SCOPE_SHAREABLE_CONSTANT_NONE : parser->current_scope->shareable_constant,
720 parser->current_scope = scope;
733 if (scope->previous == NULL)
return true;
734 if (scope->closed)
return false;
735 }
while ((scope = scope->previous) != NULL);
737 assert(
false &&
"unreachable");
745pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
748 while (depth-- > 0) {
749 assert(scope != NULL);
750 scope = scope->previous;
757 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
758 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
759 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
760} pm_scope_forwarding_param_check_result_t;
762static pm_scope_forwarding_param_check_result_t
763pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
765 bool conflict =
false;
767 while (scope != NULL) {
768 if (scope->parameters & mask) {
771 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
773 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
780 if (scope->closed)
break;
781 scope = scope->previous;
784 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
789 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
790 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
793 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
794 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
796 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
797 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
804 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
805 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
808 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
809 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
811 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
812 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
819 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
820 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
823 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
828 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
829 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
836 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
837 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
840 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
841 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
843 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
844 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
853pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
854 return parser->current_scope->shareable_constant;
862pm_parser_scope_shareable_constant_set(
pm_parser_t *parser, pm_shareable_constant_value_t shareable_constant) {
866 scope->shareable_constant = shareable_constant;
867 }
while (!scope->closed && (scope = scope->previous) != NULL);
877#define PM_LOCALS_HASH_THRESHOLD 5
881 if (locals->capacity > 0) {
882 xfree_sized(locals->locals, locals->capacity *
sizeof(
pm_local_t));
892 name = ((name >> 16) ^ name) * 0x45d9f3b;
893 name = ((name >> 16) ^ name) * 0x45d9f3b;
894 name = (name >> 16) ^ name;
904 uint32_t next_capacity = locals->capacity == 0 ? 4 : (locals->capacity * 2);
905 assert(next_capacity > locals->capacity);
908 if (next_locals == NULL) abort();
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_locals_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 pm_locals_free(locals);
934 locals->locals = next_locals;
935 locals->capacity = next_capacity;
955 if (locals->size >= (locals->capacity / 4 * 3)) {
956 pm_locals_resize(locals);
959 locals->bloom |= (1u << (name & 31));
961 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
962 for (uint32_t index = 0; index < locals->capacity; index++) {
965 if (local->name == PM_CONSTANT_ID_UNSET) {
968 .location = { .start = start, .length = length },
969 .index = locals->size++,
974 }
else if (local->name == name) {
979 uint32_t mask = locals->capacity - 1;
980 uint32_t hash = pm_locals_hash(name);
981 uint32_t initial_hash = hash;
984 pm_local_t *local = &locals->locals[hash & mask];
986 if (local->name == PM_CONSTANT_ID_UNSET) {
989 .location = { .start = start, .length = length },
990 .index = locals->size++,
995 }
else if (local->name == name) {
1000 }
while ((hash & mask) != initial_hash);
1003 assert(
false &&
"unreachable");
1013 if (!(locals->bloom & (1u << (name & 31))))
return UINT32_MAX;
1015 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
1016 for (uint32_t index = 0; index < locals->size; index++) {
1018 if (local->name == name)
return index;
1021 uint32_t mask = locals->capacity - 1;
1022 uint32_t hash = pm_locals_hash(name);
1023 uint32_t initial_hash = hash & mask;
1026 pm_local_t *local = &locals->locals[hash & mask];
1028 if (local->name == PM_CONSTANT_ID_UNSET) {
1030 }
else if (local->name == name) {
1035 }
while ((hash & mask) != initial_hash);
1047 uint32_t index = pm_locals_find(locals, name);
1048 assert(index != UINT32_MAX);
1051 assert(local->reads < UINT32_MAX);
1062 uint32_t index = pm_locals_find(locals, name);
1063 assert(index != UINT32_MAX);
1066 assert(local->reads > 0);
1076 uint32_t index = pm_locals_find(locals, name);
1077 assert(index != UINT32_MAX);
1079 return locals->locals[index].reads;
1092 pm_constant_id_list_init_capacity(parser->arena, list, locals->size);
1097 uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
1101 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
1103 for (uint32_t index = 0; index < capacity; index++) {
1106 if (local->name != PM_CONSTANT_ID_UNSET) {
1107 pm_constant_id_list_insert(list, (
size_t) local->index, local->name);
1109 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))) {
1110 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->name);
1112 if (constant->length >= 1 && *constant->start !=
'_') {
1113 PM_PARSER_WARN_FORMAT(
1115 local->location.
start,
1117 PM_WARN_UNUSED_LOCAL_VARIABLE,
1118 (
int) constant->length,
1119 (
const char *) constant->start
1135pm_parser_constant_id_raw(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1138 if (start == parser->constant_cache.start && end == parser->constant_cache.end) {
1139 return parser->constant_cache.id;
1142 pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (
size_t) (end - start));
1144 parser->constant_cache.start = start;
1145 parser->constant_cache.end = end;
1146 parser->constant_cache.id = id;
1155pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1156 return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length);
1163pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1164 return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (
const uint8_t *) start, length);
1172 return pm_parser_constant_id_raw(parser, token->start, token->end);
1179#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1180 case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1191 while (node != NULL) {
1192 switch (PM_NODE_TYPE(node)) {
1193 case PM_CASE_VOID_VALUE:
1194 return void_node != NULL ? void_node : node;
1195 case PM_MATCH_PREDICATE_NODE:
1197 case PM_BEGIN_NODE: {
1203 if (vn != NULL)
return vn;
1208 if (vn != NULL)
return vn;
1214 if (cast->
else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1218 if (vn == NULL)
return NULL;
1219 if (void_node == NULL) void_node = vn;
1223 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1227 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1239 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1240 pm_node_t *vn = pm_check_value_expression(parser, node);
1241 if (vn != NULL)
return vn;
1252 case PM_CASE_NODE: {
1254 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1263 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1267 if (vn == NULL)
return NULL;
1268 if (void_node == NULL) void_node = vn;
1271 node = UP(cast->else_clause);
1274 case PM_CASE_MATCH_NODE: {
1276 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1285 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1289 if (vn == NULL)
return NULL;
1290 if (void_node == NULL) void_node = vn;
1293 node = UP(cast->else_clause);
1296 case PM_ENSURE_NODE: {
1301 case PM_PARENTHESES_NODE: {
1303 node = UP(cast->
body);
1306 case PM_STATEMENTS_NODE: {
1310 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1313 switch (PM_NODE_TYPE(body_part)) {
1314 case PM_CASE_VOID_VALUE:
1315 if (void_node == NULL) {
1316 void_node = body_part;
1336 if (void_node == NULL) {
1342 case PM_UNLESS_NODE: {
1351 if (void_node == NULL) {
1357 case PM_ELSE_NODE: {
1370 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1374 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->previous;
1376 pm_locals_read(&scope->locals, cast->
name);
1389 pm_node_t *void_node = pm_check_value_expression(parser, node);
1390 if (void_node != NULL) {
1391 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1400 const char *
type = NULL;
1403 switch (PM_NODE_TYPE(node)) {
1404 case PM_BACK_REFERENCE_READ_NODE:
1405 case PM_CLASS_VARIABLE_READ_NODE:
1406 case PM_GLOBAL_VARIABLE_READ_NODE:
1407 case PM_INSTANCE_VARIABLE_READ_NODE:
1408 case PM_LOCAL_VARIABLE_READ_NODE:
1409 case PM_NUMBERED_REFERENCE_READ_NODE:
1410 type =
"a variable";
1413 case PM_CALL_NODE: {
1417 const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->
name);
1418 switch (message->length) {
1420 switch (message->start[0]) {
1431 type = (
const char *) message->start;
1437 switch (message->start[1]) {
1439 if (message->start[0] ==
'<' || message->start[0] ==
'>' || message->start[0] ==
'!' || message->start[0] ==
'=') {
1440 type = (
const char *) message->start;
1445 if (message->start[0] ==
'+' || message->start[0] ==
'-') {
1446 type = (
const char *) message->start;
1451 if (message->start[0] ==
'*') {
1452 type = (
const char *) message->start;
1459 if (memcmp(message->start,
"<=>", 3) == 0) {
1468 case PM_CONSTANT_PATH_NODE:
1472 case PM_CONSTANT_READ_NODE:
1473 type =
"a constant";
1476 case PM_DEFINED_NODE:
1485 case PM_IMAGINARY_NODE:
1486 case PM_INTEGER_NODE:
1487 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1488 case PM_INTERPOLATED_STRING_NODE:
1489 case PM_RATIONAL_NODE:
1490 case PM_REGULAR_EXPRESSION_NODE:
1491 case PM_SOURCE_ENCODING_NODE:
1492 case PM_SOURCE_FILE_NODE:
1493 case PM_SOURCE_LINE_NODE:
1494 case PM_STRING_NODE:
1495 case PM_SYMBOL_NODE:
1503 case PM_RANGE_NODE: {
1506 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1529 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1540 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1541 for (
size_t index = 0; index < size; index++) {
1542 pm_void_statement_check(parser, node->
body.
nodes[index]);
1552 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1553 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1554 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1555} pm_conditional_predicate_type_t;
1561pm_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) {
1563 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1564 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1566 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1567 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1569 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1579pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1580 switch (PM_NODE_TYPE(node)) {
1581 case PM_ARRAY_NODE: {
1582 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1585 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1586 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1591 case PM_HASH_NODE: {
1592 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1595 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1597 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1600 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1607 case PM_IMAGINARY_NODE:
1608 case PM_INTEGER_NODE:
1610 case PM_RATIONAL_NODE:
1611 case PM_REGULAR_EXPRESSION_NODE:
1612 case PM_SOURCE_ENCODING_NODE:
1613 case PM_SOURCE_FILE_NODE:
1614 case PM_SOURCE_LINE_NODE:
1615 case PM_STRING_NODE:
1616 case PM_SYMBOL_NODE:
1630 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1631 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);
1649 switch (PM_NODE_TYPE(node)) {
1652 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1653 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1658 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1659 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1662 case PM_PARENTHESES_NODE: {
1665 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1667 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1672 case PM_BEGIN_NODE: {
1680 case PM_RANGE_NODE: {
1683 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1684 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1692 node->
type = PM_FLIP_FLOP_NODE;
1696 case PM_REGULAR_EXPRESSION_NODE:
1701 node->
type = PM_MATCH_LAST_LINE_NODE;
1703 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1704 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1708 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1713 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1715 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1716 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1720 case PM_INTEGER_NODE:
1721 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1722 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1723 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1726 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1729 case PM_STRING_NODE:
1730 case PM_SOURCE_FILE_NODE:
1731 case PM_INTERPOLATED_STRING_NODE:
1732 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1734 case PM_SYMBOL_NODE:
1735 case PM_INTERPOLATED_SYMBOL_NODE:
1736 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1738 case PM_SOURCE_LINE_NODE:
1739 case PM_SOURCE_ENCODING_NODE:
1741 case PM_RATIONAL_NODE:
1742 case PM_IMAGINARY_NODE:
1743 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1745 case PM_CLASS_VARIABLE_WRITE_NODE:
1748 case PM_CONSTANT_WRITE_NODE:
1751 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1754 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1757 case PM_LOCAL_VARIABLE_WRITE_NODE:
1760 case PM_MULTI_WRITE_NODE:
1796 if (arguments->
block != NULL) {
1797 uint32_t end = PM_NODE_END(arguments->
block);
1800 uint32_t arguments_end = PM_LOCATION_END(&arguments->
closing_loc);
1801 if (arguments_end > end) {
1844 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1858char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1859 if (n <= 0)
return 0;
1861 if (parser->encoding_changed) {
1864 if ((width = parser->encoding->alpha_char(b, n)) != 0) {
1866 }
else if (*b ==
'_') {
1868 }
else if (*b >= 0x80) {
1869 return parser->encoding->char_width(b, n);
1873 }
else if (*b < 0x80) {
1874 return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b ==
'_');
1876 return pm_encoding_utf_8_char_width(b, n);
1885char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1888 }
else if (*b < 0x80) {
1889 return (*b ==
'_') || (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0);
1891 return pm_encoding_utf_8_char_width(b, n);
1908#if defined(PRISM_HAS_NEON)
1909#include <arm_neon.h>
1912scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1913 const uint8_t *cursor = start;
1920 static const uint8_t low_lut_data[16] = {
1921 0x15, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
1922 0x1F, 0x1F, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0E
1924 static const uint8_t high_lut_data[16] = {
1925 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
1926 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1928 const uint8x16_t low_lut = vld1q_u8(low_lut_data);
1929 const uint8x16_t high_lut = vld1q_u8(high_lut_data);
1930 const uint8x16_t mask_0f = vdupq_n_u8(0x0F);
1932 while (cursor + 16 <= end) {
1933 uint8x16_t v = vld1q_u8(cursor);
1935 uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
1936 uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
1937 uint8x16_t ident = vandq_u8(lo_class, hi_class);
1940 if (vminvq_u8(ident) != 0) {
1946 uint8x16_t is_zero = vceqq_u8(ident, vdupq_n_u8(0));
1947 uint64_t lo = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 0);
1950 cursor += pm_ctzll(lo) / 8;
1952 uint64_t hi = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 1);
1953 cursor += 8 + pm_ctzll(hi) / 8;
1956 return (
size_t) (cursor - start);
1959 return (
size_t) (cursor - start);
1962#elif defined(PRISM_HAS_SSSE3)
1963#include <tmmintrin.h>
1966scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1967 const uint8_t *cursor = start;
1969 while (cursor + 16 <= end) {
1970 __m128i v = _mm_loadu_si128((
const __m128i *) cursor);
1971 __m128i zero = _mm_setzero_si128();
1978 __m128i lowered = _mm_or_si128(v, _mm_set1_epi8(0x20));
1979 __m128i letter = _mm_and_si128(
1980 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x61), lowered), zero),
1981 _mm_cmpeq_epi8(_mm_subs_epu8(lowered, _mm_set1_epi8(0x7A)), zero));
1983 __m128i digit = _mm_and_si128(
1984 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x30), v), zero),
1985 _mm_cmpeq_epi8(_mm_subs_epu8(v, _mm_set1_epi8(0x39)), zero));
1987 __m128i underscore = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5F));
1989 __m128i ident = _mm_or_si128(_mm_or_si128(letter, digit), underscore);
1990 int mask = _mm_movemask_epi8(ident);
1992 if (mask == 0xFFFF) {
1997 cursor += pm_ctzll((uint64_t) (~mask & 0xFFFF));
1998 return (
size_t) (cursor - start);
2001 return (
size_t) (cursor - start);
2008#elif defined(PRISM_HAS_SWAR)
2020scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
2021 static const uint64_t ones = 0x0101010101010101ULL;
2022 static const uint64_t highs = 0x8080808080808080ULL;
2023 const uint8_t *cursor = start;
2025 while (cursor + 8 <= end) {
2027 memcpy(&word, cursor, 8);
2030 if (word & highs)
break;
2032 uint64_t digit = ((word | highs) - ones * 0x30) & ((ones * 0x39 | highs) - word) & highs;
2039 uint64_t lowered = word | (ones * 0x20);
2040 uint64_t letter = ((lowered | highs) - ones * 0x61) & ((ones * 0x7A | highs) - lowered) & highs;
2045 uint64_t xor_us = word ^ (ones * 0x5F);
2046 uint64_t underscore = (xor_us - ones) & ~xor_us & highs;
2048 uint64_t ident = digit | letter | underscore;
2050 if (ident == highs) {
2057 uint64_t not_ident = ~ident & highs;
2058 cursor += pm_ctzll(not_ident) / 8;
2059 return (
size_t) (cursor - start);
2062 return (
size_t) (cursor - start);
2069#define scan_identifier_ascii(start, end) ((size_t) 0)
2079char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
2082 }
else if (parser->encoding_changed) {
2085 if ((width = parser->encoding->alnum_char(b, n)) != 0) {
2087 }
else if (*b ==
'_') {
2089 }
else if (*b >= 0x80) {
2090 return parser->encoding->char_width(b, n);
2095 return char_is_identifier_utf8(b, n);
2102#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
2103#define PUNCT(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) | \
2108 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
2111const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
2116static PRISM_INLINE bool
2117char_is_global_name_punctuation(const uint8_t b) {
2118 const unsigned int i = (const unsigned int) b;
2119 if (i <= 0x20 || 0x7e < i) return false;
2121 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
2124static PRISM_INLINE bool
2125token_is_setter_name(pm_token_t *token) {
2127 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
2128 ((token->type == PM_TOKEN_IDENTIFIER) &&
2129 (token->end - token->start >= 2) &&
2130 (token->end[-1] == '='))
2138pm_local_is_keyword(const char *source, size_t length) {
2139#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
2143 switch (source[0]) {
2144 case 'd': KEYWORD("do"); return false;
2145 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
2146 case 'o': KEYWORD("or"); return false;
2147 default: return false;
2150 switch (source[0]) {
2151 case 'a': KEYWORD("and"); return false;
2152 case 'd': KEYWORD("def"); return false;
2153 case 'e': KEYWORD("end"); return false;
2154 case 'f': KEYWORD("for"); return false;
2155 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
2156 default: return false;
2159 switch (source[0]) {
2160 case 'c': KEYWORD("case"); return false;
2161 case 'e': KEYWORD("else"); return false;
2162 case 'n': KEYWORD("next"); return false;
2163 case 'r': KEYWORD("redo"); return false;
2164 case 's': KEYWORD("self"); return false;
2165 case 't': KEYWORD("then"); KEYWORD("true"); return false;
2166 case 'w': KEYWORD("when"); return false;
2167 default: return false;
2170 switch (source[0]) {
2171 case 'a': KEYWORD("alias"); return false;
2172 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
2173 case 'c': KEYWORD("class"); return false;
2174 case 'e': KEYWORD("elsif"); return false;
2175 case 'f': KEYWORD("false"); return false;
2176 case 'r': KEYWORD("retry"); return false;
2177 case 's': KEYWORD("super"); return false;
2178 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
2179 case 'w': KEYWORD("while"); return false;
2180 case 'y': KEYWORD("yield"); return false;
2181 default: return false;
2184 switch (source[0]) {
2185 case 'e': KEYWORD("ensure"); return false;
2186 case 'm': KEYWORD("module"); return false;
2187 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
2188 case 'u': KEYWORD("unless"); return false;
2189 default: return false;
2192 KEYWORD("__LINE__");
2193 KEYWORD("__FILE__");
2196 KEYWORD("__ENCODING__");
2205/******************************************************************************/
2206/* Node flag handling functions */
2207/******************************************************************************/
2212static PRISM_INLINE void
2213pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
2214 node->flags |= flag;
2220static PRISM_INLINE void
2221pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
2222 node->flags &= (pm_node_flags_t) ~flag;
2228static PRISM_INLINE void
2229pm_node_flag_set_repeated_parameter(pm_node_t *node) {
2230 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
2231 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
2232 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
2233 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
2234 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
2235 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
2236 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
2237 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
2239 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
2242/******************************************************************************/
2243/* Node creation functions */
2244/******************************************************************************/
2251#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)
2256static PRISM_INLINE pm_node_flags_t
2257pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
2258 pm_node_flags_t flags = 0;
2260 if (closing->type == PM_TOKEN_REGEXP_END) {
2261 pm_buffer_t unknown_flags = { 0 };
2263 // The closing delimiter is normally a single byte, so the options
2264 // follow it. A `\r\n` newline delimiter is two bytes, however, so we
2265 // skip past it to avoid misreading the trailing `\n` as an option.
2266 const uint8_t *flag = closing->start + 1;
2267 if ((closing->end - closing->start) >= 2 && closing->start[0] == '\r' && closing->start[1] == '\n') {
2271 for (; flag < closing->end; flag++) {
2273 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
2274 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
2275 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
2276 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
2278 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
2279 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
2280 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
2281 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
2283 default: pm_buffer_append_byte(&unknown_flags, *flag);
2287 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
2288 if (unknown_flags_length != 0) {
2289 const char *word = unknown_flags_length >= 2 ? "options" : "option";
2290 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
2292 pm_buffer_cleanup(&unknown_flags);
2298#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
2300static pm_statements_node_t *
2301pm_statements_node_create(pm_parser_t *parser);
2304pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
2307pm_statements_node_body_length(pm_statements_node_t *node);
2313static PRISM_INLINE void
2314pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
2315 if (integer->values != NULL) {
2316 size_t byte_size = integer->length * sizeof(uint32_t);
2317 uint32_t *old_values = integer->values;
2318 integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
2326static pm_error_recovery_node_t *
2327pm_error_recovery_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
2328 return pm_error_recovery_node_new(
2332 ((pm_location_t) { .start = start, .length = length }),
2340static pm_error_recovery_node_t *
2341pm_error_recovery_node_create_unexpected(pm_parser_t *parser, pm_node_t *unexpected) {
2342 return pm_error_recovery_node_new(
2346 unexpected->location,
2354static pm_alias_global_variable_node_t *
2355pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2356 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2358 return pm_alias_global_variable_node_new(
2362 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2365 TOK2LOC(parser, keyword)
2372static pm_alias_method_node_t *
2373pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2374 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2376 return pm_alias_method_node_new(
2380 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2383 TOK2LOC(parser, keyword)
2390static pm_alternation_pattern_node_t *
2391pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2392 return pm_alternation_pattern_node_new(
2396 PM_LOCATION_INIT_NODES(left, right),
2399 TOK2LOC(parser, operator)
2406static pm_and_node_t *
2407pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2408 pm_assert_value_expression(parser, left);
2410 return pm_and_node_new(
2414 PM_LOCATION_INIT_NODES(left, right),
2417 TOK2LOC(parser, operator)
2424static pm_arguments_node_t *
2425pm_arguments_node_create(pm_parser_t *parser) {
2426 return pm_arguments_node_new(
2430 PM_LOCATION_INIT_UNSET,
2431 ((pm_node_list_t) { 0 })
2439pm_arguments_node_size(pm_arguments_node_t *node) {
2440 return node->arguments.size;
2447pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
2448 if (pm_arguments_node_size(node) == 0) {
2449 PM_NODE_START_SET_NODE(node, argument);
2452 if (PM_NODE_END(node) < PM_NODE_END(argument)) {
2453 PM_NODE_LENGTH_SET_NODE(node, argument);
2456 pm_node_list_append(arena, &node->arguments, argument);
2458 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2459 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2460 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2462 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2470static pm_array_node_t *
2471pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2472 if (opening == NULL) {
2473 return pm_array_node_new(
2476 PM_NODE_FLAG_STATIC_LITERAL,
2477 PM_LOCATION_INIT_UNSET,
2478 ((pm_node_list_t) { 0 }),
2479 ((pm_location_t) { 0 }),
2480 ((pm_location_t) { 0 })
2483 return pm_array_node_new(
2486 PM_NODE_FLAG_STATIC_LITERAL,
2487 PM_LOCATION_INIT_TOKEN(parser, opening),
2488 ((pm_node_list_t) { 0 }),
2489 TOK2LOC(parser, opening),
2490 TOK2LOC(parser, opening)
2498static PRISM_INLINE void
2499pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
2500 if (!node->elements.size && !node->opening_loc.length) {
2501 PM_NODE_START_SET_NODE(node, element);
2504 pm_node_list_append(arena, &node->elements, element);
2505 PM_NODE_LENGTH_SET_NODE(node, element);
2507 // If the element is not a static literal, then the array is not a static
2508 // literal. Turn that flag off.
2509 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)) {
2510 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2513 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2514 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2522pm_array_node_close_set(const pm_parser_t *parser, pm_array_node_t *node, const pm_token_t *closing) {
2523 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == 0);
2524 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2525 node->closing_loc = TOK2LOC(parser, closing);
2532static pm_array_pattern_node_t *
2533pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2534 pm_array_pattern_node_t *node = pm_array_pattern_node_new(
2538 PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2540 ((pm_node_list_t) { 0 }),
2542 ((pm_node_list_t) { 0 }),
2543 ((pm_location_t) { 0 }),
2544 ((pm_location_t) { 0 })
2547 // For now we're going to just copy over each pointer manually. This could be
2548 // much more efficient, as we could instead resize the node list.
2549 bool found_rest = false;
2552 PM_NODE_LIST_FOREACH(nodes, index, child) {
2553 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2556 } else if (found_rest) {
2557 pm_node_list_append(parser->arena, &node->posts, child);
2559 pm_node_list_append(parser->arena, &node->requireds, child);
2569static pm_array_pattern_node_t *
2570pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2571 return pm_array_pattern_node_new(
2575 PM_LOCATION_INIT_NODE(rest),
2577 ((pm_node_list_t) { 0 }),
2579 ((pm_node_list_t) { 0 }),
2580 ((pm_location_t) { 0 }),
2581 ((pm_location_t) { 0 })
2589static pm_array_pattern_node_t *
2590pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2591 return pm_array_pattern_node_new(
2595 PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
2597 ((pm_node_list_t) { 0 }),
2599 ((pm_node_list_t) { 0 }),
2600 TOK2LOC(parser, opening),
2601 TOK2LOC(parser, closing)
2609static pm_array_pattern_node_t *
2610pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2611 return pm_array_pattern_node_new(
2615 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2617 ((pm_node_list_t) { 0 }),
2619 ((pm_node_list_t) { 0 }),
2620 TOK2LOC(parser, opening),
2621 TOK2LOC(parser, closing)
2625static PRISM_INLINE void
2626pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
2627 pm_node_list_append(arena, &node->requireds, inner);
2633static pm_assoc_node_t *
2634pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2637 if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
2638 end = PM_NODE_END(value);
2639 } else if (operator != NULL) {
2640 end = PM_TOKEN_END(parser, operator);
2642 end = PM_NODE_END(key);
2645 // Hash string keys will be frozen, so we can mark them as frozen here so
2646 // that the compiler picks them up and also when we check for static literal
2647 // on the keys it gets factored in.
2648 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2649 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2652 // If the key and value of this assoc node are both static literals, then
2653 // we can mark this node as a static literal.
2654 pm_node_flags_t flags = 0;
2656 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2657 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)
2659 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2662 return pm_assoc_node_new(
2666 ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
2669 NTOK2LOC(parser, operator)
2676static pm_assoc_splat_node_t *
2677pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2678 assert(operator->type == PM_TOKEN_USTAR_STAR);
2680 return pm_assoc_splat_node_new(
2684 (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
2686 TOK2LOC(parser, operator)
2693static pm_back_reference_read_node_t *
2694pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2695 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2697 return pm_back_reference_read_node_new(
2701 PM_LOCATION_INIT_TOKEN(parser, name),
2702 pm_parser_constant_id_token(parser, name)
2709static pm_begin_node_t *
2710pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2711 uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
2712 uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
2714 return pm_begin_node_new(
2718 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2719 NTOK2LOC(parser, begin_keyword),
2724 ((pm_location_t) { 0 })
2732pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2733 if (node->begin_keyword_loc.length == 0) {
2734 PM_NODE_START_SET_NODE(node, rescue_clause);
2736 PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
2737 node->rescue_clause = rescue_clause;
2744pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2745 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2746 PM_NODE_START_SET_NODE(node, else_clause);
2748 PM_NODE_LENGTH_SET_NODE(node, else_clause);
2749 node->else_clause = else_clause;
2756pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2757 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2758 PM_NODE_START_SET_NODE(node, ensure_clause);
2760 PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
2761 node->ensure_clause = ensure_clause;
2768pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
2769 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
2770 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
2771 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
2777static pm_block_argument_node_t *
2778pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2779 assert(operator->type == PM_TOKEN_UAMPERSAND);
2781 return pm_block_argument_node_new(
2785 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
2787 TOK2LOC(parser, operator)
2794static pm_block_node_t *
2795pm_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) {
2796 return pm_block_node_new(
2800 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2804 TOK2LOC(parser, opening),
2805 TOK2LOC(parser, closing)
2812static pm_block_parameter_node_t *
2813pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2814 assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2816 return pm_block_parameter_node_new(
2820 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
2821 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
2822 NTOK2LOC(parser, name),
2823 TOK2LOC(parser, operator)
2830static pm_block_parameters_node_t *
2831pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2833 if (opening != NULL) {
2834 start = PM_TOKEN_START(parser, opening);
2835 } else if (parameters != NULL) {
2836 start = PM_NODE_START(parameters);
2842 if (parameters != NULL) {
2843 end = PM_NODE_END(parameters);
2844 } else if (opening != NULL) {
2845 end = PM_TOKEN_END(parser, opening);
2850 return pm_block_parameters_node_new(
2854 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2856 ((pm_node_list_t) { 0 }),
2857 NTOK2LOC(parser, opening),
2858 ((pm_location_t) { 0 })
2866pm_block_parameters_node_closing_set(const pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_token_t *closing) {
2867 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == 0);
2868 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2869 node->closing_loc = TOK2LOC(parser, closing);
2875static pm_block_local_variable_node_t *
2876pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2877 return pm_block_local_variable_node_new(
2881 PM_LOCATION_INIT_TOKEN(parser, name),
2882 pm_parser_constant_id_token(parser, name)
2890pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2891 pm_node_list_append(arena, &node->locals, UP(local));
2893 if (PM_NODE_LENGTH(node) == 0) {
2894 PM_NODE_START_SET_NODE(node, local);
2897 PM_NODE_LENGTH_SET_NODE(node, local);
2903static pm_break_node_t *
2904pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2905 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2907 return pm_break_node_new(
2911 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
2913 TOK2LOC(parser, keyword)
2917// There are certain flags that we want to use internally but don't want to
2918// expose because they are not relevant beyond parsing. Therefore we'll define
2919// them here and not define them in config.yml/a header file.
2920static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2922static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2923static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2924static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2931static pm_call_node_t *
2932pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2933 return pm_call_node_new(
2937 PM_LOCATION_INIT_UNSET,
2939 ((pm_location_t) { 0 }),
2941 ((pm_location_t) { 0 }),
2942 ((pm_location_t) { 0 }),
2944 ((pm_location_t) { 0 }),
2945 ((pm_location_t) { 0 }),
2954static PRISM_INLINE pm_node_flags_t
2955pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2956 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2963static pm_call_node_t *
2964pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2965 pm_assert_value_expression(parser, receiver);
2967 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2968 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2969 flags |= PM_CALL_NODE_FLAGS_INDEX;
2972 pm_call_node_t *node = pm_call_node_create(parser, flags);
2974 PM_NODE_START_SET_NODE(node, receiver);
2976 const pm_location_t *end = pm_arguments_end(arguments);
2977 assert(end != NULL && "unreachable");
2978 PM_NODE_LENGTH_SET_LOCATION(node, end);
2980 node->receiver = receiver;
2981 node->message_loc.start = arguments->opening_loc.start;
2982 node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
2984 node->opening_loc = arguments->opening_loc;
2985 node->arguments = arguments->arguments;
2986 node->closing_loc = arguments->closing_loc;
2987 node->block = arguments->block;
2989 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2996static pm_call_node_t *
2997pm_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) {
2998 pm_assert_value_expression(parser, receiver);
2999 pm_assert_value_expression(parser, argument);
3001 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
3003 PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
3004 PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
3006 node->receiver = receiver;
3007 node->message_loc = TOK2LOC(parser, operator);
3009 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
3010 pm_arguments_node_arguments_append(parser->arena, arguments, argument);
3011 node->arguments = arguments;
3013 node->name = pm_parser_constant_id_token(parser, operator);
3017static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
3022static pm_call_node_t *
3023pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
3024 pm_assert_value_expression(parser, receiver);
3026 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3028 PM_NODE_START_SET_NODE(node, receiver);
3029 const pm_location_t *end = pm_arguments_end(arguments);
3031 PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
3033 PM_NODE_LENGTH_SET_LOCATION(node, end);
3036 node->receiver = receiver;
3037 node->call_operator_loc = TOK2LOC(parser, operator);
3038 node->message_loc = TOK2LOC(parser, message);
3039 node->opening_loc = arguments->opening_loc;
3040 node->arguments = arguments->arguments;
3041 node->closing_loc = arguments->closing_loc;
3042 node->block = arguments->block;
3044 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3045 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3052 node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
3059static pm_call_node_t *
3060pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
3061 pm_call_node_t *node = pm_call_node_create(parser, 0);
3062 node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
3064 node->receiver = receiver;
3065 node->arguments = arguments;
3067 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
3075static pm_call_node_t *
3076pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
3077 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3079 PM_NODE_START_SET_TOKEN(parser, node, message);
3080 const pm_location_t *end = pm_arguments_end(arguments);
3081 assert(end != NULL && "unreachable");
3082 PM_NODE_LENGTH_SET_LOCATION(node, end);
3084 node->message_loc = TOK2LOC(parser, message);
3085 node->opening_loc = arguments->opening_loc;
3086 node->arguments = arguments->arguments;
3087 node->closing_loc = arguments->closing_loc;
3088 node->block = arguments->block;
3090 node->name = pm_parser_constant_id_token(parser, message);
3098static pm_call_node_t *
3099pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
3100 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3102 node->base.location = (pm_location_t) { 0 };
3103 node->arguments = arguments;
3112static pm_call_node_t *
3113pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
3114 pm_assert_value_expression(parser, receiver);
3115 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
3117 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
3119 PM_NODE_START_SET_TOKEN(parser, node, message);
3120 if (arguments->closing_loc.length > 0) {
3121 PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
3123 assert(receiver != NULL);
3124 PM_NODE_LENGTH_SET_NODE(node, receiver);
3127 node->receiver = receiver;
3128 node->message_loc = TOK2LOC(parser, message);
3129 node->opening_loc = arguments->opening_loc;
3130 node->arguments = arguments->arguments;
3131 node->closing_loc = arguments->closing_loc;
3133 node->name = pm_parser_constant_id_constant(parser, "!", 1);
3140static pm_call_node_t *
3141pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
3142 pm_assert_value_expression(parser, receiver);
3144 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3146 PM_NODE_START_SET_NODE(node, receiver);
3147 const pm_location_t *end = pm_arguments_end(arguments);
3148 assert(end != NULL && "unreachable");
3149 PM_NODE_LENGTH_SET_LOCATION(node, end);
3151 node->receiver = receiver;
3152 node->call_operator_loc = TOK2LOC(parser, operator);
3153 node->opening_loc = arguments->opening_loc;
3154 node->arguments = arguments->arguments;
3155 node->closing_loc = arguments->closing_loc;
3156 node->block = arguments->block;
3158 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3159 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3162 node->name = pm_parser_constant_id_constant(parser, "call", 4);
3169static pm_call_node_t *
3170pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
3171 pm_assert_value_expression(parser, receiver);
3173 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3175 PM_NODE_START_SET_TOKEN(parser, node, operator);
3176 PM_NODE_LENGTH_SET_NODE(node, receiver);
3178 node->receiver = receiver;
3179 node->message_loc = TOK2LOC(parser, operator);
3181 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
3189static pm_call_node_t *
3190pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
3191 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3193 node->base.location = TOK2LOC(parser, message);
3194 node->message_loc = TOK2LOC(parser, message);
3196 node->name = pm_parser_constant_id_token(parser, message);
3204static PRISM_INLINE bool
3205pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
3207 (node->message_loc.length > 0) &&
3208 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
3209 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
3210 char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
3211 (node->opening_loc.length == 0) &&
3212 (node->arguments == NULL) &&
3213 (node->block == NULL)
3221pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
3222 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
3224 if (write_constant->length > 0) {
3225 size_t length = write_constant->length - 1;
3227 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
3228 memcpy(memory, write_constant->start, length);
3230 *read_name = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, memory, length);
3232 // We can get here if the message was missing because of a syntax error.
3233 *read_name = pm_parser_constant_id_constant(parser, "", 0);
3240static pm_call_and_write_node_t *
3241pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3242 assert(target->block == NULL);
3243 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3245 pm_call_and_write_node_t *node = pm_call_and_write_node_new(
3249 PM_LOCATION_INIT_NODES(target, value),
3251 target->call_operator_loc,
3252 target->message_loc,
3255 TOK2LOC(parser, operator),
3259 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3261 // The target is no longer necessary because we've reused its children.
3262 // It is arena-allocated so no explicit free is needed.
3272pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
3273 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
3274 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
3276 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
3277 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
3278 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
3284 if (block != NULL) {
3285 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
3293static pm_index_and_write_node_t *
3294pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3295 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3297 pm_index_arguments_check(parser, target->arguments, target->block);
3299 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3301 pm_index_and_write_node_t *node = pm_index_and_write_node_new(
3305 PM_LOCATION_INIT_NODES(target, value),
3307 target->call_operator_loc,
3308 target->opening_loc,
3310 target->closing_loc,
3311 (pm_block_argument_node_t *) target->block,
3312 TOK2LOC(parser, operator),
3316 // The target is no longer necessary because we've reused its children.
3317 // It is arena-allocated so no explicit free is needed.
3325static pm_call_operator_write_node_t *
3326pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3327 assert(target->block == NULL);
3329 pm_call_operator_write_node_t *node = pm_call_operator_write_node_new(
3333 PM_LOCATION_INIT_NODES(target, value),
3335 target->call_operator_loc,
3336 target->message_loc,
3339 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3340 TOK2LOC(parser, operator),
3344 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3346 // The target is no longer necessary because we've reused its children.
3347 // It is arena-allocated so no explicit free is needed.
3355static pm_index_operator_write_node_t *
3356pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3357 pm_index_arguments_check(parser, target->arguments, target->block);
3359 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3361 pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
3365 PM_LOCATION_INIT_NODES(target, value),
3367 target->call_operator_loc,
3368 target->opening_loc,
3370 target->closing_loc,
3371 (pm_block_argument_node_t *) target->block,
3372 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3373 TOK2LOC(parser, operator),
3377 // The target is no longer necessary because we've reused its children.
3378 // It is arena-allocated so no explicit free is needed.
3386static pm_call_or_write_node_t *
3387pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3388 assert(target->block == NULL);
3389 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3391 pm_call_or_write_node_t *node = pm_call_or_write_node_new(
3395 PM_LOCATION_INIT_NODES(target, value),
3397 target->call_operator_loc,
3398 target->message_loc,
3401 TOK2LOC(parser, operator),
3405 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3407 // The target is no longer necessary because we've reused its children.
3408 // It is arena-allocated so no explicit free is needed.
3416static pm_index_or_write_node_t *
3417pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3418 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3420 pm_index_arguments_check(parser, target->arguments, target->block);
3422 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3424 pm_index_or_write_node_t *node = pm_index_or_write_node_new(
3428 PM_LOCATION_INIT_NODES(target, value),
3430 target->call_operator_loc,
3431 target->opening_loc,
3433 target->closing_loc,
3434 (pm_block_argument_node_t *) target->block,
3435 TOK2LOC(parser, operator),
3439 // The target is no longer necessary because we've reused its children.
3440 // It is arena-allocated so no explicit free is needed.
3449static pm_call_target_node_t *
3450pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3451 pm_call_target_node_t *node = pm_call_target_node_new(
3455 PM_LOCATION_INIT_NODE(target),
3457 target->call_operator_loc,
3462 /* It is possible to get here where we have parsed an invalid syntax tree
3463 * where the call operator was not present. In that case we will have a
3464 * problem because it is a required location. In this case we need to fill
3465 * it in with a fake location so that the syntax tree remains valid. */
3466 if (node->call_operator_loc.length == 0) {
3467 node->call_operator_loc = target->base.location;
3470 // The target is no longer necessary because we've reused its children.
3471 // It is arena-allocated so no explicit free is needed.
3480static pm_index_target_node_t *
3481pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3482 pm_index_arguments_check(parser, target->arguments, target->block);
3483 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3485 pm_index_target_node_t *node = pm_index_target_node_new(
3488 FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3489 PM_LOCATION_INIT_NODE(target),
3491 target->opening_loc,
3493 target->closing_loc,
3494 (pm_block_argument_node_t *) target->block
3497 // The target is no longer necessary because we've reused its children.
3498 // It is arena-allocated so no explicit free is needed.
3506static pm_capture_pattern_node_t *
3507pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3508 return pm_capture_pattern_node_new(
3512 PM_LOCATION_INIT_NODES(value, target),
3515 TOK2LOC(parser, operator)
3522static pm_case_node_t *
3523pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3524 return pm_case_node_new(
3528 PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
3530 ((pm_node_list_t) { 0 }),
3532 TOK2LOC(parser, case_keyword),
3533 NTOK2LOC(parser, end_keyword)
3541pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
3542 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3544 pm_node_list_append(arena, &node->conditions, condition);
3545 PM_NODE_LENGTH_SET_NODE(node, condition);
3552pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3553 node->else_clause = else_clause;
3554 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3561pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
3562 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3563 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3569static pm_case_match_node_t *
3570pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
3571 return pm_case_match_node_new(
3575 PM_LOCATION_INIT_TOKEN(parser, case_keyword),
3577 ((pm_node_list_t) { 0 }),
3579 TOK2LOC(parser, case_keyword),
3580 ((pm_location_t) { 0 })
3588pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
3589 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3591 pm_node_list_append(arena, &node->conditions, condition);
3592 PM_NODE_LENGTH_SET_NODE(node, condition);
3599pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3600 node->else_clause = else_clause;
3601 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3608pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3609 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3610 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3616static pm_class_node_t *
3617pm_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) {
3618 return pm_class_node_new(
3622 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
3624 TOK2LOC(parser, class_keyword),
3626 NTOK2LOC(parser, inheritance_operator),
3629 TOK2LOC(parser, end_keyword),
3630 pm_parser_constant_id_token(parser, name)
3637static pm_class_variable_and_write_node_t *
3638pm_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) {
3639 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3641 return pm_class_variable_and_write_node_new(
3645 PM_LOCATION_INIT_NODES(target, value),
3647 target->base.location,
3648 TOK2LOC(parser, operator),
3656static pm_class_variable_operator_write_node_t *
3657pm_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) {
3658 return pm_class_variable_operator_write_node_new(
3662 PM_LOCATION_INIT_NODES(target, value),
3664 target->base.location,
3665 TOK2LOC(parser, operator),
3667 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3674static pm_class_variable_or_write_node_t *
3675pm_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) {
3676 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3678 return pm_class_variable_or_write_node_new(
3682 PM_LOCATION_INIT_NODES(target, value),
3684 target->base.location,
3685 TOK2LOC(parser, operator),
3693static pm_class_variable_read_node_t *
3694pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3695 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3697 return pm_class_variable_read_node_new(
3701 PM_LOCATION_INIT_TOKEN(parser, token),
3702 pm_parser_constant_id_token(parser, token)
3712static PRISM_INLINE pm_node_flags_t
3713pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3714 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
3723static pm_class_variable_write_node_t *
3724pm_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) {
3725 return pm_class_variable_write_node_new(
3728 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3729 PM_LOCATION_INIT_NODES(read_node, value),
3731 read_node->base.location,
3733 TOK2LOC(parser, operator)
3740static pm_constant_path_and_write_node_t *
3741pm_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) {
3742 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3744 return pm_constant_path_and_write_node_new(
3748 PM_LOCATION_INIT_NODES(target, value),
3750 TOK2LOC(parser, operator),
3758static pm_constant_path_operator_write_node_t *
3759pm_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) {
3760 return pm_constant_path_operator_write_node_new(
3764 PM_LOCATION_INIT_NODES(target, value),
3766 TOK2LOC(parser, operator),
3768 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3775static pm_constant_path_or_write_node_t *
3776pm_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) {
3777 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3779 return pm_constant_path_or_write_node_new(
3783 PM_LOCATION_INIT_NODES(target, value),
3785 TOK2LOC(parser, operator),
3793static pm_constant_path_node_t *
3794pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3795 pm_assert_value_expression(parser, parent);
3797 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3798 if (name_token->type == PM_TOKEN_CONSTANT) {
3799 name = pm_parser_constant_id_token(parser, name_token);
3802 return pm_constant_path_node_new(
3806 (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
3809 TOK2LOC(parser, delimiter),
3810 TOK2LOC(parser, name_token)
3817static pm_constant_path_write_node_t *
3818pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3819 return pm_constant_path_write_node_new(
3822 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3823 PM_LOCATION_INIT_NODES(target, value),
3825 TOK2LOC(parser, operator),
3833static pm_constant_and_write_node_t *
3834pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3835 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3837 return pm_constant_and_write_node_new(
3841 PM_LOCATION_INIT_NODES(target, value),
3843 target->base.location,
3844 TOK2LOC(parser, operator),
3852static pm_constant_operator_write_node_t *
3853pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3854 return pm_constant_operator_write_node_new(
3858 PM_LOCATION_INIT_NODES(target, value),
3860 target->base.location,
3861 TOK2LOC(parser, operator),
3863 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3870static pm_constant_or_write_node_t *
3871pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3872 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3874 return pm_constant_or_write_node_new(
3878 PM_LOCATION_INIT_NODES(target, value),
3880 target->base.location,
3881 TOK2LOC(parser, operator),
3889static pm_constant_read_node_t *
3890pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3891 assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
3893 return pm_constant_read_node_new(
3897 PM_LOCATION_INIT_TOKEN(parser, name),
3898 pm_parser_constant_id_token(parser, name)
3905static pm_constant_write_node_t *
3906pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3907 return pm_constant_write_node_new(
3910 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3911 PM_LOCATION_INIT_NODES(target, value),
3913 target->base.location,
3915 TOK2LOC(parser, operator)
3923pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3924 switch (PM_NODE_TYPE(node)) {
3925 case PM_BEGIN_NODE: {
3926 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3927 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3930 case PM_PARENTHESES_NODE: {
3931 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3932 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3935 case PM_STATEMENTS_NODE: {
3936 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3937 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3942 case PM_IMAGINARY_NODE:
3943 case PM_INTEGER_NODE:
3944 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3945 case PM_INTERPOLATED_STRING_NODE:
3946 case PM_INTERPOLATED_SYMBOL_NODE:
3947 case PM_INTERPOLATED_X_STRING_NODE:
3948 case PM_RATIONAL_NODE:
3949 case PM_REGULAR_EXPRESSION_NODE:
3950 case PM_SOURCE_ENCODING_NODE:
3951 case PM_SOURCE_FILE_NODE:
3952 case PM_SOURCE_LINE_NODE:
3953 case PM_STRING_NODE:
3954 case PM_SYMBOL_NODE:
3955 case PM_X_STRING_NODE:
3956 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3966static pm_def_node_t *
3968 pm_parser_t *parser,
3969 pm_constant_id_t name,
3970 const pm_token_t *name_loc,
3971 pm_node_t *receiver,
3972 pm_parameters_node_t *parameters,
3974 pm_constant_id_list_t *locals,
3975 const pm_token_t *def_keyword,
3976 const pm_token_t *operator,
3977 const pm_token_t *lparen,
3978 const pm_token_t *rparen,
3979 const pm_token_t *equal,
3980 const pm_token_t *end_keyword
3982 if (receiver != NULL) {
3983 pm_def_node_receiver_check(parser, receiver);
3986 return pm_def_node_new(
3990 (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
3992 TOK2LOC(parser, name_loc),
3997 TOK2LOC(parser, def_keyword),
3998 NTOK2LOC(parser, operator),
3999 NTOK2LOC(parser, lparen),
4000 NTOK2LOC(parser, rparen),
4001 NTOK2LOC(parser, equal),
4002 NTOK2LOC(parser, end_keyword)
4009static pm_defined_node_t *
4010pm_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) {
4011 return pm_defined_node_new(
4015 (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
4016 NTOK2LOC(parser, lparen),
4018 NTOK2LOC(parser, rparen),
4019 TOK2LOC(parser, keyword)
4026static pm_else_node_t *
4027pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4028 return pm_else_node_new(
4032 ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
4033 TOK2LOC(parser, else_keyword),
4035 NTOK2LOC(parser, end_keyword)
4042static pm_embedded_statements_node_t *
4043pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
4044 return pm_embedded_statements_node_new(
4048 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4049 TOK2LOC(parser, opening),
4051 TOK2LOC(parser, closing)
4058static pm_embedded_variable_node_t *
4059pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
4060 return pm_embedded_variable_node_new(
4064 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
4065 TOK2LOC(parser, operator),
4073static pm_ensure_node_t *
4074pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4075 return pm_ensure_node_new(
4079 PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
4080 TOK2LOC(parser, ensure_keyword),
4082 TOK2LOC(parser, end_keyword)
4089static pm_false_node_t *
4090pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4091 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4093 return pm_false_node_new(
4096 PM_NODE_FLAG_STATIC_LITERAL,
4097 PM_LOCATION_INIT_TOKEN(parser, token)
4105static pm_find_pattern_node_t *
4106pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4107 assert(nodes->size >= 2);
4108 pm_node_t *left = nodes->nodes[0];
4109 pm_node_t *right = nodes->nodes[nodes->size - 1];
4111 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4112 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4114 pm_find_pattern_node_t *node = pm_find_pattern_node_new(
4118 PM_LOCATION_INIT_NODES(left, right),
4120 (pm_splat_node_t *) left,
4121 ((pm_node_list_t) { 0 }),
4122 (pm_splat_node_t *) right,
4123 ((pm_location_t) { 0 }),
4124 ((pm_location_t) { 0 })
4127 // For now we're going to just copy over each pointer manually. This could be
4128 // much more efficient, as we could instead resize the node list to only point
4130 for (size_t index = 1; index < nodes->size - 1; index++) {
4131 pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
4142pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4143 ptrdiff_t diff = token->end - token->start;
4144 if (diff <= 0) return 0.0;
4146 // First, get a buffer of the content.
4147 size_t length = (size_t) diff;
4148 const size_t buffer_size = sizeof(char) * (length + 1);
4149 char *buffer = xmalloc(buffer_size);
4150 memcpy((void *) buffer, token->start, length);
4152 // Next, determine if we need to replace the decimal point because of
4153 // locale-specific options, and then normalize them if we have to.
4154 char decimal_point = *localeconv()->decimal_point;
4155 if (decimal_point != '.') {
4156 for (size_t index = 0; index < length; index++) {
4157 if (buffer[index] == '.') buffer[index] = decimal_point;
4161 // Next, handle underscores by removing them from the buffer.
4162 for (size_t index = 0; index < length; index++) {
4163 if (buffer[index] == '_') {
4164 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4169 // Null-terminate the buffer so that strtod cannot read off the end.
4170 buffer[length] = '\0';
4172 // Now, call strtod to parse the value. Note that CRuby has their own
4173 // version of strtod which avoids locales. We're okay using the locale-aware
4174 // version because we've already validated through the parser that the token
4175 // is in a valid format.
4178 double value = strtod(buffer, &eptr);
4180 // This should never happen, because we've already checked that the token
4181 // is in a valid format. However it's good to be safe.
4182 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4183 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
4184 xfree_sized(buffer, buffer_size);
4188 // If errno is set, then it should only be ERANGE. At this point we need to
4189 // check if it's infinity (it should be).
4190 if (errno == ERANGE && PRISM_ISINF(value)) {
4192 const char *ellipsis;
4198 warn_width = (int) length;
4202 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);
4203 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4206 // Finally we can free the buffer and return the value.
4207 xfree_sized(buffer, buffer_size);
4214static pm_float_node_t *
4215pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4216 assert(token->type == PM_TOKEN_FLOAT);
4218 return pm_float_node_new(
4221 PM_NODE_FLAG_STATIC_LITERAL,
4222 PM_LOCATION_INIT_TOKEN(parser, token),
4223 pm_double_parse(parser, token)
4230static pm_imaginary_node_t *
4231pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4232 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4234 return pm_imaginary_node_new(
4237 PM_NODE_FLAG_STATIC_LITERAL,
4238 PM_LOCATION_INIT_TOKEN(parser, token),
4239 UP(pm_float_node_create(parser, &((pm_token_t) {
4240 .type = PM_TOKEN_FLOAT,
4241 .start = token->start,
4242 .end = token->end - 1
4250static pm_rational_node_t *
4251pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4252 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4254 pm_rational_node_t *node = pm_rational_node_new(
4257 PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4258 PM_LOCATION_INIT_TOKEN(parser, token),
4259 ((pm_integer_t) { 0 }),
4260 ((pm_integer_t) { 0 })
4263 const uint8_t *start = token->start;
4264 const uint8_t *end = token->end - 1; // r
4266 while (start < end && *start == '0') start++; // 0.1 -> .1
4267 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4269 size_t length = (size_t) (end - start);
4271 node->denominator.value = 1;
4275 const uint8_t *point = memchr(start, '.', length);
4276 assert(point && "should have a decimal point");
4278 uint8_t *digits = xmalloc(length);
4279 if (digits == NULL) {
4280 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4284 memcpy(digits, start, (unsigned long) (point - start));
4285 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4286 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4288 size_t fract_length = 0;
4289 for (const uint8_t *fract = point; fract < end; ++fract) {
4290 if (*fract != '_') ++fract_length;
4293 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
4294 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
4295 xfree_sized(digits, length);
4297 pm_integers_reduce(&node->numerator, &node->denominator);
4298 pm_integer_arena_move(parser->arena, &node->numerator);
4299 pm_integer_arena_move(parser->arena, &node->denominator);
4307static pm_imaginary_node_t *
4308pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4309 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4311 return pm_imaginary_node_new(
4314 PM_NODE_FLAG_STATIC_LITERAL,
4315 PM_LOCATION_INIT_TOKEN(parser, token),
4316 UP(pm_float_node_rational_create(parser, &((pm_token_t) {
4317 .type = PM_TOKEN_FLOAT_RATIONAL,
4318 .start = token->start,
4319 .end = token->end - 1
4327static pm_for_node_t *
4329 pm_parser_t *parser,
4331 pm_node_t *collection,
4332 pm_statements_node_t *statements,
4333 const pm_token_t *for_keyword,
4334 const pm_token_t *in_keyword,
4335 const pm_token_t *do_keyword,
4336 const pm_token_t *end_keyword
4338 return pm_for_node_new(
4342 PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
4346 TOK2LOC(parser, for_keyword),
4347 TOK2LOC(parser, in_keyword),
4348 NTOK2LOC(parser, do_keyword),
4349 TOK2LOC(parser, end_keyword)
4356static pm_forwarding_arguments_node_t *
4357pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4358 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4360 return pm_forwarding_arguments_node_new(
4364 PM_LOCATION_INIT_TOKEN(parser, token)
4371static pm_forwarding_parameter_node_t *
4372pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4373 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4375 return pm_forwarding_parameter_node_new(
4379 PM_LOCATION_INIT_TOKEN(parser, token)
4386static pm_forwarding_super_node_t *
4387pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4388 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4389 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4391 pm_block_node_t *block = NULL;
4392 if (arguments->block != NULL) {
4393 block = (pm_block_node_t *) arguments->block;
4396 return pm_forwarding_super_node_new(
4400 (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
4401 PM_LOCATION_INIT_TOKEN(parser, token),
4410static pm_hash_pattern_node_t *
4411pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4412 return pm_hash_pattern_node_new(
4416 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4418 ((pm_node_list_t) { 0 }),
4420 TOK2LOC(parser, opening),
4421 TOK2LOC(parser, closing)
4428static pm_hash_pattern_node_t *
4429pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4433 if (elements->size > 0) {
4435 start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
4436 end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
4438 start = PM_NODE_START(elements->nodes[0]);
4439 end = PM_NODE_END(elements->nodes[elements->size - 1]);
4442 assert(rest != NULL);
4443 start = PM_NODE_START(rest);
4444 end = PM_NODE_END(rest);
4447 pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
4451 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4453 ((pm_node_list_t) { 0 }),
4455 ((pm_location_t) { 0 }),
4456 ((pm_location_t) { 0 })
4459 pm_node_list_concat(parser->arena, &node->elements, elements);
4466static pm_constant_id_t
4467pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4468 switch (PM_NODE_TYPE(target)) {
4469 case PM_GLOBAL_VARIABLE_READ_NODE:
4470 return ((pm_global_variable_read_node_t *) target)->name;
4471 case PM_BACK_REFERENCE_READ_NODE:
4472 return ((pm_back_reference_read_node_t *) target)->name;
4473 case PM_NUMBERED_REFERENCE_READ_NODE:
4474 // This will only ever happen in the event of a syntax error, but we
4475 // still need to provide something for the node.
4476 return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
4478 assert(false && "unreachable");
4479 return (pm_constant_id_t) -1;
4486static pm_global_variable_and_write_node_t *
4487pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4488 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4490 return pm_global_variable_and_write_node_new(
4494 PM_LOCATION_INIT_NODES(target, value),
4495 pm_global_variable_write_name(parser, target),
4497 TOK2LOC(parser, operator),
4505static pm_global_variable_operator_write_node_t *
4506pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4507 return pm_global_variable_operator_write_node_new(
4511 PM_LOCATION_INIT_NODES(target, value),
4512 pm_global_variable_write_name(parser, target),
4514 TOK2LOC(parser, operator),
4516 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4523static pm_global_variable_or_write_node_t *
4524pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4525 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4527 return pm_global_variable_or_write_node_new(
4531 PM_LOCATION_INIT_NODES(target, value),
4532 pm_global_variable_write_name(parser, target),
4534 TOK2LOC(parser, operator),
4542static pm_global_variable_read_node_t *
4543pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4544 return pm_global_variable_read_node_new(
4548 PM_LOCATION_INIT_TOKEN(parser, name),
4549 pm_parser_constant_id_token(parser, name)
4556static pm_global_variable_read_node_t *
4557pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4558 return pm_global_variable_read_node_new(
4562 PM_LOCATION_INIT_UNSET,
4570static pm_global_variable_write_node_t *
4571pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4572 return pm_global_variable_write_node_new(
4575 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4576 PM_LOCATION_INIT_NODES(target, value),
4577 pm_global_variable_write_name(parser, target),
4580 TOK2LOC(parser, operator)
4587static pm_global_variable_write_node_t *
4588pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4589 return pm_global_variable_write_node_new(
4593 PM_LOCATION_INIT_UNSET,
4595 ((pm_location_t) { 0 }),
4597 ((pm_location_t) { 0 })
4604static pm_hash_node_t *
4605pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4606 assert(opening != NULL);
4608 return pm_hash_node_new(
4611 PM_NODE_FLAG_STATIC_LITERAL,
4612 PM_LOCATION_INIT_TOKEN(parser, opening),
4613 TOK2LOC(parser, opening),
4614 ((pm_node_list_t) { 0 }),
4615 ((pm_location_t) { 0 })
4622static PRISM_INLINE void
4623pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
4624 pm_node_list_append(arena, &hash->elements, element);
4626 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4627 if (static_literal) {
4628 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4629 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);
4630 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4631 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4634 if (!static_literal) {
4635 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4639static PRISM_INLINE void
4640pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
4641 PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
4642 hash->closing_loc = TOK2LOC(parser, token);
4648static pm_if_node_t *
4649pm_if_node_create(pm_parser_t *parser,
4650 const pm_token_t *if_keyword,
4651 pm_node_t *predicate,
4652 const pm_token_t *then_keyword,
4653 pm_statements_node_t *statements,
4654 pm_node_t *subsequent,
4655 const pm_token_t *end_keyword
4657 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4659 uint32_t start = PM_TOKEN_START(parser, if_keyword);
4662 if (end_keyword != NULL) {
4663 end = PM_TOKEN_END(parser, end_keyword);
4664 } else if (subsequent != NULL) {
4665 end = PM_NODE_END(subsequent);
4666 } else if (pm_statements_node_body_length(statements) != 0) {
4667 end = PM_NODE_END(statements);
4669 end = PM_NODE_END(predicate);
4672 return pm_if_node_new(
4675 PM_NODE_FLAG_NEWLINE,
4676 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4677 TOK2LOC(parser, if_keyword),
4679 NTOK2LOC(parser, then_keyword),
4682 NTOK2LOC(parser, end_keyword)
4689static pm_if_node_t *
4690pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4691 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4693 pm_statements_node_t *statements = pm_statements_node_create(parser);
4694 pm_statements_node_body_append(parser, statements, statement, true);
4696 return pm_if_node_new(
4699 PM_NODE_FLAG_NEWLINE,
4700 PM_LOCATION_INIT_NODES(statement, predicate),
4701 TOK2LOC(parser, if_keyword),
4703 ((pm_location_t) { 0 }),
4706 ((pm_location_t) { 0 })
4713static pm_if_node_t *
4714pm_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) {
4715 pm_assert_value_expression(parser, predicate);
4716 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4718 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4719 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4721 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4722 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4724 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
4725 return pm_if_node_new(
4728 PM_NODE_FLAG_NEWLINE,
4729 PM_LOCATION_INIT_NODES(predicate, false_expression),
4730 ((pm_location_t) { 0 }),
4732 TOK2LOC(parser, qmark),
4735 ((pm_location_t) { 0 })
4739static PRISM_INLINE void
4740pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
4741 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4742 node->end_keyword_loc = TOK2LOC(parser, keyword);
4745static PRISM_INLINE void
4746pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
4747 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4748 node->end_keyword_loc = TOK2LOC(parser, keyword);
4754static pm_implicit_node_t *
4755pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4756 return pm_implicit_node_new(
4760 PM_LOCATION_INIT_NODE(value),
4768static pm_implicit_rest_node_t *
4769pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4770 assert(token->type == PM_TOKEN_COMMA);
4772 return pm_implicit_rest_node_new(
4776 PM_LOCATION_INIT_TOKEN(parser, token)
4783static pm_integer_node_t *
4784pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4785 assert(token->type == PM_TOKEN_INTEGER);
4787 pm_integer_node_t *node = pm_integer_node_new(
4790 base | PM_NODE_FLAG_STATIC_LITERAL,
4791 PM_LOCATION_INIT_TOKEN(parser, token),
4792 ((pm_integer_t) { 0 })
4795 if (parser->integer.lexed) {
4796 // The value was already computed during lexing.
4797 node->value.value = parser->integer.value;
4798 parser->integer.lexed = false;
4800 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4802 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4803 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4804 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4805 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4806 default: assert(false && "unreachable"); break;
4809 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4810 pm_integer_arena_move(parser->arena, &node->value);
4820static pm_imaginary_node_t *
4821pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4822 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4824 return pm_imaginary_node_new(
4827 PM_NODE_FLAG_STATIC_LITERAL,
4828 PM_LOCATION_INIT_TOKEN(parser, token),
4829 UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4830 .type = PM_TOKEN_INTEGER,
4831 .start = token->start,
4832 .end = token->end - 1
4841static pm_rational_node_t *
4842pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4843 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4845 pm_rational_node_t *node = pm_rational_node_new(
4848 base | PM_NODE_FLAG_STATIC_LITERAL,
4849 PM_LOCATION_INIT_TOKEN(parser, token),
4850 ((pm_integer_t) { 0 }),
4851 ((pm_integer_t) { .value = 1 })
4854 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4856 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4857 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4858 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4859 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4860 default: assert(false && "unreachable"); break;
4863 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4864 pm_integer_arena_move(parser->arena, &node->numerator);
4873static pm_imaginary_node_t *
4874pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4875 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4877 return pm_imaginary_node_new(
4880 PM_NODE_FLAG_STATIC_LITERAL,
4881 PM_LOCATION_INIT_TOKEN(parser, token),
4882 UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4883 .type = PM_TOKEN_INTEGER_RATIONAL,
4884 .start = token->start,
4885 .end = token->end - 1
4893static pm_in_node_t *
4894pm_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) {
4895 uint32_t start = PM_TOKEN_START(parser, in_keyword);
4898 if (statements != NULL) {
4899 end = PM_NODE_END(statements);
4900 } else if (then_keyword != NULL) {
4901 end = PM_TOKEN_END(parser, then_keyword);
4903 end = PM_NODE_END(pattern);
4906 return pm_in_node_new(
4910 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4913 TOK2LOC(parser, in_keyword),
4914 NTOK2LOC(parser, then_keyword)
4921static pm_instance_variable_and_write_node_t *
4922pm_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) {
4923 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4925 return pm_instance_variable_and_write_node_new(
4929 PM_LOCATION_INIT_NODES(target, value),
4931 target->base.location,
4932 TOK2LOC(parser, operator),
4940static pm_instance_variable_operator_write_node_t *
4941pm_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) {
4942 return pm_instance_variable_operator_write_node_new(
4946 PM_LOCATION_INIT_NODES(target, value),
4948 target->base.location,
4949 TOK2LOC(parser, operator),
4951 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4958static pm_instance_variable_or_write_node_t *
4959pm_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) {
4960 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4962 return pm_instance_variable_or_write_node_new(
4966 PM_LOCATION_INIT_NODES(target, value),
4968 target->base.location,
4969 TOK2LOC(parser, operator),
4977static pm_instance_variable_read_node_t *
4978pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4979 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4981 return pm_instance_variable_read_node_new(
4985 PM_LOCATION_INIT_TOKEN(parser, token),
4986 pm_parser_constant_id_token(parser, token)
4994static pm_instance_variable_write_node_t *
4995pm_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) {
4996 return pm_instance_variable_write_node_new(
4999 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5000 PM_LOCATION_INIT_NODES(read_node, value),
5002 read_node->base.location,
5004 TOK2LOC(parser, operator)
5014pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5015 switch (PM_NODE_TYPE(part)) {
5016 case PM_STRING_NODE:
5017 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5019 case PM_EMBEDDED_STATEMENTS_NODE: {
5020 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5021 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5023 if (embedded == NULL) {
5024 // If there are no statements or more than one statement, then
5025 // we lose the static literal flag.
5026 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5027 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5028 // If the embedded statement is a string, then we can keep the
5029 // static literal flag and mark the string as frozen.
5030 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5031 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5032 // If the embedded statement is an interpolated string and it's
5033 // a static literal, then we can keep the static literal flag.
5035 // Otherwise we lose the static literal flag.
5036 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5041 case PM_EMBEDDED_VARIABLE_NODE:
5042 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5045 assert(false && "unexpected node type");
5049 pm_node_list_append(arena, parts, part);
5055static pm_interpolated_regular_expression_node_t *
5056pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5057 return pm_interpolated_regular_expression_node_new(
5060 PM_NODE_FLAG_STATIC_LITERAL,
5061 PM_LOCATION_INIT_TOKEN(parser, opening),
5062 TOK2LOC(parser, opening),
5063 ((pm_node_list_t) { 0 }),
5064 TOK2LOC(parser, opening)
5068static PRISM_INLINE void
5069pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5070 if (PM_NODE_START(node) > PM_NODE_START(part)) {
5071 PM_NODE_START_SET_NODE(node, part);
5073 if (PM_NODE_END(node) < PM_NODE_END(part)) {
5074 PM_NODE_LENGTH_SET_NODE(node, part);
5077 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5080static PRISM_INLINE void
5081pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5082 node->closing_loc = TOK2LOC(parser, closing);
5083 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5084 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
5110static PRISM_INLINE void
5111pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
5112 pm_arena_t *arena = parser->arena;
5113#define CLEAR_FLAGS(node) \
5114 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))
5116#define MUTABLE_FLAGS(node) \
5117 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5119 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5120 PM_NODE_START_SET_NODE(node, part);
5123 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5124 PM_NODE_LENGTH_SET_NODE(node, part);
5127 switch (PM_NODE_TYPE(part)) {
5128 case PM_STRING_NODE:
5129 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5130 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5131 // as long as this interpolation only consists of other string literals.
5132 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5133 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5135 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5137 case PM_INTERPOLATED_STRING_NODE:
5138 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5139 // If the string that we're concatenating is a static literal,
5140 // then we can keep the static literal flag for this string.
5142 // Otherwise, we lose the static literal flag here and we should
5143 // also clear the mutability flags.
5147 case PM_EMBEDDED_STATEMENTS_NODE: {
5148 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5149 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5151 if (embedded == NULL) {
5152 // If we're embedding multiple statements or no statements, then
5153 // the string is not longer a static literal.
5155 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5156 // If the embedded statement is a string, then we can make that
5157 // string as frozen and static literal, and not touch the static
5158 // literal status of this string.
5159 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5161 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5162 MUTABLE_FLAGS(node);
5164 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5165 // If the embedded statement is an interpolated string, but that
5166 // string is marked as static literal, then we can keep our
5167 // static literal status for this string.
5168 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5169 MUTABLE_FLAGS(node);
5172 // In all other cases, we lose the static literal flag here and
5179 case PM_EMBEDDED_VARIABLE_NODE:
5180 // Embedded variables clear static literal, which means we also
5181 // should clear the mutability flags.
5184 case PM_X_STRING_NODE:
5185 case PM_INTERPOLATED_X_STRING_NODE:
5186 case PM_SYMBOL_NODE:
5187 case PM_INTERPOLATED_SYMBOL_NODE:
5188 // These will only happen in error cases. But we want to handle it
5189 // here so that we don't fail the assertion.
5191 pm_node_list_append(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
5193 case PM_ERROR_RECOVERY_NODE:
5197 assert(false && "unexpected node type");
5201 pm_node_list_append(arena, &node->parts, part);
5210static pm_interpolated_string_node_t *
5211pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5212 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5214 switch (parser->frozen_string_literal) {
5215 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5216 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5218 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5219 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5223 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5224 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5226 pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
5230 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5231 NTOK2LOC(parser, opening),
5232 ((pm_node_list_t) { 0 }),
5233 NTOK2LOC(parser, closing)
5236 if (parts != NULL) {
5238 PM_NODE_LIST_FOREACH(parts, index, part) {
5239 pm_interpolated_string_node_append(parser, node, part);
5250pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5251 node->closing_loc = TOK2LOC(parser, closing);
5252 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5256pm_interpolated_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5257 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5258 PM_NODE_START_SET_NODE(node, part);
5261 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5263 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5264 PM_NODE_LENGTH_SET_NODE(node, part);
5269pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5270 node->closing_loc = TOK2LOC(parser, closing);
5271 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5277static pm_interpolated_symbol_node_t *
5278pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5279 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5280 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5282 pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
5285 PM_NODE_FLAG_STATIC_LITERAL,
5286 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5287 NTOK2LOC(parser, opening),
5288 ((pm_node_list_t) { 0 }),
5289 NTOK2LOC(parser, closing)
5292 if (parts != NULL) {
5294 PM_NODE_LIST_FOREACH(parts, index, part) {
5295 pm_interpolated_symbol_node_append(parser->arena, node, part);
5305static pm_interpolated_x_string_node_t *
5306pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5307 return pm_interpolated_x_string_node_new(
5311 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5312 TOK2LOC(parser, opening),
5313 ((pm_node_list_t) { 0 }),
5314 TOK2LOC(parser, closing)
5318static PRISM_INLINE void
5319pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5320 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5321 PM_NODE_LENGTH_SET_NODE(node, part);
5324static PRISM_INLINE void
5325pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5326 node->closing_loc = TOK2LOC(parser, closing);
5327 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5333static pm_it_local_variable_read_node_t *
5334pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5335 return pm_it_local_variable_read_node_new(
5339 PM_LOCATION_INIT_TOKEN(parser, name)
5346static pm_it_parameters_node_t *
5347pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5348 return pm_it_parameters_node_new(
5352 PM_LOCATION_INIT_TOKENS(parser, opening, closing)
5359static pm_keyword_hash_node_t *
5360pm_keyword_hash_node_create(pm_parser_t *parser) {
5361 return pm_keyword_hash_node_new(
5364 PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5365 PM_LOCATION_INIT_UNSET,
5366 ((pm_node_list_t) { 0 })
5374pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *hash, pm_node_t *element) {
5375 // If the element being added is not an AssocNode or does not have a symbol
5376 // key, then we want to turn the SYMBOL_KEYS flag off.
5377 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5378 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5381 pm_node_list_append(arena, &hash->elements, element);
5382 if (PM_NODE_LENGTH(hash) == 0) {
5383 PM_NODE_START_SET_NODE(hash, element);
5385 PM_NODE_LENGTH_SET_NODE(hash, element);
5391static pm_required_keyword_parameter_node_t *
5392pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5393 return pm_required_keyword_parameter_node_new(
5397 PM_LOCATION_INIT_TOKEN(parser, name),
5398 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5399 TOK2LOC(parser, name)
5406static pm_optional_keyword_parameter_node_t *
5407pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5408 return pm_optional_keyword_parameter_node_new(
5412 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5413 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5414 TOK2LOC(parser, name),
5422static pm_keyword_rest_parameter_node_t *
5423pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5424 return pm_keyword_rest_parameter_node_new(
5428 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
5429 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
5430 NTOK2LOC(parser, name),
5431 TOK2LOC(parser, operator)
5438static pm_lambda_node_t *
5439pm_lambda_node_create(
5440 pm_parser_t *parser,
5441 pm_constant_id_list_t *locals,
5442 const pm_token_t *operator,
5443 const pm_token_t *opening,
5444 const pm_token_t *closing,
5445 pm_node_t *parameters,
5448 return pm_lambda_node_new(
5452 PM_LOCATION_INIT_TOKENS(parser, operator, closing),
5454 TOK2LOC(parser, operator),
5455 TOK2LOC(parser, opening),
5456 TOK2LOC(parser, closing),
5465static pm_local_variable_and_write_node_t *
5466pm_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) {
5467 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));
5468 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5470 return pm_local_variable_and_write_node_new(
5474 PM_LOCATION_INIT_NODES(target, value),
5476 TOK2LOC(parser, operator),
5486static pm_local_variable_operator_write_node_t *
5487pm_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) {
5488 return pm_local_variable_operator_write_node_new(
5492 PM_LOCATION_INIT_NODES(target, value),
5494 TOK2LOC(parser, operator),
5497 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
5505static pm_local_variable_or_write_node_t *
5506pm_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) {
5507 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));
5508 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5510 return pm_local_variable_or_write_node_new(
5514 PM_LOCATION_INIT_NODES(target, value),
5516 TOK2LOC(parser, operator),
5526static pm_local_variable_read_node_t *
5527pm_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) {
5528 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5530 return pm_local_variable_read_node_new(
5534 PM_LOCATION_INIT_TOKEN(parser, name),
5543static pm_local_variable_read_node_t *
5544pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5545 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5546 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5553static pm_local_variable_read_node_t *
5554pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5555 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5556 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5562static pm_local_variable_write_node_t *
5563pm_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) {
5564 return pm_local_variable_write_node_new(
5567 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5568 ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
5573 TOK2LOC(parser, operator)
5580static PRISM_INLINE bool
5581pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5582 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5589static PRISM_INLINE bool
5590pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
5593 (parser->start[start] == '_') &&
5594 (parser->start[start + 1] != '0') &&
5595 pm_char_is_decimal_digit(parser->start[start + 1])
5603static PRISM_INLINE void
5604pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
5605 if (pm_token_is_numbered_parameter(parser, start, length)) {
5606 PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
5614static pm_local_variable_target_node_t *
5615pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5616 pm_refute_numbered_parameter(parser, location->start, location->length);
5618 return pm_local_variable_target_node_new(
5622 ((pm_location_t) { .start = location->start, .length = location->length }),
5631static pm_match_predicate_node_t *
5632pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5633 pm_assert_value_expression(parser, value);
5635 return pm_match_predicate_node_new(
5639 PM_LOCATION_INIT_NODES(value, pattern),
5642 TOK2LOC(parser, operator)
5649static pm_match_required_node_t *
5650pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5651 pm_assert_value_expression(parser, value);
5653 return pm_match_required_node_new(
5657 PM_LOCATION_INIT_NODES(value, pattern),
5660 TOK2LOC(parser, operator)
5667static pm_match_write_node_t *
5668pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5669 return pm_match_write_node_new(
5673 PM_LOCATION_INIT_NODE(call),
5675 ((pm_node_list_t) { 0 })
5682static pm_module_node_t *
5683pm_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) {
5684 pm_constant_id_list_t module_locals = { .ids = NULL, .size = 0, .capacity = 0 };
5685 if (locals != NULL) module_locals = *locals;
5687 return pm_module_node_new(
5691 PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
5693 TOK2LOC(parser, module_keyword),
5696 TOK2LOC(parser, end_keyword),
5697 pm_parser_constant_id_token(parser, name)
5704static pm_multi_target_node_t *
5705pm_multi_target_node_create(pm_parser_t *parser) {
5706 return pm_multi_target_node_new(
5710 PM_LOCATION_INIT_UNSET,
5711 ((pm_node_list_t) { 0 }),
5713 ((pm_node_list_t) { 0 }),
5714 ((pm_location_t) { 0 }),
5715 ((pm_location_t) { 0 })
5723pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5724 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5725 if (node->rest == NULL) {
5726 node->rest = target;
5728 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5729 pm_node_list_append(parser->arena, &node->rights, target);
5731 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5732 if (node->rest == NULL) {
5733 node->rest = target;
5735 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5736 pm_node_list_append(parser->arena, &node->rights, target);
5738 } else if (node->rest == NULL) {
5739 pm_node_list_append(parser->arena, &node->lefts, target);
5741 pm_node_list_append(parser->arena, &node->rights, target);
5744 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
5745 PM_NODE_START_SET_NODE(node, target);
5748 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
5749 PM_NODE_LENGTH_SET_NODE(node, target);
5757pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
5758 PM_NODE_START_SET_TOKEN(parser, node, lparen);
5759 PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
5760 node->lparen_loc = TOK2LOC(parser, lparen);
5767pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
5768 PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
5769 node->rparen_loc = TOK2LOC(parser, rparen);
5775static pm_multi_write_node_t *
5776pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5777 /* The target is no longer necessary because we have reused its children. It
5778 * is arena-allocated so no explicit free is needed. */
5779 return pm_multi_write_node_new(
5782 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5783 PM_LOCATION_INIT_NODES(target, value),
5789 TOK2LOC(parser, operator),
5797static pm_next_node_t *
5798pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5799 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5801 return pm_next_node_new(
5805 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
5807 TOK2LOC(parser, keyword)
5814static pm_nil_node_t *
5815pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5816 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5818 return pm_nil_node_new(
5821 PM_NODE_FLAG_STATIC_LITERAL,
5822 PM_LOCATION_INIT_TOKEN(parser, token)
5829static pm_no_block_parameter_node_t *
5830pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5831 assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5832 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5834 return pm_no_block_parameter_node_new(
5838 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5839 TOK2LOC(parser, operator),
5840 TOK2LOC(parser, keyword)
5847static pm_no_keywords_parameter_node_t *
5848pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5849 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5850 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5852 return pm_no_keywords_parameter_node_new(
5856 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5857 TOK2LOC(parser, operator),
5858 TOK2LOC(parser, keyword)
5865static pm_numbered_parameters_node_t *
5866pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
5867 return pm_numbered_parameters_node_new(
5871 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5880#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5889pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5890 const uint8_t *start = token->start + 1;
5891 const uint8_t *end = token->end;
5893 ptrdiff_t diff = end - start;
5895#if PTRDIFF_MAX > SIZE_MAX
5896 assert(diff < (ptrdiff_t) SIZE_MAX);
5898 size_t length = (size_t) diff;
5900 char *digits = xcalloc(length + 1, sizeof(char));
5901 memcpy(digits, start, length);
5902 digits[length] = '\0';
5906 unsigned long value = strtoul(digits, &endptr, 10);
5908 if ((digits == endptr) || (*endptr != '\0')) {
5909 pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
5913 xfree_sized(digits, sizeof(char) * (length + 1));
5915 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5916 PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5920 return (uint32_t) value;
5928static pm_numbered_reference_read_node_t *
5929pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5930 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5932 return pm_numbered_reference_read_node_new(
5936 PM_LOCATION_INIT_TOKEN(parser, name),
5937 pm_numbered_reference_read_node_number(parser, name)
5944static pm_optional_parameter_node_t *
5945pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5946 return pm_optional_parameter_node_new(
5950 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5951 pm_parser_constant_id_token(parser, name),
5952 TOK2LOC(parser, name),
5953 TOK2LOC(parser, operator),
5961static pm_or_node_t *
5962pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5963 pm_assert_value_expression(parser, left);
5965 return pm_or_node_new(
5969 PM_LOCATION_INIT_NODES(left, right),
5972 TOK2LOC(parser, operator)
5979static pm_parameters_node_t *
5980pm_parameters_node_create(pm_parser_t *parser) {
5981 return pm_parameters_node_new(
5985 PM_LOCATION_INIT_UNSET,
5986 ((pm_node_list_t) { 0 }),
5987 ((pm_node_list_t) { 0 }),
5989 ((pm_node_list_t) { 0 }),
5990 ((pm_node_list_t) { 0 }),
6000pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
6001 if ((params->base.location.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
6002 PM_NODE_START_SET_NODE(params, param);
6005 if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
6006 PM_NODE_LENGTH_SET_NODE(params, param);
6014pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6015 pm_parameters_node_location_set(params, param);
6016 pm_node_list_append(arena, ¶ms->requireds, param);
6023pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6024 pm_parameters_node_location_set(params, UP(param));
6025 pm_node_list_append(arena, ¶ms->optionals, UP(param));
6032pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6033 pm_parameters_node_location_set(params, param);
6034 pm_node_list_append(arena, ¶ms->posts, param);
6041pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6042 pm_parameters_node_location_set(params, param);
6043 params->rest = param;
6050pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6051 pm_parameters_node_location_set(params, param);
6052 pm_node_list_append(arena, ¶ms->keywords, param);
6059pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6060 assert(params->keyword_rest == NULL);
6061 pm_parameters_node_location_set(params, param);
6062 params->keyword_rest = param;
6069pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
6070 assert(params->block == NULL);
6071 pm_parameters_node_location_set(params, param);
6072 params->block = param;
6078static pm_program_node_t *
6079pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6080 return pm_program_node_new(
6084 PM_LOCATION_INIT_NODE(statements),
6093static pm_parentheses_node_t *
6094pm_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) {
6095 return pm_parentheses_node_new(
6099 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6101 TOK2LOC(parser, opening),
6102 TOK2LOC(parser, closing)
6109static pm_pinned_expression_node_t *
6110pm_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) {
6111 return pm_pinned_expression_node_new(
6115 PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
6117 TOK2LOC(parser, operator),
6118 TOK2LOC(parser, lparen),
6119 TOK2LOC(parser, rparen)
6126static pm_pinned_variable_node_t *
6127pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6128 return pm_pinned_variable_node_new(
6132 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
6134 TOK2LOC(parser, operator)
6141static pm_post_execution_node_t *
6142pm_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) {
6143 return pm_post_execution_node_new(
6147 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6149 TOK2LOC(parser, keyword),
6150 TOK2LOC(parser, opening),
6151 TOK2LOC(parser, closing)
6158static pm_pre_execution_node_t *
6159pm_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) {
6160 return pm_pre_execution_node_new(
6164 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6166 TOK2LOC(parser, keyword),
6167 TOK2LOC(parser, opening),
6168 TOK2LOC(parser, closing)
6175static pm_range_node_t *
6176pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6177 pm_assert_value_expression(parser, left);
6178 pm_assert_value_expression(parser, right);
6179 pm_node_flags_t flags = 0;
6181 // Indicate that this node is an exclusive range if the operator is `...`.
6182 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6183 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6186 // Indicate that this node is a static literal (i.e., can be compiled with
6187 // a putobject in CRuby) if the left and right are implicit nil, explicit
6188 // nil, or integers.
6190 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6191 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6193 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6196 uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
6197 uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
6199 return pm_range_node_new(
6203 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6206 TOK2LOC(parser, operator)
6213static pm_redo_node_t *
6214pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6215 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6217 return pm_redo_node_new(
6221 PM_LOCATION_INIT_TOKEN(parser, token)
6229static pm_regular_expression_node_t *
6230pm_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) {
6231 return pm_regular_expression_node_new(
6234 pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6235 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6236 TOK2LOC(parser, opening),
6237 TOK2LOC(parser, content),
6238 TOK2LOC(parser, closing),
6246static PRISM_INLINE pm_regular_expression_node_t *
6247pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6248 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6254static pm_required_parameter_node_t *
6255pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6256 return pm_required_parameter_node_new(
6260 PM_LOCATION_INIT_TOKEN(parser, token),
6261 pm_parser_constant_id_token(parser, token)
6268static pm_rescue_modifier_node_t *
6269pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6270 return pm_rescue_modifier_node_new(
6274 PM_LOCATION_INIT_NODES(expression, rescue_expression),
6276 TOK2LOC(parser, keyword),
6284static pm_rescue_node_t *
6285pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6286 return pm_rescue_node_new(
6290 PM_LOCATION_INIT_TOKEN(parser, keyword),
6291 TOK2LOC(parser, keyword),
6292 ((pm_node_list_t) { 0 }),
6293 ((pm_location_t) { 0 }),
6295 ((pm_location_t) { 0 }),
6301static PRISM_INLINE void
6302pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
6303 node->operator_loc = TOK2LOC(parser, operator);
6310pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6311 node->reference = reference;
6312 PM_NODE_LENGTH_SET_NODE(node, reference);
6319pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6320 node->statements = statements;
6321 if (pm_statements_node_body_length(statements) > 0) {
6322 PM_NODE_LENGTH_SET_NODE(node, statements);
6330pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6331 node->subsequent = subsequent;
6332 PM_NODE_LENGTH_SET_NODE(node, subsequent);
6339pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
6340 pm_node_list_append(arena, &node->exceptions, exception);
6341 PM_NODE_LENGTH_SET_NODE(node, exception);
6347static pm_rest_parameter_node_t *
6348pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6349 return pm_rest_parameter_node_new(
6353 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
6354 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
6355 NTOK2LOC(parser, name),
6356 TOK2LOC(parser, operator)
6363static pm_retry_node_t *
6364pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6365 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6367 return pm_retry_node_new(
6371 PM_LOCATION_INIT_TOKEN(parser, token)
6378static pm_return_node_t *
6379pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6380 return pm_return_node_new(
6384 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
6385 TOK2LOC(parser, keyword),
6393static pm_self_node_t *
6394pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6395 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6397 return pm_self_node_new(
6401 PM_LOCATION_INIT_TOKEN(parser, token)
6408static pm_shareable_constant_node_t *
6409pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6410 return pm_shareable_constant_node_new(
6413 (pm_node_flags_t) value,
6414 PM_LOCATION_INIT_NODE(write),
6422static pm_singleton_class_node_t *
6423pm_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) {
6424 return pm_singleton_class_node_new(
6428 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
6430 TOK2LOC(parser, class_keyword),
6431 TOK2LOC(parser, operator),
6434 TOK2LOC(parser, end_keyword)
6441static pm_source_encoding_node_t *
6442pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6443 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6445 return pm_source_encoding_node_new(
6448 PM_NODE_FLAG_STATIC_LITERAL,
6449 PM_LOCATION_INIT_TOKEN(parser, token)
6456static pm_source_file_node_t*
6457pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6458 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6460 pm_node_flags_t flags = 0;
6462 switch (parser->frozen_string_literal) {
6463 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6464 flags |= PM_STRING_FLAGS_MUTABLE;
6466 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6467 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6471 return pm_source_file_node_new(
6475 PM_LOCATION_INIT_TOKEN(parser, file_keyword),
6483static pm_source_line_node_t *
6484pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6485 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6487 return pm_source_line_node_new(
6490 PM_NODE_FLAG_STATIC_LITERAL,
6491 PM_LOCATION_INIT_TOKEN(parser, token)
6498static pm_splat_node_t *
6499pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6500 return pm_splat_node_new(
6504 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
6505 TOK2LOC(parser, operator),
6513static pm_statements_node_t *
6514pm_statements_node_create(pm_parser_t *parser) {
6515 return pm_statements_node_new(
6519 PM_LOCATION_INIT_UNSET,
6520 ((pm_node_list_t) { 0 })
6528pm_statements_node_body_length(pm_statements_node_t *node) {
6529 return node && node->body.size;
6536static PRISM_INLINE void
6537pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6538 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6539 PM_NODE_START_SET_NODE(node, statement);
6542 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6543 PM_NODE_LENGTH_SET_NODE(node, statement);
6551pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6552 pm_statements_node_body_update(node, statement);
6554 if (node->body.size > 0) {
6555 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6557 switch (PM_NODE_TYPE(previous)) {
6562 case PM_RETURN_NODE:
6563 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6570 pm_node_list_append(parser->arena, &node->body, statement);
6571 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6578pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
6579 pm_statements_node_body_update(node, statement);
6580 pm_node_list_prepend(arena, &node->body, statement);
6581 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6587static PRISM_INLINE pm_string_node_t *
6588pm_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) {
6589 pm_node_flags_t flags = 0;
6591 switch (parser->frozen_string_literal) {
6592 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6593 flags = PM_STRING_FLAGS_MUTABLE;
6595 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6596 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6600 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6601 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6603 return pm_string_node_new(
6607 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6608 NTOK2LOC(parser, opening),
6609 TOK2LOC(parser, content),
6610 NTOK2LOC(parser, closing),
6618static pm_string_node_t *
6619pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6620 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6627static pm_string_node_t *
6628pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6629 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6630 parser->current_string = PM_STRING_EMPTY;
6637static pm_super_node_t *
6638pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6639 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6641 const pm_location_t *end = pm_arguments_end(arguments);
6642 assert(end != NULL && "unreachable");
6644 return pm_super_node_new(
6648 ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
6649 TOK2LOC(parser, keyword),
6650 arguments->opening_loc,
6651 arguments->arguments,
6652 arguments->closing_loc,
6662pm_ascii_only_p(const pm_string_t *contents) {
6663 const size_t length = pm_string_length(contents);
6664 const uint8_t *source = pm_string_source(contents);
6666 for (size_t index = 0; index < length; index++) {
6667 if (source[index] & 0x80) return false;
6677parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6678 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6679 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6682 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6695parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6696 const pm_encoding_t *encoding = parser->encoding;
6698 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6699 size_t width = encoding->char_width(cursor, end - cursor);
6702 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6719static PRISM_INLINE pm_node_flags_t
6720parse_symbol_encoding(pm_parser_t *parser, const pm_encoding_t *explicit_encoding, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6721 if (explicit_encoding != NULL) {
6722 // A Symbol may optionally have its encoding explicitly set. This will
6723 // happen if an escape sequence results in a non-ASCII code point.
6724 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6725 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6726 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6727 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6728 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6729 } else if (validate) {
6730 parse_symbol_encoding_validate_other(parser, location, contents);
6732 } else if (pm_ascii_only_p(contents)) {
6733 // Ruby stipulates that all source files must use an ASCII-compatible
6734 // encoding. Thus, all symbols appearing in source are eligible for
6735 // "downgrading" to US-ASCII.
6736 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6737 } else if (validate) {
6738 parse_symbol_encoding_validate_other(parser, location, contents);
6748static pm_symbol_node_t *
6749pm_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) {
6750 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6751 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6753 return pm_symbol_node_new(
6756 PM_NODE_FLAG_STATIC_LITERAL | flags,
6757 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6758 NTOK2LOC(parser, opening),
6759 NTOK2LOC(parser, value),
6760 NTOK2LOC(parser, closing),
6768static PRISM_INLINE pm_symbol_node_t *
6769pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6770 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6776static pm_symbol_node_t *
6777pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6778 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));
6779 parser->current_string = PM_STRING_EMPTY;
6786static pm_symbol_node_t *
6787pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6788 assert(token->type == PM_TOKEN_LABEL);
6790 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6791 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6792 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6794 assert((label.end - label.start) >= 0);
6795 pm_string_shared_init(&node->unescaped, label.start, label.end);
6796 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, parser->explicit_encoding, &label, &node->unescaped, false));
6804static pm_symbol_node_t *
6805pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6806 pm_symbol_node_t *node = pm_symbol_node_new(
6809 PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
6810 PM_LOCATION_INIT_UNSET,
6811 ((pm_location_t) { 0 }),
6812 ((pm_location_t) { 0 }),
6813 ((pm_location_t) { 0 }),
6814 ((pm_string_t) { 0 })
6817 pm_string_constant_init(&node->unescaped, content, strlen(content));
6825pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6826 const pm_location_t *location = NULL;
6828 switch (PM_NODE_TYPE(node)) {
6829 case PM_SYMBOL_NODE: {
6830 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6831 if (cast->closing_loc.length > 0) {
6832 location = &cast->closing_loc;
6836 case PM_INTERPOLATED_SYMBOL_NODE: {
6837 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6838 if (cast->closing_loc.length > 0) {
6839 location = &cast->closing_loc;
6847 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6853static pm_symbol_node_t *
6854pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6855 pm_symbol_node_t *new_node = pm_symbol_node_new(
6858 PM_NODE_FLAG_STATIC_LITERAL,
6859 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6860 TOK2LOC(parser, opening),
6862 TOK2LOC(parser, closing),
6866 pm_token_t content = {
6867 .type = PM_TOKEN_IDENTIFIER,
6868 .start = parser->start + node->content_loc.start,
6869 .end = parser->start + node->content_loc.start + node->content_loc.length
6872 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, parser->explicit_encoding, &content, &node->unescaped, true));
6874 /* The old node is arena-allocated so no explicit free is needed. */
6881static pm_string_node_t *
6882pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6883 pm_node_flags_t flags = 0;
6885 switch (parser->frozen_string_literal) {
6886 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6887 flags = PM_STRING_FLAGS_MUTABLE;
6889 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6890 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6894 pm_string_node_t *new_node = pm_string_node_new(
6898 PM_LOCATION_INIT_NODE(node),
6905 /* The old node is arena-allocated so no explicit free is needed. */
6912static pm_true_node_t *
6913pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6914 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6916 return pm_true_node_new(
6919 PM_NODE_FLAG_STATIC_LITERAL,
6920 PM_LOCATION_INIT_TOKEN(parser, token)
6927static pm_true_node_t *
6928pm_true_node_synthesized_create(pm_parser_t *parser) {
6929 return pm_true_node_new(
6932 PM_NODE_FLAG_STATIC_LITERAL,
6933 PM_LOCATION_INIT_UNSET
6940static pm_undef_node_t *
6941pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6942 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6944 return pm_undef_node_new(
6948 PM_LOCATION_INIT_TOKEN(parser, token),
6949 ((pm_node_list_t) { 0 }),
6950 TOK2LOC(parser, token)
6958pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6959 PM_NODE_LENGTH_SET_NODE(node, name);
6960 pm_node_list_append(arena, &node->names, name);
6966static pm_unless_node_t *
6967pm_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) {
6968 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6969 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6971 return pm_unless_node_new(
6974 PM_NODE_FLAG_NEWLINE,
6975 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
6976 TOK2LOC(parser, keyword),
6978 NTOK2LOC(parser, then_keyword),
6981 ((pm_location_t) { 0 })
6988static pm_unless_node_t *
6989pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6990 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6992 pm_statements_node_t *statements = pm_statements_node_create(parser);
6993 pm_statements_node_body_append(parser, statements, statement, true);
6995 return pm_unless_node_new(
6998 PM_NODE_FLAG_NEWLINE,
6999 PM_LOCATION_INIT_NODES(statement, predicate),
7000 TOK2LOC(parser, unless_keyword),
7002 ((pm_location_t) { 0 }),
7005 ((pm_location_t) { 0 })
7009static PRISM_INLINE void
7010pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
7011 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
7012 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
7021pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7022 assert(parser->current_block_exits != NULL);
7024 // All of the block exits that we want to remove should be within the
7025 // statements, and since we are modifying the statements, we shouldn't have
7026 // to check the end location.
7027 uint32_t start = statements->base.location.start;
7029 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7030 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7031 if (block_exit->location.start < start) break;
7033 // Implicitly remove from the list by lowering the size.
7034 parser->current_block_exits->size--;
7041static pm_until_node_t *
7042pm_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) {
7043 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7045 return pm_until_node_new(
7049 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7050 TOK2LOC(parser, keyword),
7051 NTOK2LOC(parser, do_keyword),
7052 TOK2LOC(parser, closing),
7061static pm_until_node_t *
7062pm_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) {
7063 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7064 pm_loop_modifier_block_exits(parser, statements);
7066 return pm_until_node_new(
7070 PM_LOCATION_INIT_NODES(statements, predicate),
7071 TOK2LOC(parser, keyword),
7072 ((pm_location_t) { 0 }),
7073 ((pm_location_t) { 0 }),
7082static pm_when_node_t *
7083pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7084 return pm_when_node_new(
7088 PM_LOCATION_INIT_TOKEN(parser, keyword),
7089 TOK2LOC(parser, keyword),
7090 ((pm_node_list_t) { 0 }),
7091 ((pm_location_t) { 0 }),
7100pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
7101 PM_NODE_LENGTH_SET_NODE(node, condition);
7102 pm_node_list_append(arena, &node->conditions, condition);
7108static PRISM_INLINE void
7109pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
7110 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
7111 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
7118pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7119 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
7120 PM_NODE_LENGTH_SET_NODE(node, statements);
7123 node->statements = statements;
7129static pm_while_node_t *
7130pm_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) {
7131 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7133 return pm_while_node_new(
7137 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7138 TOK2LOC(parser, keyword),
7139 NTOK2LOC(parser, do_keyword),
7140 TOK2LOC(parser, closing),
7149static pm_while_node_t *
7150pm_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) {
7151 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7152 pm_loop_modifier_block_exits(parser, statements);
7154 return pm_while_node_new(
7158 PM_LOCATION_INIT_NODES(statements, predicate),
7159 TOK2LOC(parser, keyword),
7160 ((pm_location_t) { 0 }),
7161 ((pm_location_t) { 0 }),
7170static pm_while_node_t *
7171pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7172 return pm_while_node_new(
7176 PM_LOCATION_INIT_UNSET,
7177 ((pm_location_t) { 0 }),
7178 ((pm_location_t) { 0 }),
7179 ((pm_location_t) { 0 }),
7189static pm_x_string_node_t *
7190pm_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) {
7191 return pm_x_string_node_new(
7194 PM_STRING_FLAGS_FROZEN,
7195 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
7196 TOK2LOC(parser, opening),
7197 TOK2LOC(parser, content),
7198 TOK2LOC(parser, closing),
7206static PRISM_INLINE pm_x_string_node_t *
7207pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7208 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7214static pm_yield_node_t *
7215pm_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) {
7216 uint32_t start = PM_TOKEN_START(parser, keyword);
7219 if (rparen_loc->length > 0) {
7220 end = PM_LOCATION_END(rparen_loc);
7221 } else if (arguments != NULL) {
7222 end = PM_NODE_END(arguments);
7223 } else if (lparen_loc->length > 0) {
7224 end = PM_LOCATION_END(lparen_loc);
7226 end = PM_TOKEN_END(parser, keyword);
7229 return pm_yield_node_new(
7233 ((pm_location_t) { .start = start, .length = U32(end - start) }),
7234 TOK2LOC(parser, keyword),
7246pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7247 pm_scope_t *scope = parser->current_scope;
7250 while (scope != NULL) {
7251 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7252 if (scope->closed) break;
7254 scope = scope->previous;
7266static PRISM_INLINE int
7267pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7268 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7274static PRISM_INLINE void
7275pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7276 pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
7282static pm_constant_id_t
7283pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7284 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
7285 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7292static PRISM_INLINE pm_constant_id_t
7293pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
7294 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
7300static PRISM_INLINE pm_constant_id_t
7301pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7302 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
7308static pm_constant_id_t
7309pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7310 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7311 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7318static pm_constant_id_t
7319pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7320 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7321 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7333pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7334 // We want to check whether the parameter name is a numbered parameter or
7336 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7338 // Otherwise we'll fetch the constant id for the parameter name and check
7339 // whether it's already in the current scope.
7340 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7342 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7343 // Add an error if the parameter doesn't start with _ and has been seen before
7344 if ((name->start < name->end) && (*name->start != '_')) {
7345 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7356pm_parser_scope_pop(pm_parser_t *parser) {
7357 pm_scope_t *scope = parser->current_scope;
7358 parser->current_scope = scope->previous;
7359 pm_locals_free(&scope->locals);
7360 xfree_sized(scope, sizeof(pm_scope_t));
7363/******************************************************************************/
7365/******************************************************************************/
7370static PRISM_INLINE void
7371pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7372 *stack = (*stack << 1) | (value & 1);
7378static PRISM_INLINE void
7379pm_state_stack_pop(pm_state_stack_t *stack) {
7386static PRISM_INLINE bool
7387pm_state_stack_p(const pm_state_stack_t *stack) {
7391static PRISM_INLINE void
7392pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7393 // Use the negation of the value to prevent stack overflow.
7394 pm_state_stack_push(&parser->accepts_block_stack, !value);
7397static PRISM_INLINE void
7398pm_accepts_block_stack_pop(pm_parser_t *parser) {
7399 pm_state_stack_pop(&parser->accepts_block_stack);
7402static PRISM_INLINE bool
7403pm_accepts_block_stack_p(pm_parser_t *parser) {
7404 return !pm_state_stack_p(&parser->accepts_block_stack);
7407static PRISM_INLINE void
7408pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7409 pm_state_stack_push(&parser->do_loop_stack, value);
7412static PRISM_INLINE void
7413pm_do_loop_stack_pop(pm_parser_t *parser) {
7414 pm_state_stack_pop(&parser->do_loop_stack);
7417static PRISM_INLINE bool
7418pm_do_loop_stack_p(pm_parser_t *parser) {
7419 return pm_state_stack_p(&parser->do_loop_stack);
7446static PRISM_INLINE void
7447pm_enclosure_frame_push(pm_parser_t *parser) {
7448 pm_do_loop_stack_push(parser, false);
7449 pm_accepts_block_stack_push(parser, true);
7452static PRISM_INLINE void
7453pm_enclosure_frame_pop(pm_parser_t *parser) {
7454 pm_do_loop_stack_pop(parser);
7455 pm_accepts_block_stack_pop(parser);
7458/******************************************************************************/
7459/* Lexer check helpers */
7460/******************************************************************************/
7466static PRISM_INLINE uint8_t
7467peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7468 if (cursor < parser->end) {
7480static PRISM_INLINE uint8_t
7481peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7482 return peek_at(parser, parser->current.end + offset);
7489static PRISM_INLINE uint8_t
7490peek(const pm_parser_t *parser) {
7491 return peek_at(parser, parser->current.end);
7498static PRISM_INLINE bool
7499match(pm_parser_t *parser, uint8_t value) {
7500 if (peek(parser) == value) {
7501 parser->current.end++;
7511static PRISM_INLINE size_t
7512match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7513 if (peek_at(parser, cursor) == '\n') {
7516 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7527static PRISM_INLINE size_t
7528match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7529 return match_eol_at(parser, parser->current.end + offset);
7537static PRISM_INLINE size_t
7538match_eol(pm_parser_t *parser) {
7539 return match_eol_at(parser, parser->current.end);
7545static PRISM_INLINE const uint8_t *
7546next_newline(const uint8_t *cursor, ptrdiff_t length) {
7547 assert(length >= 0);
7549 // Note that it's okay for us to use memchr here to look for \n because none
7550 // of the encodings that we support have \n as a component of a multi-byte
7552 return memchr(cursor, '\n', (size_t) length);
7558static PRISM_INLINE bool
7559ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7560 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));
7568parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7569 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7571 if (encoding != NULL) {
7572 if (parser->encoding != encoding) {
7573 parser->encoding = encoding;
7574 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7577 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7589parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7590 const uint8_t *cursor = parser->current.start + 1;
7591 const uint8_t *end = parser->current.end;
7593 bool separator = false;
7595 if (end - cursor <= 6) return;
7596 switch (cursor[6]) {
7597 case 'C': case 'c': cursor += 6; continue;
7598 case 'O': case 'o': cursor += 5; continue;
7599 case 'D': case 'd': cursor += 4; continue;
7600 case 'I': case 'i': cursor += 3; continue;
7601 case 'N': case 'n': cursor += 2; continue;
7602 case 'G': case 'g': cursor += 1; continue;
7609 if (pm_char_is_whitespace(*cursor)) break;
7612 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7618 if (++cursor >= end) return;
7619 } while (pm_char_is_whitespace(*cursor));
7621 if (separator) break;
7622 if (*cursor != '=' && *cursor != ':') return;
7628 const uint8_t *value_start = cursor;
7629 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7631 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7632 // If we were unable to parse the encoding value, then we've got an
7633 // issue because we didn't understand the encoding that the user was
7634 // trying to use. In this case we'll keep using the default encoding but
7635 // add an error to the parser to indicate an unsuccessful parse.
7636 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7641 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7642 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7643 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7644} pm_magic_comment_boolean_value_t;
7650static pm_magic_comment_boolean_value_t
7651parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7652 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7653 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7654 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7655 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7657 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7661static PRISM_INLINE bool
7662pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7663 return b == '\'' || b == '"' || b == ':' || b == ';';
7672parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7676 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1,
'*', (
size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7677 if (cursor[-1] ==
'-' && cursor + 1 < end && cursor[1] ==
'-') {
7695parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7698 const uint8_t *start = parser->current.start + 1;
7699 const uint8_t *end = parser->current.end;
7700 if (end - start <= 7)
return false;
7702 const uint8_t *cursor;
7703 bool indicator =
false;
7705 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7708 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7720 if (pm_memchr(start,
':', (
size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
7726 start += pm_strspn_whitespace(start, end - start);
7730 while (cursor < end) {
7732 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7735 const uint8_t *key_start = cursor;
7736 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7738 const uint8_t *key_end = cursor;
7739 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7740 if (cursor == end)
break;
7742 if (*cursor ==
':') {
7745 if (!indicator)
return false;
7749 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7750 if (cursor == end)
break;
7752 const uint8_t *value_start;
7753 const uint8_t *value_end;
7755 if (*cursor ==
'"') {
7756 value_start = ++cursor;
7757 for (; cursor < end && *cursor !=
'"'; cursor++) {
7758 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7761 if (cursor < end && *cursor ==
'"') cursor++;
7763 value_start = cursor;
7764 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7769 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7771 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7772 if (cursor != end)
return false;
7778 const size_t key_length = (size_t) (key_end - key_start);
7779 const uint8_t *dash = pm_memchr(key_start,
'-', key_length, parser->encoding_changed, parser->encoding);
7782 pm_string_shared_init(&key, key_start, key_end);
7784 uint8_t *buffer =
xmalloc(key_length);
7785 if (buffer == NULL)
break;
7787 memcpy(buffer, key_start, key_length);
7788 buffer[dash - key_start] =
'_';
7790 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7791 buffer[dash - key_start] =
'_';
7794 pm_string_owned_init(&key, buffer, key_length);
7799 const uint8_t *key_source = pm_string_source(&key);
7800 uint32_t value_length = (uint32_t) (value_end - value_start);
7804 if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7806 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7807 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7809 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7813 if (key_length == 11) {
7814 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7815 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7816 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7817 PM_PARSER_WARN_TOKEN_FORMAT(
7820 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7822 (
const char *) key_source,
7824 (
const char *) value_start
7827 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7828 parser->warn_mismatched_indentation =
false;
7830 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7831 parser->warn_mismatched_indentation =
true;
7835 }
else if (key_length == 21) {
7836 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7839 if (semantic_token_seen) {
7840 pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7842 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7843 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7844 PM_PARSER_WARN_TOKEN_FORMAT(
7847 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7849 (
const char *) key_source,
7851 (
const char *) value_start
7854 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7857 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7863 }
else if (key_length == 24) {
7864 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7865 const uint8_t *cursor = parser->current.start;
7866 while ((cursor > parser->start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7868 if (!((cursor == parser->start) || (cursor[-1] ==
'\n'))) {
7869 pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7870 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7871 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7872 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7873 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7874 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7875 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7876 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7877 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7879 PM_PARSER_WARN_TOKEN_FORMAT(
7882 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7884 (
const char *) key_source,
7886 (
const char *) value_start
7894 pm_string_cleanup(&key);
7911static const uint32_t context_terminators[] = {
7912 [PM_CONTEXT_NONE] = 0,
7913 [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7914 [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7915 [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7916 [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7917 [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7918 [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7919 [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7920 [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7921 [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
7922 [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7923 [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7924 [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7925 [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7926 [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7927 [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7928 [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7929 [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7930 [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7931 [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7932 [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7933 [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
7934 [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
7935 [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7936 [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
7937 [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7938 [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
7939 [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
7940 [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
7941 [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7942 [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7943 [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7944 [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7945 [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7946 [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7947 [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
7948 [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
7949 [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7950 [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7951 [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7952 [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7953 [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
7954 [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7955 [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7956 [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7957 [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7958 [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
7959 [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7960 [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7961 [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7962 [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7963 [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
7964 [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7965 [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
7966 [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
7970context_terminator(pm_context_t context,
pm_token_t *token) {
7971 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7982 while (context_node != NULL) {
7983 if (context_terminator(context_node->context, token))
return context_node->context;
7984 context_node = context_node->prev;
7987 return PM_CONTEXT_NONE;
7991context_push(
pm_parser_t *parser, pm_context_t context) {
7993 if (context_node == NULL)
return false;
7997 if (parser->current_context == NULL) {
7998 parser->current_context = context_node;
8000 context_node->prev = parser->current_context;
8001 parser->current_context = context_node;
8011 parser->current_context = prev;
8015context_p(
const pm_parser_t *parser, pm_context_t context) {
8018 while (context_node != NULL) {
8019 if (context_node->context == context)
return true;
8020 context_node = context_node->prev;
8030 while (context_node != NULL) {
8031 switch (context_node->context) {
8032 case PM_CONTEXT_DEF:
8033 case PM_CONTEXT_DEF_PARAMS:
8034 case PM_CONTEXT_DEF_ENSURE:
8035 case PM_CONTEXT_DEF_RESCUE:
8036 case PM_CONTEXT_DEF_ELSE:
8038 case PM_CONTEXT_CLASS:
8039 case PM_CONTEXT_CLASS_ENSURE:
8040 case PM_CONTEXT_CLASS_RESCUE:
8041 case PM_CONTEXT_CLASS_ELSE:
8042 case PM_CONTEXT_MODULE:
8043 case PM_CONTEXT_MODULE_ENSURE:
8044 case PM_CONTEXT_MODULE_RESCUE:
8045 case PM_CONTEXT_MODULE_ELSE:
8046 case PM_CONTEXT_SCLASS:
8047 case PM_CONTEXT_SCLASS_ENSURE:
8048 case PM_CONTEXT_SCLASS_RESCUE:
8049 case PM_CONTEXT_SCLASS_ELSE:
8052 context_node = context_node->prev;
8064context_human(pm_context_t context) {
8066 case PM_CONTEXT_NONE:
8067 assert(
false &&
"unreachable");
8069 case PM_CONTEXT_BEGIN:
return "begin statement";
8070 case PM_CONTEXT_BLOCK_BRACES:
return "'{'..'}' block";
8071 case PM_CONTEXT_BLOCK_KEYWORDS:
return "'do'..'end' block";
8072 case PM_CONTEXT_BLOCK_PARAMETERS:
return "'|'..'|' block parameter";
8073 case PM_CONTEXT_CASE_WHEN:
return "'when' clause";
8074 case PM_CONTEXT_CASE_IN:
return "'in' clause";
8075 case PM_CONTEXT_CLASS:
return "class definition";
8076 case PM_CONTEXT_DEF:
return "method definition";
8077 case PM_CONTEXT_DEF_PARAMS:
return "method parameters";
8078 case PM_CONTEXT_DEFAULT_PARAMS:
return "parameter default value";
8079 case PM_CONTEXT_DEFINED:
return "'defined?' expression";
8080 case PM_CONTEXT_ELSE:
8081 case PM_CONTEXT_BEGIN_ELSE:
8082 case PM_CONTEXT_BLOCK_ELSE:
8083 case PM_CONTEXT_CLASS_ELSE:
8084 case PM_CONTEXT_DEF_ELSE:
8085 case PM_CONTEXT_LAMBDA_ELSE:
8086 case PM_CONTEXT_MODULE_ELSE:
8087 case PM_CONTEXT_SCLASS_ELSE:
return "'else' clause";
8088 case PM_CONTEXT_ELSIF:
return "'elsif' clause";
8089 case PM_CONTEXT_EMBEXPR:
return "embedded expression";
8090 case PM_CONTEXT_BEGIN_ENSURE:
8091 case PM_CONTEXT_BLOCK_ENSURE:
8092 case PM_CONTEXT_CLASS_ENSURE:
8093 case PM_CONTEXT_DEF_ENSURE:
8094 case PM_CONTEXT_LAMBDA_ENSURE:
8095 case PM_CONTEXT_MODULE_ENSURE:
8096 case PM_CONTEXT_SCLASS_ENSURE:
return "'ensure' clause";
8097 case PM_CONTEXT_FOR:
return "for loop";
8098 case PM_CONTEXT_FOR_INDEX:
return "for loop index";
8099 case PM_CONTEXT_IF:
return "if statement";
8100 case PM_CONTEXT_LAMBDA_BRACES:
return "'{'..'}' lambda block";
8101 case PM_CONTEXT_LAMBDA_DO_END:
return "'do'..'end' lambda block";
8102 case PM_CONTEXT_LOOP_PREDICATE:
return "loop predicate";
8103 case PM_CONTEXT_MAIN:
return "top level context";
8104 case PM_CONTEXT_MODULE:
return "module definition";
8105 case PM_CONTEXT_MULTI_TARGET:
return "multiple targets";
8106 case PM_CONTEXT_PARENS:
return "parentheses";
8107 case PM_CONTEXT_POSTEXE:
return "'END' block";
8108 case PM_CONTEXT_PREDICATE:
return "predicate";
8109 case PM_CONTEXT_PREEXE:
return "'BEGIN' block";
8110 case PM_CONTEXT_BEGIN_RESCUE:
8111 case PM_CONTEXT_BLOCK_RESCUE:
8112 case PM_CONTEXT_CLASS_RESCUE:
8113 case PM_CONTEXT_DEF_RESCUE:
8114 case PM_CONTEXT_LAMBDA_RESCUE:
8115 case PM_CONTEXT_MODULE_RESCUE:
8116 case PM_CONTEXT_RESCUE_MODIFIER:
8117 case PM_CONTEXT_SCLASS_RESCUE:
return "'rescue' clause";
8118 case PM_CONTEXT_SCLASS:
return "singleton class definition";
8119 case PM_CONTEXT_TERNARY:
return "ternary expression";
8120 case PM_CONTEXT_UNLESS:
return "unless statement";
8121 case PM_CONTEXT_UNTIL:
return "until statement";
8122 case PM_CONTEXT_WHILE:
return "while statement";
8125 assert(
false &&
"unreachable");
8134pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8135 if (invalid != NULL) {
8136 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8137 pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
8142pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8143 const uint8_t *invalid = NULL;
8144 size_t length = pm_strspn_binary_number(
string, parser->end -
string, &invalid);
8145 pm_strspn_number_validate(parser,
string, length, invalid);
8150pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8151 const uint8_t *invalid = NULL;
8152 size_t length = pm_strspn_octal_number(
string, parser->end -
string, &invalid);
8153 pm_strspn_number_validate(parser,
string, length, invalid);
8158pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8159 const uint8_t *invalid = NULL;
8160 size_t length = pm_strspn_decimal_number(
string, parser->end -
string, &invalid);
8161 pm_strspn_number_validate(parser,
string, length, invalid);
8166pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8167 const uint8_t *invalid = NULL;
8168 size_t length = pm_strspn_hexadecimal_number(
string, parser->end -
string, &invalid);
8169 pm_strspn_number_validate(parser,
string, length, invalid);
8173static pm_token_type_t
8174lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8175 pm_token_type_t
type = PM_TOKEN_INTEGER;
8179 if (peek(parser) ==
'.') {
8180 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8181 parser->current.end += 2;
8182 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8183 type = PM_TOKEN_FLOAT;
8193 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8194 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8195 parser->current.end += 2;
8197 if (pm_char_is_decimal_digit(peek(parser))) {
8198 parser->current.end++;
8199 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8201 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8203 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8204 parser->current.end++;
8205 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8211 type = PM_TOKEN_FLOAT;
8217static pm_token_type_t
8218lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8219 pm_token_type_t
type = PM_TOKEN_INTEGER;
8222 if (peek_offset(parser, -1) ==
'0') {
8223 switch (*parser->current.end) {
8227 parser->current.end++;
8228 if (pm_char_is_decimal_digit(peek(parser))) {
8229 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8232 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8240 parser->current.end++;
8241 if (pm_char_is_binary_digit(peek(parser))) {
8242 parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
8245 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8248 parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
8254 parser->current.end++;
8255 if (pm_char_is_octal_digit(peek(parser))) {
8256 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8259 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8262 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8275 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8276 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8282 parser->current.end++;
8283 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8284 parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
8287 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8290 parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8295 type = lex_optional_float_suffix(parser, seen_e);
8302 type = lex_optional_float_suffix(parser, seen_e);
8311 const uint8_t *cursor = parser->current.end;
8312 const uint8_t *end = parser->end;
8313 uint64_t value = (uint64_t) (cursor[-1] -
'0');
8315 bool has_underscore =
false;
8316 bool prev_underscore =
false;
8317 const uint8_t *invalid = NULL;
8319 while (cursor < end) {
8320 uint8_t c = *cursor;
8321 if (c >=
'0' && c <=
'9') {
8322 if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c -
'0');
8323 prev_underscore =
false;
8325 }
else if (c ==
'_') {
8326 has_underscore =
true;
8327 if (prev_underscore && invalid == NULL) invalid = cursor;
8328 prev_underscore =
true;
8335 if (has_underscore) {
8336 if (prev_underscore && invalid == NULL) invalid = cursor - 1;
8337 pm_strspn_number_validate(parser, parser->current.end, (
size_t) (cursor - parser->current.end), invalid);
8340 if (value <= UINT32_MAX) {
8341 parser->integer.value = (uint32_t) value;
8342 parser->integer.lexed =
true;
8345 parser->current.end = cursor;
8353 uint8_t next = peek(parser);
8354 if (next ==
'.' || next ==
'e' || next ==
'E') {
8355 type = lex_optional_float_suffix(parser, seen_e);
8359 if (
type != PM_TOKEN_INTEGER) {
8360 parser->integer.lexed =
false;
8369 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8370 const uint8_t *fraction_start = parser->current.end;
8371 const uint8_t *fraction_end = parser->current.end + 2;
8372 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
8373 pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
8379static pm_token_type_t
8381 pm_token_type_t
type = PM_TOKEN_INTEGER;
8382 parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8383 parser->integer.lexed =
false;
8385 if (parser->current.end < parser->end) {
8386 bool seen_e =
false;
8387 type = lex_numeric_prefix(parser, &seen_e);
8389 const uint8_t *end = parser->current.end;
8390 pm_token_type_t suffix_type =
type;
8392 if (
type == PM_TOKEN_INTEGER) {
8393 if (match(parser,
'r')) {
8394 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8396 if (match(parser,
'i')) {
8397 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8399 }
else if (match(parser,
'i')) {
8400 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8403 if (!seen_e && match(parser,
'r')) {
8404 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8406 if (match(parser,
'i')) {
8407 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8409 }
else if (match(parser,
'i')) {
8410 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8414 const uint8_t b = peek(parser);
8415 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8416 parser->current.end = end;
8425static pm_token_type_t
8427 if (parser->current.end >= parser->end) {
8428 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8429 return PM_TOKEN_GLOBAL_VARIABLE;
8434 bool allow_multiple =
true;
8436 switch (*parser->current.end) {
8453 parser->current.end++;
8454 return PM_TOKEN_GLOBAL_VARIABLE;
8460 parser->current.end++;
8461 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8464 parser->current.end++;
8467 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8469 parser->current.end += width;
8470 }
while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8473 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;
8474 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
8477 return PM_TOKEN_GLOBAL_VARIABLE;
8489 parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
8490 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8493 parser->current.end++;
8494 allow_multiple =
false;
8499 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8501 parser->current.end += width;
8502 }
while (allow_multiple && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8503 }
else if (pm_char_is_whitespace(peek(parser))) {
8506 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8510 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;
8511 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8512 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);
8515 return PM_TOKEN_GLOBAL_VARIABLE;
8533lex_keyword(
pm_parser_t *parser,
const uint8_t *current_start,
const char *value,
size_t vlen, pm_lex_state_t state, pm_token_type_t
type, pm_token_type_t modifier_type) {
8534 if (memcmp(current_start, value, vlen) == 0) {
8535 pm_lex_state_t last_state = parser->lex_state;
8537 if (parser->lex_state & PM_LEX_STATE_FNAME) {
8538 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8540 lex_state_set(parser, state);
8541 if (state == PM_LEX_STATE_BEG) {
8542 parser->command_start =
true;
8545 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8546 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8547 return modifier_type;
8554 return PM_TOKEN_EOF;
8557static pm_token_type_t
8558lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8561 const uint8_t *end = parser->end;
8562 const uint8_t *current_start = parser->current.start;
8563 const uint8_t *current_end = parser->current.end;
8564 bool encoding_changed = parser->encoding_changed;
8566 if (encoding_changed) {
8567 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8568 current_end += width;
8572 current_end += scan_identifier_ascii(current_end, end);
8575 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8576 current_end += width;
8579 parser->current.end = current_end;
8583 width = (size_t) (current_end - current_start);
8585 if (current_end < end) {
8586 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8592 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8593 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8597 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8598 (void) match(parser,
':');
8602 parser->explicit_encoding = NULL;
8603 return PM_TOKEN_LABEL;
8606 if (parser->lex_state != PM_LEX_STATE_DOT) {
8607 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8608 return PM_TOKEN_KEYWORD_DEFINED;
8612 return PM_TOKEN_METHOD_NAME;
8615 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,
'=')) {
8618 return PM_TOKEN_IDENTIFIER;
8622 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8623 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8627 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8628 (void) match(parser,
':');
8632 parser->explicit_encoding = NULL;
8633 return PM_TOKEN_LABEL;
8637 if (parser->lex_state != PM_LEX_STATE_DOT) {
8638 pm_token_type_t
type;
8642 pm_lex_state_t previous_lex_state = parser->lex_state;
8646 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8654 if (previous_lex_state & PM_LEX_STATE_FNAME) {
8655 return PM_TOKEN_KEYWORD_DO;
8657 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
8671 parser->lambda_enclosure_nesting = -1;
8672 return PM_TOKEN_KEYWORD_DO_LAMBDA;
8674 if (pm_do_loop_stack_p(parser)) {
8675 return PM_TOKEN_KEYWORD_DO_LOOP;
8677 if (!pm_accepts_block_stack_p(parser)) {
8678 return PM_TOKEN_KEYWORD_DO_BLOCK;
8680 return PM_TOKEN_KEYWORD_DO;
8683 if ((
type = lex_keyword(parser, current_start,
"if", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IF, PM_TOKEN_KEYWORD_IF_MODIFIER)) != PM_TOKEN_EOF)
return type;
8684 if ((
type = lex_keyword(parser, current_start,
"in", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8685 if ((
type = lex_keyword(parser, current_start,
"or", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_OR, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8688 if ((
type = lex_keyword(parser, current_start,
"and", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8689 if ((
type = lex_keyword(parser, current_start,
"def", width, PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8690 if ((
type = lex_keyword(parser, current_start,
"end", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8691 if ((
type = lex_keyword(parser, current_start,
"END", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8692 if ((
type = lex_keyword(parser, current_start,
"for", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8693 if ((
type = lex_keyword(parser, current_start,
"nil", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8694 if ((
type = lex_keyword(parser, current_start,
"not", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_NOT, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8697 if ((
type = lex_keyword(parser, current_start,
"case", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8698 if ((
type = lex_keyword(parser, current_start,
"else", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8699 if ((
type = lex_keyword(parser, current_start,
"next", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8700 if ((
type = lex_keyword(parser, current_start,
"redo", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8701 if ((
type = lex_keyword(parser, current_start,
"self", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8702 if ((
type = lex_keyword(parser, current_start,
"then", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8703 if ((
type = lex_keyword(parser, current_start,
"true", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8704 if ((
type = lex_keyword(parser, current_start,
"when", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8707 if ((
type = lex_keyword(parser, current_start,
"alias", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_ALIAS, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8708 if ((
type = lex_keyword(parser, current_start,
"begin", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8709 if ((
type = lex_keyword(parser, current_start,
"BEGIN", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8710 if ((
type = lex_keyword(parser, current_start,
"break", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8711 if ((
type = lex_keyword(parser, current_start,
"class", width, PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8712 if ((
type = lex_keyword(parser, current_start,
"elsif", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8713 if ((
type = lex_keyword(parser, current_start,
"false", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8714 if ((
type = lex_keyword(parser, current_start,
"retry", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8715 if ((
type = lex_keyword(parser, current_start,
"super", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8716 if ((
type = lex_keyword(parser, current_start,
"undef", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_UNDEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8717 if ((
type = lex_keyword(parser, current_start,
"until", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNTIL, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) != PM_TOKEN_EOF)
return type;
8718 if ((
type = lex_keyword(parser, current_start,
"while", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHILE, PM_TOKEN_KEYWORD_WHILE_MODIFIER)) != PM_TOKEN_EOF)
return type;
8719 if ((
type = lex_keyword(parser, current_start,
"yield", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_YIELD, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8722 if ((
type = lex_keyword(parser, current_start,
"ensure", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8723 if ((
type = lex_keyword(parser, current_start,
"module", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8724 if ((
type = lex_keyword(parser, current_start,
"rescue", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) != PM_TOKEN_EOF)
return type;
8725 if ((
type = lex_keyword(parser, current_start,
"return", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8726 if ((
type = lex_keyword(parser, current_start,
"unless", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNLESS, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) != PM_TOKEN_EOF)
return type;
8729 if ((
type = lex_keyword(parser, current_start,
"__LINE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8730 if ((
type = lex_keyword(parser, current_start,
"__FILE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___FILE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8733 if ((
type = lex_keyword(parser, current_start,
"__ENCODING__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8738 if (encoding_changed) {
8739 return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8745 if (*current_start < 0x80) {
8746 return (*current_start >=
'A' && *current_start <=
'Z') ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8748 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8757 return (parser->current.start == parser->start) || (parser->current.start[-1] ==
'\n');
8774static pm_token_type_t
8775lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8778 if (pound + 1 >= parser->end) {
8779 parser->current.end = pound + 1;
8780 return PM_TOKEN_STRING_CONTENT;
8789 if (pound + 2 >= parser->end) {
8790 parser->current.end = pound + 1;
8791 return PM_TOKEN_STRING_CONTENT;
8796 const uint8_t *variable = pound + 2;
8797 if (*variable ==
'@' && pound + 3 < parser->end) variable++;
8799 if (char_is_identifier_start(parser, variable, parser->end - variable)) {
8803 if (pound > parser->current.start) {
8804 parser->current.end = pound;
8805 return PM_TOKEN_STRING_CONTENT;
8810 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8811 parser->current.end = pound + 1;
8812 return PM_TOKEN_EMBVAR;
8818 parser->current.end = pound + 1;
8824 if (pound + 2 >= parser->end) {
8825 parser->current.end = pound + 1;
8826 return PM_TOKEN_STRING_CONTENT;
8832 const uint8_t *check = pound + 2;
8834 if (pound[2] ==
'-') {
8835 if (pound + 3 >= parser->end) {
8836 parser->current.end = pound + 2;
8837 return PM_TOKEN_STRING_CONTENT;
8848 char_is_identifier_start(parser, check, parser->end - check) ||
8849 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8854 if (pound > parser->current.start) {
8855 parser->current.end = pound;
8856 return PM_TOKEN_STRING_CONTENT;
8861 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8862 parser->current.end = pound + 1;
8863 return PM_TOKEN_EMBVAR;
8868 parser->current.end = pound + 1;
8874 if (pound > parser->current.start) {
8875 parser->current.end = pound;
8876 return PM_TOKEN_STRING_CONTENT;
8879 parser->enclosure_nesting++;
8883 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8884 parser->current.end = pound + 2;
8885 parser->command_start =
true;
8886 pm_enclosure_frame_push(parser);
8887 return PM_TOKEN_EMBEXPR_BEGIN;
8892 parser->current.end = pound + 1;
8897static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8898static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8899static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8900static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8901static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8906static const bool ascii_printable_chars[] = {
8907 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8908 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8909 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8910 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8911 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8912 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8913 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8914 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8918char_is_ascii_printable(
const uint8_t b) {
8919 return (b < 0x80) && ascii_printable_chars[b];
8927escape_hexadecimal_digit(
const uint8_t value) {
8928 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8937escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const pm_location_t *error_location,
const uint8_t flags) {
8939 for (
size_t index = 0; index < length; index++) {
8940 if (index != 0) value <<= 4;
8941 value |= escape_hexadecimal_digit(
string[index]);
8946 if (value >= 0xD800 && value <= 0xDFFF) {
8947 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8950 }
else if (error_location != NULL) {
8951 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
8953 pm_parser_err(parser, U32(
string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
8965escape_byte(uint8_t value,
const uint8_t flags) {
8966 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8967 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8975escape_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) {
8979 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8980 if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
8981 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8985 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
8989 parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
8992 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8993 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8997 pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
9000 pm_buffer_append_byte(buffer, 0xEF);
9001 pm_buffer_append_byte(buffer, 0xBF);
9002 pm_buffer_append_byte(buffer, 0xBD);
9013 if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
9014 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9018 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
9022 parser->explicit_encoding = parser->encoding;
9025 pm_buffer_append_byte(buffer,
byte);
9045 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9046 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9049 escape_write_byte_encoded(parser, buffer, flags,
byte);
9058 if (parser->encoding_changed) {
9059 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9061 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9065 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);
9066 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
9067 }
else if (width > 1) {
9069 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9070 pm_buffer_append_bytes(b, parser->current.end, width);
9071 parser->current.end += width;
9075 parser->current.end++;
9076 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9086escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9087#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9089 PM_PARSER_WARN_TOKEN_FORMAT(
9092 PM_WARN_INVALID_CHARACTER,
9106 uint8_t peeked = peek(parser);
9109 parser->current.end++;
9110 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9114 parser->current.end++;
9115 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9119 parser->current.end++;
9120 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9124 parser->current.end++;
9125 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9129 parser->current.end++;
9130 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9134 parser->current.end++;
9135 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9139 parser->current.end++;
9140 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9144 parser->current.end++;
9145 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9149 parser->current.end++;
9150 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9154 parser->current.end++;
9155 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9159 parser->current.end++;
9160 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9163 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9164 uint8_t value = (uint8_t) (*parser->current.end -
'0');
9165 parser->current.end++;
9167 if (pm_char_is_octal_digit(peek(parser))) {
9168 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9169 parser->current.end++;
9171 if (pm_char_is_octal_digit(peek(parser))) {
9172 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9173 parser->current.end++;
9177 value = escape_byte(value, flags);
9178 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9182 const uint8_t *start = parser->current.end - 1;
9184 parser->current.end++;
9185 uint8_t
byte = peek(parser);
9187 if (pm_char_is_hexadecimal_digit(
byte)) {
9188 uint8_t value = escape_hexadecimal_digit(
byte);
9189 parser->current.end++;
9191 byte = peek(parser);
9192 if (pm_char_is_hexadecimal_digit(
byte)) {
9193 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9194 parser->current.end++;
9197 value = escape_byte(value, flags);
9198 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9199 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9200 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9202 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9206 escape_write_byte_encoded(parser, buffer, flags, value);
9208 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9214 const uint8_t *start = parser->current.end - 1;
9215 parser->current.end++;
9217 if (parser->current.end == parser->end) {
9218 const uint8_t *start = parser->current.end - 2;
9219 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9220 }
else if (peek(parser) ==
'{') {
9221 const uint8_t *unicode_codepoints_start = parser->current.end - 2;
9222 parser->current.end++;
9226 if ((whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end)) > 0) {
9227 parser->current.end += whitespace;
9228 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9233 parser->current.end += 2;
9239 const uint8_t *extra_codepoints_start = NULL;
9240 int codepoints_count = 0;
9242 while ((parser->current.end < parser->end) && (*parser->current.end !=
'}')) {
9243 const uint8_t *unicode_start = parser->current.end;
9244 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
9246 if (hexadecimal_length > 6) {
9248 pm_parser_err(parser, U32(unicode_start - parser->start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9249 }
else if (hexadecimal_length == 0) {
9252 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9257 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9259 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
9260 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9266 parser->current.end += hexadecimal_length;
9268 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9269 extra_codepoints_start = unicode_start;
9272 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
9273 escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
9275 parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
9280 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9281 pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9284 if (parser->current.end == parser->end) {
9285 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);
9286 }
else if (peek(parser) ==
'}') {
9287 parser->current.end++;
9289 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9294 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9296 pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9300 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9301 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->current.end - unicode_codepoints_start));
9304 size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
9307 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9308 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9310 const uint8_t *start = parser->current.end - 2;
9311 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9313 }
else if (length == 4) {
9314 uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
9316 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9317 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end + 4 - start));
9320 escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
9321 parser->current.end += 4;
9323 parser->current.end += length;
9325 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9329 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9331 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9339 parser->current.end++;
9340 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9341 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9344 if (parser->current.end == parser->end) {
9345 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9349 uint8_t peeked = peek(parser);
9352 parser->current.end++;
9353 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9357 parser->current.end++;
9359 if (match(parser,
'u') || match(parser,
'U')) {
9360 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9364 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9367 parser->current.end++;
9368 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9369 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9372 parser->current.end++;
9373 escape_read_warn(parser, flags, 0,
"\\t");
9374 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9377 if (!char_is_ascii_printable(peeked)) {
9378 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9382 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);
9383 parser->current.end++;
9384 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9390 parser->current.end++;
9391 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9392 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9395 if (peek(parser) !=
'-') {
9396 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9397 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9401 parser->current.end++;
9402 if (parser->current.end == parser->end) {
9403 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9407 uint8_t peeked = peek(parser);
9410 parser->current.end++;
9411 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9415 parser->current.end++;
9417 if (match(parser,
'u') || match(parser,
'U')) {
9418 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9422 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9425 parser->current.end++;
9426 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9427 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9430 parser->current.end++;
9431 escape_read_warn(parser, flags, 0,
"\\t");
9432 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9435 if (!char_is_ascii_printable(peeked)) {
9436 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9437 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9441 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);
9442 parser->current.end++;
9443 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9449 parser->current.end++;
9450 if (flags & PM_ESCAPE_FLAG_META) {
9451 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9454 if (peek(parser) !=
'-') {
9455 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9456 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9460 parser->current.end++;
9461 if (parser->current.end == parser->end) {
9462 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9466 uint8_t peeked = peek(parser);
9469 parser->current.end++;
9471 if (match(parser,
'u') || match(parser,
'U')) {
9472 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9476 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9479 parser->current.end++;
9480 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9481 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9484 parser->current.end++;
9485 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9486 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9489 if (!char_is_ascii_printable(peeked)) {
9490 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9491 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9495 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);
9496 parser->current.end++;
9497 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9502 if (peek_offset(parser, 1) ==
'\n') {
9503 if (parser->heredoc_end == NULL) pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
9504 parser->current.end += 2;
9505 escape_write_byte_encoded(parser, buffer, flags, escape_byte(
'\n', flags));
9511 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9512 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9513 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9516 if (parser->current.end < parser->end) {
9517 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9519 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9551static pm_token_type_t
9553 if (lex_state_end_p(parser)) {
9554 lex_state_set(parser, PM_LEX_STATE_BEG);
9555 return PM_TOKEN_QUESTION_MARK;
9563 parser->explicit_encoding = NULL;
9565 if (parser->current.end >= parser->end) {
9566 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9567 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9568 return PM_TOKEN_CHARACTER_LITERAL;
9571 if (pm_char_is_whitespace(*parser->current.end)) {
9572 lex_state_set(parser, PM_LEX_STATE_BEG);
9573 return PM_TOKEN_QUESTION_MARK;
9576 lex_state_set(parser, PM_LEX_STATE_BEG);
9578 if (match(parser,
'\\')) {
9579 lex_state_set(parser, PM_LEX_STATE_END);
9582 pm_buffer_init(&buffer, 3);
9584 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9587 void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length,
PRISM_ALIGNOF(uint8_t));
9588 pm_string_constant_init(&parser->current_string, (
const char *) arena_data, buffer.length);
9589 pm_buffer_cleanup(&buffer);
9591 return PM_TOKEN_CHARACTER_LITERAL;
9593 size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9598 !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) ==
'_') ||
9600 (parser->current.end + encoding_width >= parser->end) ||
9601 !char_is_identifier(parser, parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
9604 lex_state_set(parser, PM_LEX_STATE_END);
9605 parser->current.end += encoding_width;
9606 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9607 return PM_TOKEN_CHARACTER_LITERAL;
9611 return PM_TOKEN_QUESTION_MARK;
9618static pm_token_type_t
9620 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9621 const uint8_t *end = parser->end;
9624 if ((width = char_is_identifier_start(parser, parser->current.end, end - parser->current.end)) > 0) {
9625 parser->current.end += width;
9627 while ((width = char_is_identifier(parser, parser->current.end, end - parser->current.end)) > 0) {
9628 parser->current.end += width;
9630 }
else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
9631 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9632 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
9633 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9636 size_t width = parser->encoding->char_width(parser->current.end, end - parser->current.end);
9637 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, (
int) ((parser->current.end + width) - parser->current.start), (
const char *) parser->current.start);
9639 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9640 pm_parser_err_token(parser, &parser->current, diag_id);
9645 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
9646 lex_mode_pop(parser);
9657 if (parser->lex_callback.callback) {
9658 parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
9671 .location = TOK2LOC(parser, &parser->current)
9682static pm_token_type_t
9685 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9687 if (newline == NULL) {
9688 parser->current.end = parser->end;
9690 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9691 parser->current.end = newline + 1;
9694 parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
9695 parser_lex_callback(parser);
9698 const uint8_t *comment_start = parser->current.start;
9699 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9703 while (parser->current.end + 4 <= parser->end) {
9704 parser->current.start = parser->current.end;
9709 (memcmp(parser->current.end,
"=end", 4) == 0) &&
9711 (parser->current.end + 4 == parser->end) ||
9712 pm_char_is_whitespace(parser->current.end[4]) ||
9713 (parser->current.end[4] ==
'\0') ||
9714 (parser->current.end[4] ==
'\004') ||
9715 (parser->current.end[4] ==
'\032')
9718 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9720 if (newline == NULL) {
9721 parser->current.end = parser->end;
9723 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9724 parser->current.end = newline + 1;
9727 parser->current.type = PM_TOKEN_EMBDOC_END;
9728 parser_lex_callback(parser);
9730 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9731 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9733 return PM_TOKEN_EMBDOC_END;
9738 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9740 if (newline == NULL) {
9741 parser->current.end = parser->end;
9743 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9744 parser->current.end = newline + 1;
9747 parser->current.type = PM_TOKEN_EMBDOC_LINE;
9748 parser_lex_callback(parser);
9751 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9753 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9754 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9756 return PM_TOKEN_EOF;
9766 parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
9767 parser_lex_callback(parser);
9781 assert(parser->heredoc_end <= parser->end);
9782 parser->next_start = parser->heredoc_end;
9783 parser->heredoc_end = NULL;
9791 const uint8_t *cursor = parser->current.end;
9793 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9794 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9857 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9871 if (parser->encoding_changed) {
9872 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9874 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9879 return (width == 0 ? 1 : width);
9887 size_t width = parser_char_width(parser);
9888 pm_buffer_append_bytes(&token_buffer->
buffer, parser->current.end, width);
9889 parser->current.end += width;
9894 size_t width = parser_char_width(parser);
9895 const uint8_t *start = parser->current.end;
9896 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, width);
9897 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, width);
9898 parser->current.end += width;
9910 size_t len = pm_buffer_length(&token_buffer->
buffer);
9911 void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->
buffer),
len,
PRISM_ALIGNOF(uint8_t));
9912 pm_string_constant_init(&parser->current_string, (
const char *) arena_data,
len);
9913 pm_buffer_cleanup(&token_buffer->
buffer);
9918 pm_token_buffer_copy(parser, &token_buffer->
base);
9933 if (token_buffer->
cursor == NULL) {
9934 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9936 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->current.end - token_buffer->
cursor));
9937 pm_token_buffer_copy(parser, token_buffer);
9944 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9946 const uint8_t *cursor = token_buffer->
base.
cursor;
9947 size_t length = (size_t) (parser->current.end - cursor);
9948 pm_buffer_append_bytes(&token_buffer->
base.
buffer, cursor, length);
9949 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, cursor, length);
9950 pm_regexp_token_buffer_copy(parser, token_buffer);
9954#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9966 const uint8_t *start;
9967 if (token_buffer->
cursor == NULL) {
9968 pm_buffer_init(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9969 start = parser->current.start;
9971 start = token_buffer->
cursor;
9974 const uint8_t *end = parser->current.end - 1;
9975 assert(end >= start);
9976 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9978 token_buffer->
cursor = end;
9983 const uint8_t *start;
9985 pm_buffer_init(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9986 pm_buffer_init(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9987 start = parser->current.start;
9992 const uint8_t *end = parser->current.end - 1;
9993 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9994 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9999#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10006pm_heredoc_strspn_inline_whitespace(
pm_parser_t *parser,
const uint8_t **cursor, pm_heredoc_indent_t indent) {
10007 size_t whitespace = 0;
10010 case PM_HEREDOC_INDENT_NONE:
10015 case PM_HEREDOC_INDENT_DASH:
10017 *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
10019 case PM_HEREDOC_INDENT_TILDE:
10022 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10023 if (**cursor ==
'\t') {
10024 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10043 size_t eol_length = match_eol(parser);
10046 if (parser->heredoc_end) {
10050 parser_flush_heredoc_end(parser);
10053 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
10056 uint8_t delimiter = *parser->current.end;
10060 if (eol_length == 2) {
10061 delimiter = *(parser->current.end + 1);
10064 parser->current.end += eol_length;
10068 return *parser->current.end++;
10075#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10085 assert(parser->current.end <= parser->end);
10086 parser->previous = parser->current;
10089 bool previous_command_start = parser->command_start;
10090 parser->command_start =
false;
10094 bool lexed_comment =
false;
10098 unsigned int semantic_token_seen = parser->semantic_token_seen;
10099 parser->semantic_token_seen =
true;
10107 switch (parser->lex_modes.current->mode) {
10108 case PM_LEX_DEFAULT:
10109 case PM_LEX_EMBEXPR:
10110 case PM_LEX_EMBVAR:
10119 if (parser->next_start != NULL) {
10120 parser->current.end = parser->next_start;
10121 parser->next_start = NULL;
10126 bool space_seen =
false;
10131 bool chomping =
true;
10138 static const uint8_t inline_whitespace[256] = {
10139 [
' '] = 1, [
'\t'] = 1, [
'\f'] = 1, [
'\v'] = 1
10141 const uint8_t *scan = parser->current.end;
10142 while (scan < parser->end && inline_whitespace[*scan]) scan++;
10143 if (scan > parser->current.end) {
10144 parser->current.end = scan;
10147 if (scan >= parser->end)
break;
10150 switch (*parser->current.end) {
10152 if (match_eol_offset(parser, 1)) {
10155 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10156 parser->current.end++;
10161 size_t eol_length = match_eol_offset(parser, 1);
10163 if (parser->heredoc_end) {
10164 parser->current.end = parser->heredoc_end;
10165 parser->heredoc_end = NULL;
10167 parser->current.end += eol_length + 1;
10168 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10171 }
else if (pm_char_is_inline_whitespace(*parser->current.end)) {
10172 parser->current.end += 2;
10186 parser->current.start = parser->current.end;
10190 if (parser->current.end >= parser->end) {
10194 if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
10195 lex_mode_pop(parser);
10196 goto switch_lex_modes;
10204 if (parser->current.start > parser->start && (*(parser->current.start - 1) ==
'\n')) {
10205 parser->current.start -= 1;
10212 switch (*parser->current.end++) {
10216 parser->current.end--;
10220 const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
10221 parser->current.end = ending == NULL ? parser->end : ending;
10226 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10227 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
10229 parser->current.type = PM_TOKEN_COMMENT;
10230 parser_lex_callback(parser);
10234 if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
10235 ptrdiff_t length = parser->current.end - parser->current.start;
10241 if (length >= 10 && !parser->encoding_locked) {
10242 parser_lex_magic_comment_encoding(parser);
10250 if (ending == NULL) {
10251 lexed_comment =
true;
10253 parser->current.start = ending;
10254 parser->current.end = ending + 1;
10260 parser->semantic_token_seen = semantic_token_seen & 0x1;
10261 size_t eol_length = match_eol_at(parser, parser->current.end - 1);
10273 if (!lexed_comment) {
10274 parser->current.end += eol_length - 1;
10277 if (parser->heredoc_end == NULL) {
10278 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10282 if (parser->heredoc_end) {
10283 parser_flush_heredoc_end(parser);
10288 switch (lex_state_ignored_p(parser)) {
10289 case PM_IGNORED_NEWLINE_NONE:
10291 case PM_IGNORED_NEWLINE_PATTERN:
10292 if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
10293 if (!lexed_comment) {
10294 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10295 parser_lex_callback(parser);
10298 lex_state_set(parser, PM_LEX_STATE_BEG);
10299 parser->command_start =
true;
10300 parser->current.type = PM_TOKEN_NEWLINE;
10304 case PM_IGNORED_NEWLINE_ALL:
10305 if (!lexed_comment) parser_lex_ignored_newline(parser);
10306 lexed_comment =
false;
10307 goto lex_next_token;
10314 const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
10315 next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
10317 if (next_content < parser->end) {
10323 if (next_content[0] ==
'#') {
10325 const uint8_t *following = next_newline(next_content, parser->end - next_content);
10327 while (following && (following + 1 < parser->end)) {
10329 following += pm_strspn_inline_whitespace(following, parser->end - following);
10333 if (peek_at(parser, following) !=
'#')
break;
10337 following = next_newline(following, parser->end - following);
10342 if (lex_state_ignored_p(parser)) {
10343 if (!lexed_comment) parser_lex_ignored_newline(parser);
10344 lexed_comment =
false;
10345 goto lex_next_token;
10351 (peek_at(parser, following) ==
'.') ||
10352 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10354 if (!lexed_comment) parser_lex_ignored_newline(parser);
10355 lexed_comment =
false;
10356 goto lex_next_token;
10364 (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
10366 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10367 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10369 peek_at(parser, following) ==
'a' &&
10370 peek_at(parser, following + 1) ==
'n' &&
10371 peek_at(parser, following + 2) ==
'd' &&
10372 peek_at(parser, next_content + 3) !=
'!' &&
10373 peek_at(parser, next_content + 3) !=
'?' &&
10374 !char_is_identifier(parser, following + 3, parser->end - (following + 3))
10377 peek_at(parser, following) ==
'o' &&
10378 peek_at(parser, following + 1) ==
'r' &&
10379 peek_at(parser, next_content + 2) !=
'!' &&
10380 peek_at(parser, next_content + 2) !=
'?' &&
10381 !char_is_identifier(parser, following + 2, parser->end - (following + 2))
10385 if (!lexed_comment) parser_lex_ignored_newline(parser);
10386 lexed_comment =
false;
10387 goto lex_next_token;
10393 if (next_content[0] ==
'.') {
10397 if (peek_at(parser, next_content + 1) ==
'.') {
10398 if (!lexed_comment) {
10399 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10400 parser_lex_callback(parser);
10403 lex_state_set(parser, PM_LEX_STATE_BEG);
10404 parser->command_start =
true;
10405 parser->current.type = PM_TOKEN_NEWLINE;
10409 if (!lexed_comment) parser_lex_ignored_newline(parser);
10410 lex_state_set(parser, PM_LEX_STATE_DOT);
10411 parser->current.start = next_content;
10412 parser->current.end = next_content + 1;
10413 parser->next_start = NULL;
10419 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10420 if (!lexed_comment) parser_lex_ignored_newline(parser);
10421 lex_state_set(parser, PM_LEX_STATE_DOT);
10422 parser->current.start = next_content;
10423 parser->current.end = next_content + 2;
10424 parser->next_start = NULL;
10425 LEX(PM_TOKEN_AMPERSAND_DOT);
10428 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
10431 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10432 if (!lexed_comment) parser_lex_ignored_newline(parser);
10433 lex_state_set(parser, PM_LEX_STATE_BEG);
10434 parser->current.start = next_content;
10435 parser->current.end = next_content + 2;
10436 parser->next_start = NULL;
10437 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10442 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10443 if (!lexed_comment) parser_lex_ignored_newline(parser);
10444 lex_state_set(parser, PM_LEX_STATE_BEG);
10445 parser->current.start = next_content;
10446 parser->current.end = next_content + 2;
10447 parser->next_start = NULL;
10448 LEX(PM_TOKEN_PIPE_PIPE);
10454 peek_at(parser, next_content) ==
'a' &&
10455 peek_at(parser, next_content + 1) ==
'n' &&
10456 peek_at(parser, next_content + 2) ==
'd' &&
10457 peek_at(parser, next_content + 3) !=
'!' &&
10458 peek_at(parser, next_content + 3) !=
'?' &&
10459 !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
10461 if (!lexed_comment) parser_lex_ignored_newline(parser);
10462 lex_state_set(parser, PM_LEX_STATE_BEG);
10463 parser->current.start = next_content;
10464 parser->current.end = next_content + 3;
10465 parser->next_start = NULL;
10466 parser->command_start =
true;
10467 LEX(PM_TOKEN_KEYWORD_AND);
10473 peek_at(parser, next_content) ==
'o' &&
10474 peek_at(parser, next_content + 1) ==
'r' &&
10475 peek_at(parser, next_content + 2) !=
'!' &&
10476 peek_at(parser, next_content + 2) !=
'?' &&
10477 !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
10479 if (!lexed_comment) parser_lex_ignored_newline(parser);
10480 lex_state_set(parser, PM_LEX_STATE_BEG);
10481 parser->current.start = next_content;
10482 parser->current.end = next_content + 2;
10483 parser->next_start = NULL;
10484 parser->command_start =
true;
10485 LEX(PM_TOKEN_KEYWORD_OR);
10492 lex_state_set(parser, PM_LEX_STATE_BEG);
10493 parser->command_start =
true;
10494 parser->current.type = PM_TOKEN_NEWLINE;
10495 if (!lexed_comment) parser_lex_callback(parser);
10501 if ((parser->previous.
type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
10502 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
10505 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10506 LEX(PM_TOKEN_COMMA);
10514 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10516 if (lex_state_beg_p(parser)) {
10517 type = PM_TOKEN_PARENTHESIS_LEFT_GROUPING;
10518 }
else if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10519 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10522 parser->enclosure_nesting++;
10523 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10524 pm_enclosure_frame_push(parser);
10530 parser->enclosure_nesting--;
10531 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10532 pm_enclosure_frame_pop(parser);
10533 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10537 lex_state_set(parser, PM_LEX_STATE_BEG);
10538 parser->command_start =
true;
10539 LEX(PM_TOKEN_SEMICOLON);
10543 parser->enclosure_nesting++;
10544 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10546 if (lex_state_operator_p(parser)) {
10547 if (match(parser,
']')) {
10548 parser->enclosure_nesting--;
10549 lex_state_set(parser, PM_LEX_STATE_ARG);
10550 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10553 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10557 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10558 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10561 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10562 pm_enclosure_frame_push(parser);
10567 parser->enclosure_nesting--;
10568 lex_state_set(parser, PM_LEX_STATE_END);
10569 pm_enclosure_frame_pop(parser);
10570 LEX(PM_TOKEN_BRACKET_RIGHT);
10574 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10576 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
10578 parser->command_start =
true;
10579 lex_state_set(parser, PM_LEX_STATE_BEG);
10580 type = PM_TOKEN_LAMBDA_BEGIN;
10581 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10583 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10584 type = PM_TOKEN_BRACE_LEFT_HASH;
10585 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10587 parser->command_start =
true;
10588 lex_state_set(parser, PM_LEX_STATE_BEG);
10589 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10592 parser->command_start =
true;
10593 lex_state_set(parser, PM_LEX_STATE_BEG);
10594 type = PM_TOKEN_BRACE_LEFT_ARGUMENT;
10597 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10598 type = PM_TOKEN_BRACE_LEFT_HASH;
10601 parser->enclosure_nesting++;
10602 parser->brace_nesting++;
10603 pm_enclosure_frame_push(parser);
10610 parser->enclosure_nesting--;
10611 pm_enclosure_frame_pop(parser);
10613 if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
10614 lex_mode_pop(parser);
10615 LEX(PM_TOKEN_EMBEXPR_END);
10618 parser->brace_nesting--;
10619 lex_state_set(parser, PM_LEX_STATE_END);
10620 LEX(PM_TOKEN_BRACE_RIGHT);
10624 if (match(parser,
'*')) {
10625 if (match(parser,
'=')) {
10626 lex_state_set(parser, PM_LEX_STATE_BEG);
10627 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10630 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10632 if (lex_state_spcarg_p(parser, space_seen)) {
10633 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10634 type = PM_TOKEN_USTAR_STAR;
10635 }
else if (lex_state_beg_p(parser)) {
10636 type = PM_TOKEN_USTAR_STAR;
10637 }
else if (ambiguous_operator_p(parser, space_seen)) {
10638 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10641 if (lex_state_operator_p(parser)) {
10642 lex_state_set(parser, PM_LEX_STATE_ARG);
10644 lex_state_set(parser, PM_LEX_STATE_BEG);
10650 if (match(parser,
'=')) {
10651 lex_state_set(parser, PM_LEX_STATE_BEG);
10652 LEX(PM_TOKEN_STAR_EQUAL);
10655 pm_token_type_t
type = PM_TOKEN_STAR;
10657 if (lex_state_spcarg_p(parser, space_seen)) {
10658 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10659 type = PM_TOKEN_USTAR;
10660 }
else if (lex_state_beg_p(parser)) {
10661 type = PM_TOKEN_USTAR;
10662 }
else if (ambiguous_operator_p(parser, space_seen)) {
10663 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10666 if (lex_state_operator_p(parser)) {
10667 lex_state_set(parser, PM_LEX_STATE_ARG);
10669 lex_state_set(parser, PM_LEX_STATE_BEG);
10677 if (lex_state_operator_p(parser)) {
10678 lex_state_set(parser, PM_LEX_STATE_ARG);
10679 if (match(parser,
'@')) {
10680 LEX(PM_TOKEN_BANG);
10683 lex_state_set(parser, PM_LEX_STATE_BEG);
10686 if (match(parser,
'=')) {
10687 LEX(PM_TOKEN_BANG_EQUAL);
10690 if (match(parser,
'~')) {
10691 LEX(PM_TOKEN_BANG_TILDE);
10694 LEX(PM_TOKEN_BANG);
10699 current_token_starts_line(parser) &&
10700 (parser->current.end + 5 <= parser->end) &&
10701 memcmp(parser->current.end,
"begin", 5) == 0 &&
10702 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10704 pm_token_type_t
type = lex_embdoc(parser);
10705 if (
type == PM_TOKEN_EOF) {
10709 goto lex_next_token;
10712 if (lex_state_operator_p(parser)) {
10713 lex_state_set(parser, PM_LEX_STATE_ARG);
10715 lex_state_set(parser, PM_LEX_STATE_BEG);
10718 if (match(parser,
'>')) {
10719 LEX(PM_TOKEN_EQUAL_GREATER);
10722 if (match(parser,
'~')) {
10723 LEX(PM_TOKEN_EQUAL_TILDE);
10726 if (match(parser,
'=')) {
10727 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10730 LEX(PM_TOKEN_EQUAL);
10734 if (match(parser,
'<')) {
10736 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10737 !lex_state_end_p(parser) &&
10738 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10740 const uint8_t *end = parser->current.end;
10742 pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
10743 pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
10745 if (match(parser,
'-')) {
10746 indent = PM_HEREDOC_INDENT_DASH;
10748 else if (match(parser,
'~')) {
10749 indent = PM_HEREDOC_INDENT_TILDE;
10752 if (match(parser,
'`')) {
10753 quote = PM_HEREDOC_QUOTE_BACKTICK;
10755 else if (match(parser,
'"')) {
10756 quote = PM_HEREDOC_QUOTE_DOUBLE;
10758 else if (match(parser,
'\'')) {
10759 quote = PM_HEREDOC_QUOTE_SINGLE;
10762 const uint8_t *ident_start = parser->current.end;
10765 if (parser->current.end >= parser->end) {
10766 parser->current.end = end;
10767 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) == 0) {
10768 parser->current.end = end;
10770 if (quote == PM_HEREDOC_QUOTE_NONE) {
10771 parser->current.end += width;
10773 while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end))) {
10774 parser->current.end += width;
10779 while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
10780 if (*parser->current.end ==
'\r' || *parser->current.end ==
'\n')
break;
10781 parser->current.end++;
10785 size_t ident_length = (size_t) (parser->current.end - ident_start);
10786 bool ident_error =
false;
10788 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10789 pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10790 ident_error =
true;
10793 parser->explicit_encoding = NULL;
10795 .mode = PM_LEX_HEREDOC,
10798 .ident_start = ident_start,
10799 .ident_length = ident_length,
10803 .next_start = parser->current.end,
10804 .common_whitespace = NULL,
10805 .line_continuation =
false
10809 if (parser->heredoc_end == NULL) {
10810 const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
10812 if (body_start == NULL) {
10817 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10818 body_start = parser->end;
10822 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
10826 parser->next_start = body_start;
10828 parser->next_start = parser->heredoc_end;
10831 LEX(PM_TOKEN_HEREDOC_START);
10835 if (match(parser,
'=')) {
10836 lex_state_set(parser, PM_LEX_STATE_BEG);
10837 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10840 if (ambiguous_operator_p(parser, space_seen)) {
10841 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10844 if (lex_state_operator_p(parser)) {
10845 lex_state_set(parser, PM_LEX_STATE_ARG);
10847 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10848 lex_state_set(parser, PM_LEX_STATE_BEG);
10851 LEX(PM_TOKEN_LESS_LESS);
10854 if (lex_state_operator_p(parser)) {
10855 lex_state_set(parser, PM_LEX_STATE_ARG);
10857 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10858 lex_state_set(parser, PM_LEX_STATE_BEG);
10861 if (match(parser,
'=')) {
10862 if (match(parser,
'>')) {
10863 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10866 LEX(PM_TOKEN_LESS_EQUAL);
10869 LEX(PM_TOKEN_LESS);
10873 if (match(parser,
'>')) {
10874 if (lex_state_operator_p(parser)) {
10875 lex_state_set(parser, PM_LEX_STATE_ARG);
10877 lex_state_set(parser, PM_LEX_STATE_BEG);
10879 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10882 if (lex_state_operator_p(parser)) {
10883 lex_state_set(parser, PM_LEX_STATE_ARG);
10885 lex_state_set(parser, PM_LEX_STATE_BEG);
10888 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10892 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10893 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10894 LEX(PM_TOKEN_STRING_BEGIN);
10899 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10900 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10901 LEX(PM_TOKEN_BACKTICK);
10904 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10905 if (previous_command_start) {
10906 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10908 lex_state_set(parser, PM_LEX_STATE_ARG);
10911 LEX(PM_TOKEN_BACKTICK);
10914 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10915 LEX(PM_TOKEN_XSTRING_BEGIN);
10920 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10921 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10922 LEX(PM_TOKEN_STRING_BEGIN);
10927 LEX(lex_question_mark(parser));
10931 if (match(parser,
'&')) {
10932 lex_state_set(parser, PM_LEX_STATE_BEG);
10934 if (match(parser,
'=')) {
10935 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10938 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10941 if (match(parser,
'=')) {
10942 lex_state_set(parser, PM_LEX_STATE_BEG);
10943 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10946 if (match(parser,
'.')) {
10947 lex_state_set(parser, PM_LEX_STATE_DOT);
10948 LEX(PM_TOKEN_AMPERSAND_DOT);
10951 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10952 if (lex_state_spcarg_p(parser, space_seen)) {
10953 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10954 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10956 const uint8_t delim = peek_offset(parser, 1);
10958 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->current.end + 1, parser->end - (parser->current.end + 1))) {
10959 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10963 type = PM_TOKEN_UAMPERSAND;
10964 }
else if (lex_state_beg_p(parser)) {
10965 type = PM_TOKEN_UAMPERSAND;
10966 }
else if (ambiguous_operator_p(parser, space_seen)) {
10967 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10970 if (lex_state_operator_p(parser)) {
10971 lex_state_set(parser, PM_LEX_STATE_ARG);
10973 lex_state_set(parser, PM_LEX_STATE_BEG);
10981 if (match(parser,
'|')) {
10982 if (match(parser,
'=')) {
10983 lex_state_set(parser, PM_LEX_STATE_BEG);
10984 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10987 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10988 parser->current.end--;
10989 LEX(PM_TOKEN_PIPE);
10992 lex_state_set(parser, PM_LEX_STATE_BEG);
10993 LEX(PM_TOKEN_PIPE_PIPE);
10996 if (match(parser,
'=')) {
10997 lex_state_set(parser, PM_LEX_STATE_BEG);
10998 LEX(PM_TOKEN_PIPE_EQUAL);
11001 if (lex_state_operator_p(parser)) {
11002 lex_state_set(parser, PM_LEX_STATE_ARG);
11004 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11007 LEX(PM_TOKEN_PIPE);
11011 if (lex_state_operator_p(parser)) {
11012 lex_state_set(parser, PM_LEX_STATE_ARG);
11014 if (match(parser,
'@')) {
11015 LEX(PM_TOKEN_UPLUS);
11018 LEX(PM_TOKEN_PLUS);
11021 if (match(parser,
'=')) {
11022 lex_state_set(parser, PM_LEX_STATE_BEG);
11023 LEX(PM_TOKEN_PLUS_EQUAL);
11027 lex_state_beg_p(parser) ||
11028 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11030 lex_state_set(parser, PM_LEX_STATE_BEG);
11032 if (pm_char_is_decimal_digit(peek(parser))) {
11033 parser->current.end++;
11034 pm_token_type_t
type = lex_numeric(parser);
11035 lex_state_set(parser, PM_LEX_STATE_END);
11039 LEX(PM_TOKEN_UPLUS);
11042 if (ambiguous_operator_p(parser, space_seen)) {
11043 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11046 lex_state_set(parser, PM_LEX_STATE_BEG);
11047 LEX(PM_TOKEN_PLUS);
11052 if (lex_state_operator_p(parser)) {
11053 lex_state_set(parser, PM_LEX_STATE_ARG);
11055 if (match(parser,
'@')) {
11056 LEX(PM_TOKEN_UMINUS);
11059 LEX(PM_TOKEN_MINUS);
11062 if (match(parser,
'=')) {
11063 lex_state_set(parser, PM_LEX_STATE_BEG);
11064 LEX(PM_TOKEN_MINUS_EQUAL);
11067 if (match(parser,
'>')) {
11068 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11069 LEX(PM_TOKEN_MINUS_GREATER);
11072 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11073 bool is_beg = lex_state_beg_p(parser);
11074 if (!is_beg && spcarg) {
11075 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11078 if (is_beg || spcarg) {
11079 lex_state_set(parser, PM_LEX_STATE_BEG);
11080 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11083 if (ambiguous_operator_p(parser, space_seen)) {
11084 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11087 lex_state_set(parser, PM_LEX_STATE_BEG);
11088 LEX(PM_TOKEN_MINUS);
11093 bool beg_p = lex_state_beg_p(parser);
11095 if (match(parser,
'.')) {
11096 if (match(parser,
'.')) {
11098 if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) {
11099 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11100 lex_state_set(parser, PM_LEX_STATE_BEG);
11102 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11104 LEX(PM_TOKEN_UDOT_DOT_DOT);
11107 if (parser->enclosure_nesting == 0 && parser_end_of_line_p(parser)) {
11108 pm_parser_warn_token(parser, &parser->current, PM_WARN_DOT_DOT_DOT_EOL);
11111 lex_state_set(parser, PM_LEX_STATE_BEG);
11112 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11115 lex_state_set(parser, PM_LEX_STATE_BEG);
11116 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11119 lex_state_set(parser, PM_LEX_STATE_DOT);
11134 pm_token_type_t
type = lex_numeric(parser);
11135 lex_state_set(parser, PM_LEX_STATE_END);
11141 if (match(parser,
':')) {
11142 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)) {
11143 lex_state_set(parser, PM_LEX_STATE_BEG);
11144 LEX(PM_TOKEN_UCOLON_COLON);
11147 lex_state_set(parser, PM_LEX_STATE_DOT);
11148 LEX(PM_TOKEN_COLON_COLON);
11151 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11152 lex_state_set(parser, PM_LEX_STATE_BEG);
11153 LEX(PM_TOKEN_COLON);
11156 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11157 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->current.end);
11158 parser->current.end++;
11165 parser->explicit_encoding = NULL;
11168 lex_state_set(parser, PM_LEX_STATE_FNAME);
11169 LEX(PM_TOKEN_SYMBOL_BEGIN);
11173 if (lex_state_beg_p(parser)) {
11174 lex_mode_push_regexp(parser,
'\0',
'/');
11175 LEX(PM_TOKEN_REGEXP_BEGIN);
11178 if (match(parser,
'=')) {
11179 lex_state_set(parser, PM_LEX_STATE_BEG);
11180 LEX(PM_TOKEN_SLASH_EQUAL);
11183 if (lex_state_spcarg_p(parser, space_seen)) {
11185 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_4_0) {
11186 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
11188 lex_mode_push_regexp(parser,
'\0',
'/');
11189 LEX(PM_TOKEN_REGEXP_BEGIN);
11192 if (ambiguous_operator_p(parser, space_seen)) {
11193 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11196 if (lex_state_operator_p(parser)) {
11197 lex_state_set(parser, PM_LEX_STATE_ARG);
11199 lex_state_set(parser, PM_LEX_STATE_BEG);
11202 LEX(PM_TOKEN_SLASH);
11206 if (lex_state_operator_p(parser)) {
11207 lex_state_set(parser, PM_LEX_STATE_ARG);
11209 lex_state_set(parser, PM_LEX_STATE_BEG);
11211 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11215 if (lex_state_operator_p(parser)) {
11216 (void) match(parser,
'@');
11217 lex_state_set(parser, PM_LEX_STATE_ARG);
11219 lex_state_set(parser, PM_LEX_STATE_BEG);
11222 LEX(PM_TOKEN_TILDE);
11230 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
11231 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11232 LEX(PM_TOKEN_PERCENT);
11235 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11236 lex_state_set(parser, PM_LEX_STATE_BEG);
11237 LEX(PM_TOKEN_PERCENT_EQUAL);
11239 lex_state_beg_p(parser) ||
11240 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11241 lex_state_spcarg_p(parser, space_seen)
11243 if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) {
11244 if (*parser->current.end >= 0x80) {
11245 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11246 goto lex_next_token;
11249 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11250 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11251 LEX(PM_TOKEN_STRING_BEGIN);
11256 uint8_t delimiter = peek_offset(parser, 1);
11257 if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) {
11258 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11259 goto lex_next_token;
11262 switch (peek(parser)) {
11264 parser->current.end++;
11266 if (parser->current.end < parser->end) {
11267 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11269 lex_mode_push_list_eof(parser);
11272 LEX(PM_TOKEN_PERCENT_LOWER_I);
11275 parser->current.end++;
11277 if (parser->current.end < parser->end) {
11278 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11280 lex_mode_push_list_eof(parser);
11283 LEX(PM_TOKEN_PERCENT_UPPER_I);
11286 parser->current.end++;
11288 if (parser->current.end < parser->end) {
11289 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11290 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11292 lex_mode_push_regexp(parser,
'\0',
'\0');
11295 LEX(PM_TOKEN_REGEXP_BEGIN);
11298 parser->current.end++;
11300 if (parser->current.end < parser->end) {
11301 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11302 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11304 lex_mode_push_string_eof(parser);
11307 LEX(PM_TOKEN_STRING_BEGIN);
11310 parser->current.end++;
11312 if (parser->current.end < parser->end) {
11313 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11314 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11316 lex_mode_push_string_eof(parser);
11319 LEX(PM_TOKEN_STRING_BEGIN);
11322 parser->current.end++;
11324 if (parser->current.end < parser->end) {
11325 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11326 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11327 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11329 lex_mode_push_string_eof(parser);
11332 LEX(PM_TOKEN_SYMBOL_BEGIN);
11335 parser->current.end++;
11337 if (parser->current.end < parser->end) {
11338 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11340 lex_mode_push_list_eof(parser);
11343 LEX(PM_TOKEN_PERCENT_LOWER_W);
11346 parser->current.end++;
11348 if (parser->current.end < parser->end) {
11349 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11351 lex_mode_push_list_eof(parser);
11354 LEX(PM_TOKEN_PERCENT_UPPER_W);
11357 parser->current.end++;
11359 if (parser->current.end < parser->end) {
11360 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11361 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11363 lex_mode_push_string_eof(parser);
11366 LEX(PM_TOKEN_PERCENT_LOWER_X);
11373 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11374 goto lex_next_token;
11378 if (ambiguous_operator_p(parser, space_seen)) {
11379 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11382 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11383 LEX(PM_TOKEN_PERCENT);
11388 pm_token_type_t
type = lex_global_variable(parser);
11392 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
11393 lex_mode_pop(parser);
11396 lex_state_set(parser, PM_LEX_STATE_END);
11402 lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11403 LEX(lex_at_variable(parser));
11406 if (*parser->current.start !=
'_') {
11407 size_t width = char_is_identifier_start(parser, parser->current.start, parser->end - parser->current.start);
11414 if (*parser->current.start >= 0x80) {
11415 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
11416 }
else if (*parser->current.start ==
'\\') {
11417 switch (peek_at(parser, parser->current.start + 1)) {
11419 parser->current.end++;
11420 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11423 parser->current.end++;
11424 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11427 parser->current.end++;
11428 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11431 parser->current.end++;
11432 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11435 if (peek_at(parser, parser->current.start + 2) !=
'\n') {
11436 parser->current.end++;
11437 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11442 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11445 }
else if (char_is_ascii_printable(*parser->current.start)) {
11446 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
11448 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
11451 goto lex_next_token;
11454 parser->current.end = parser->current.start + width;
11457 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11464 ((parser->current.end - parser->current.start) == 7) &&
11465 current_token_starts_line(parser) &&
11466 (memcmp(parser->current.start,
"__END__", 7) == 0) &&
11467 (parser->current.end == parser->end || match_eol(parser))
11472 const uint8_t *cursor = parser->current.end;
11473 while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
11474 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
11477 parser->current.end = parser->end;
11478 parser->current.type = PM_TOKEN___END__;
11479 parser_lex_callback(parser);
11481 parser->data_loc.
start = PM_TOKEN_START(parser, &parser->current);
11482 parser->data_loc.
length = PM_TOKEN_LENGTH(&parser->current);
11487 pm_lex_state_t last_state = parser->lex_state;
11489 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11490 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11491 if (previous_command_start) {
11492 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11494 lex_state_set(parser, PM_LEX_STATE_ARG);
11496 }
else if (parser->lex_state == PM_LEX_STATE_FNAME) {
11497 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11499 lex_state_set(parser, PM_LEX_STATE_END);
11504 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11505 (
type == PM_TOKEN_IDENTIFIER) &&
11506 ((pm_parser_local_depth(parser, &parser->current) != -1) ||
11507 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
11509 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11516 case PM_LEX_LIST: {
11517 if (parser->next_start != NULL) {
11518 parser->current.end = parser->next_start;
11519 parser->next_start = NULL;
11523 parser->current.start = parser->current.end;
11531 if (parser->heredoc_end) {
11532 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11533 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11536 }
else if (lex_mode->as.list.terminator ==
'\n') {
11541 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11543 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));
11546 if (whitespace > 0) {
11547 parser->current.end += whitespace;
11548 if (peek_offset(parser, -1) ==
'\n') {
11550 parser_flush_heredoc_end(parser);
11552 LEX(PM_TOKEN_WORDS_SEP);
11557 if (parser->current.end >= parser->end) {
11563 const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
11564 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11570 while (breakpoint != NULL) {
11575 if (pm_char_is_whitespace(*breakpoint) && *breakpoint != lex_mode->as.list.terminator) {
11576 parser->current.end = breakpoint;
11577 pm_token_buffer_flush(parser, &token_buffer);
11578 LEX(PM_TOKEN_STRING_CONTENT);
11583 if (*breakpoint == lex_mode->as.list.terminator) {
11586 if (lex_mode->as.list.nesting > 0) {
11587 parser->current.end = breakpoint + 1;
11588 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11589 lex_mode->as.list.nesting--;
11595 if (breakpoint > parser->current.start) {
11596 parser->current.end = breakpoint;
11597 pm_token_buffer_flush(parser, &token_buffer);
11598 LEX(PM_TOKEN_STRING_CONTENT);
11603 parser->current.end = breakpoint + 1;
11608 if (*breakpoint ==
'\n') {
11609 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11612 lex_mode_pop(parser);
11613 lex_state_set(parser, PM_LEX_STATE_END);
11614 LEX(PM_TOKEN_STRING_END);
11618 if (*breakpoint ==
'\0') {
11619 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1),
true);
11626 if (*breakpoint ==
'\\') {
11627 parser->current.end = breakpoint + 1;
11631 if (parser->current.end == parser->end) {
11636 pm_token_buffer_escape(parser, &token_buffer);
11637 uint8_t peeked = peek(parser);
11645 pm_token_buffer_push_byte(&token_buffer, peeked);
11646 parser->current.end++;
11649 parser->current.end++;
11650 if (peek(parser) !=
'\n') {
11651 pm_token_buffer_push_byte(&token_buffer,
'\r');
11656 pm_token_buffer_push_byte(&token_buffer,
'\n');
11658 if (parser->heredoc_end) {
11662 parser_flush_heredoc_end(parser);
11663 pm_token_buffer_copy(parser, &token_buffer);
11664 LEX(PM_TOKEN_STRING_CONTENT);
11667 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11670 parser->current.end++;
11673 if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
11674 pm_token_buffer_push_byte(&token_buffer, peeked);
11675 parser->current.end++;
11676 }
else if (lex_mode->as.list.interpolation) {
11677 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11679 pm_token_buffer_push_byte(&token_buffer,
'\\');
11680 pm_token_buffer_push_escaped(&token_buffer, parser);
11686 token_buffer.
cursor = parser->current.end;
11687 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11692 if (*breakpoint ==
'#') {
11693 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11700 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11704 if (
type == PM_TOKEN_STRING_CONTENT) {
11705 pm_token_buffer_flush(parser, &token_buffer);
11713 assert(*breakpoint == lex_mode->as.list.incrementor);
11714 parser->current.end = breakpoint + 1;
11715 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11716 lex_mode->as.list.nesting++;
11720 if (parser->current.end > parser->current.start) {
11721 pm_token_buffer_flush(parser, &token_buffer);
11722 LEX(PM_TOKEN_STRING_CONTENT);
11727 parser->current.end = parser->end;
11728 pm_token_buffer_flush(parser, &token_buffer);
11729 LEX(PM_TOKEN_STRING_CONTENT);
11731 case PM_LEX_REGEXP: {
11733 if (parser->next_start == NULL) {
11734 parser->current.start = parser->current.end;
11736 parser->current.start = parser->next_start;
11737 parser->current.end = parser->next_start;
11738 parser->next_start = NULL;
11743 if (parser->current.end >= parser->end) {
11753 const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
11754 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11757 while (breakpoint != NULL) {
11758 uint8_t term = lex_mode->as.regexp.terminator;
11759 bool is_terminator = (*breakpoint == term);
11764 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11765 if (term ==
'\n') {
11766 is_terminator =
true;
11772 if (term ==
'\r') {
11773 is_terminator =
false;
11779 if (is_terminator) {
11780 if (lex_mode->as.regexp.nesting > 0) {
11781 parser->current.end = breakpoint + 1;
11782 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11783 lex_mode->as.regexp.nesting--;
11790 if (breakpoint > parser->current.start) {
11791 parser->current.end = breakpoint;
11792 pm_regexp_token_buffer_flush(parser, &token_buffer);
11793 LEX(PM_TOKEN_STRING_CONTENT);
11797 size_t eol_length = match_eol_at(parser, breakpoint);
11799 parser->current.end = breakpoint + eol_length;
11804 if (parser->heredoc_end == NULL) {
11805 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11808 parser->current.end = breakpoint + 1;
11813 parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
11815 lex_mode_pop(parser);
11816 lex_state_set(parser, PM_LEX_STATE_END);
11817 LEX(PM_TOKEN_REGEXP_END);
11822 if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
11823 parser->current.end = breakpoint + 1;
11824 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11825 lex_mode->as.regexp.nesting++;
11829 switch (*breakpoint) {
11832 parser->current.end = breakpoint + 1;
11833 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11836 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11837 parser->current.end = breakpoint + 1;
11838 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11843 parser->current.end = breakpoint;
11844 pm_regexp_token_buffer_escape(parser, &token_buffer);
11851 if (parser->heredoc_end == NULL) {
11852 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
11853 parser->current.end = breakpoint + 1;
11854 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11858 parser->current.end = breakpoint + 1;
11859 parser_flush_heredoc_end(parser);
11860 pm_regexp_token_buffer_flush(parser, &token_buffer);
11861 LEX(PM_TOKEN_STRING_CONTENT);
11866 parser->current.end = breakpoint + 1;
11870 if (parser->current.end == parser->end) {
11875 pm_regexp_token_buffer_escape(parser, &token_buffer);
11876 uint8_t peeked = peek(parser);
11880 parser->current.end++;
11881 if (peek(parser) !=
'\n') {
11882 if (lex_mode->as.regexp.terminator !=
'\r') {
11883 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11885 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11886 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11891 if (parser->heredoc_end) {
11895 parser_flush_heredoc_end(parser);
11896 pm_regexp_token_buffer_copy(parser, &token_buffer);
11897 LEX(PM_TOKEN_STRING_CONTENT);
11900 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11903 parser->current.end++;
11913 if (lex_mode->as.regexp.terminator == peeked) {
11918 case '$':
case ')':
case '*':
case '+':
11919 case '.':
case '>':
case '?':
case ']':
11920 case '^':
case '|':
case '}':
11921 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11927 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11928 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11929 parser->current.end++;
11933 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11934 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11938 token_buffer.
base.
cursor = parser->current.end;
11939 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11945 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11952 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11956 if (
type == PM_TOKEN_STRING_CONTENT) {
11957 pm_regexp_token_buffer_flush(parser, &token_buffer);
11963 assert(
false &&
"unreachable");
11968 if (parser->current.end > parser->current.start) {
11969 pm_regexp_token_buffer_flush(parser, &token_buffer);
11970 LEX(PM_TOKEN_STRING_CONTENT);
11975 parser->current.end = parser->end;
11976 pm_regexp_token_buffer_flush(parser, &token_buffer);
11977 LEX(PM_TOKEN_STRING_CONTENT);
11979 case PM_LEX_STRING: {
11981 if (parser->next_start == NULL) {
11982 parser->current.start = parser->current.end;
11984 parser->current.start = parser->next_start;
11985 parser->current.end = parser->next_start;
11986 parser->next_start = NULL;
11991 if (parser->current.end >= parser->end) {
11998 const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
11999 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12005 while (breakpoint != NULL) {
12008 if (lex_mode->as.string.incrementor !=
'\0' && *breakpoint == lex_mode->as.string.incrementor) {
12009 lex_mode->as.string.nesting++;
12010 parser->current.end = breakpoint + 1;
12011 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12015 uint8_t term = lex_mode->as.string.terminator;
12016 bool is_terminator = (*breakpoint == term);
12021 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12022 if (term ==
'\n') {
12023 is_terminator =
true;
12029 if (term ==
'\r') {
12030 is_terminator =
false;
12037 if (is_terminator) {
12040 if (lex_mode->as.string.nesting > 0) {
12041 parser->current.end = breakpoint + 1;
12042 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12043 lex_mode->as.string.nesting--;
12049 if (breakpoint > parser->current.start) {
12050 parser->current.end = breakpoint;
12051 pm_token_buffer_flush(parser, &token_buffer);
12052 LEX(PM_TOKEN_STRING_CONTENT);
12057 size_t eol_length = match_eol_at(parser, breakpoint);
12059 parser->current.end = breakpoint + eol_length;
12064 if (parser->heredoc_end == NULL) {
12065 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
12068 parser->current.end = breakpoint + 1;
12071 if (lex_mode->as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12072 parser->current.end++;
12073 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12074 lex_mode_pop(parser);
12075 LEX(PM_TOKEN_LABEL_END);
12081 if (term ==
'\n' && parser->heredoc_end) {
12082 parser_flush_heredoc_end(parser);
12085 lex_state_set(parser, PM_LEX_STATE_END);
12086 lex_mode_pop(parser);
12087 LEX(PM_TOKEN_STRING_END);
12090 switch (*breakpoint) {
12093 parser->current.end = breakpoint + 1;
12094 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12097 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12098 parser->current.end = breakpoint + 1;
12099 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12106 parser->current.end = breakpoint;
12107 pm_token_buffer_escape(parser, &token_buffer);
12108 token_buffer.
cursor = breakpoint;
12116 if (parser->heredoc_end == NULL) {
12117 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12118 parser->current.end = breakpoint + 1;
12119 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12123 parser->current.end = breakpoint + 1;
12124 parser_flush_heredoc_end(parser);
12125 pm_token_buffer_flush(parser, &token_buffer);
12126 LEX(PM_TOKEN_STRING_CONTENT);
12129 parser->current.end = breakpoint + 1;
12133 if (parser->current.end == parser->end) {
12138 pm_token_buffer_escape(parser, &token_buffer);
12139 uint8_t peeked = peek(parser);
12143 pm_token_buffer_push_byte(&token_buffer,
'\\');
12144 parser->current.end++;
12147 parser->current.end++;
12148 if (peek(parser) !=
'\n') {
12149 if (!lex_mode->as.string.interpolation) {
12150 pm_token_buffer_push_byte(&token_buffer,
'\\');
12152 pm_token_buffer_push_byte(&token_buffer,
'\r');
12157 if (!lex_mode->as.string.interpolation) {
12158 pm_token_buffer_push_byte(&token_buffer,
'\\');
12159 pm_token_buffer_push_byte(&token_buffer,
'\n');
12162 if (parser->heredoc_end) {
12166 parser_flush_heredoc_end(parser);
12167 pm_token_buffer_copy(parser, &token_buffer);
12168 LEX(PM_TOKEN_STRING_CONTENT);
12171 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
12174 parser->current.end++;
12177 if (lex_mode->as.string.incrementor !=
'\0' && peeked == lex_mode->as.string.incrementor) {
12178 pm_token_buffer_push_byte(&token_buffer, peeked);
12179 parser->current.end++;
12180 }
else if (lex_mode->as.string.terminator !=
'\0' && peeked == lex_mode->as.string.terminator) {
12181 pm_token_buffer_push_byte(&token_buffer, peeked);
12182 parser->current.end++;
12183 }
else if (lex_mode->as.string.interpolation) {
12184 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12186 pm_token_buffer_push_byte(&token_buffer,
'\\');
12187 pm_token_buffer_push_escaped(&token_buffer, parser);
12193 token_buffer.
cursor = parser->current.end;
12194 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12198 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12205 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12209 if (
type == PM_TOKEN_STRING_CONTENT) {
12210 pm_token_buffer_flush(parser, &token_buffer);
12216 assert(
false &&
"unreachable");
12220 if (parser->current.end > parser->current.start) {
12221 pm_token_buffer_flush(parser, &token_buffer);
12222 LEX(PM_TOKEN_STRING_CONTENT);
12227 parser->current.end = parser->end;
12228 pm_token_buffer_flush(parser, &token_buffer);
12229 LEX(PM_TOKEN_STRING_CONTENT);
12231 case PM_LEX_HEREDOC: {
12233 if (parser->next_start == NULL) {
12234 parser->current.start = parser->current.end;
12236 parser->current.start = parser->next_start;
12237 parser->current.end = parser->next_start;
12238 parser->heredoc_end = NULL;
12239 parser->next_start = NULL;
12247 bool line_continuation = lex_mode->as.heredoc.line_continuation;
12248 lex_mode->as.heredoc.line_continuation =
false;
12254 if (parser->current.end >= parser->end) {
12255 pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
12256 parser->next_start = lex_mode->as.heredoc.next_start;
12257 parser->heredoc_end = parser->current.end;
12258 lex_state_set(parser, PM_LEX_STATE_END);
12259 lex_mode_pop(parser);
12260 LEX(PM_TOKEN_HEREDOC_END);
12263 const uint8_t *ident_start = heredoc_lex_mode->ident_start;
12264 size_t ident_length = heredoc_lex_mode->ident_length;
12268 if (current_token_starts_line(parser)) {
12269 const uint8_t *start = parser->current.start;
12271 if (!line_continuation && (start + ident_length <= parser->end)) {
12272 const uint8_t *newline = next_newline(start, parser->end - start);
12273 const uint8_t *ident_end = newline;
12274 const uint8_t *terminator_end = newline;
12276 if (newline == NULL) {
12277 terminator_end = parser->end;
12278 ident_end = parser->end;
12281 if (newline[-1] ==
'\r') {
12286 const uint8_t *terminator_start = ident_end - ident_length;
12287 const uint8_t *cursor = start;
12289 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12290 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12296 (cursor == terminator_start) &&
12297 (memcmp(terminator_start, ident_start, ident_length) == 0)
12299 if (newline != NULL) {
12300 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
12303 parser->current.end = terminator_end;
12304 if (*lex_mode->as.heredoc.next_start ==
'\\') {
12305 parser->next_start = NULL;
12307 parser->next_start = lex_mode->as.heredoc.next_start;
12308 parser->heredoc_end = parser->current.end;
12311 lex_state_set(parser, PM_LEX_STATE_END);
12312 lex_mode_pop(parser);
12313 LEX(PM_TOKEN_HEREDOC_END);
12317 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
12319 heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
12320 lex_mode->as.heredoc.common_whitespace != NULL &&
12321 (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
12322 peek_at(parser, start) !=
'\n'
12324 *lex_mode->as.heredoc.common_whitespace = whitespace;
12331 uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] =
"\r\n\\#";
12333 pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
12334 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12335 breakpoints[3] =
'\0';
12338 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12340 bool was_line_continuation =
false;
12342 while (breakpoint != NULL) {
12343 switch (*breakpoint) {
12346 parser->current.end = breakpoint + 1;
12347 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12350 parser->current.end = breakpoint + 1;
12352 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12353 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12360 pm_token_buffer_escape(parser, &token_buffer);
12361 token_buffer.
cursor = breakpoint;
12365 if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
12366 parser_flush_heredoc_end(parser);
12367 parser->current.end = breakpoint + 1;
12368 pm_token_buffer_flush(parser, &token_buffer);
12369 LEX(PM_TOKEN_STRING_CONTENT);
12372 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12376 const uint8_t *start = breakpoint + 1;
12378 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12381 const uint8_t *newline = next_newline(start, parser->end - start);
12383 if (newline == NULL) {
12384 newline = parser->end;
12385 }
else if (newline[-1] ==
'\r') {
12390 const uint8_t *terminator_start = newline - ident_length;
12394 const uint8_t *cursor = start;
12396 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12397 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12403 cursor == terminator_start &&
12404 (memcmp(terminator_start, ident_start, ident_length) == 0)
12406 parser->current.end = breakpoint + 1;
12407 pm_token_buffer_flush(parser, &token_buffer);
12408 LEX(PM_TOKEN_STRING_CONTENT);
12412 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
12419 if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12420 if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12421 *lex_mode->as.heredoc.common_whitespace = whitespace;
12424 parser->current.end = breakpoint + 1;
12425 pm_token_buffer_flush(parser, &token_buffer);
12426 LEX(PM_TOKEN_STRING_CONTENT);
12431 parser->current.end = breakpoint + 1;
12432 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12442 parser->current.end = breakpoint + 1;
12446 if (parser->current.end == parser->end) {
12451 pm_token_buffer_escape(parser, &token_buffer);
12452 uint8_t peeked = peek(parser);
12454 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12457 parser->current.end++;
12458 if (peek(parser) !=
'\n') {
12459 pm_token_buffer_push_byte(&token_buffer,
'\\');
12460 pm_token_buffer_push_byte(&token_buffer,
'\r');
12465 pm_token_buffer_push_byte(&token_buffer,
'\\');
12466 pm_token_buffer_push_byte(&token_buffer,
'\n');
12467 token_buffer.
cursor = parser->current.end + 1;
12468 breakpoint = parser->current.end;
12471 pm_token_buffer_push_byte(&token_buffer,
'\\');
12472 pm_token_buffer_push_escaped(&token_buffer, parser);
12478 parser->current.end++;
12479 if (peek(parser) !=
'\n') {
12480 pm_token_buffer_push_byte(&token_buffer,
'\r');
12488 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12489 const uint8_t *end = parser->current.end;
12491 if (parser->heredoc_end == NULL) {
12492 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
12497 parser->current.end = breakpoint;
12498 pm_token_buffer_flush(parser, &token_buffer);
12502 parser->current.end = end + 1;
12503 lex_mode->as.heredoc.line_continuation =
true;
12504 LEX(PM_TOKEN_STRING_CONTENT);
12507 was_line_continuation =
true;
12508 token_buffer.
cursor = parser->current.end + 1;
12509 breakpoint = parser->current.end;
12512 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12517 token_buffer.
cursor = parser->current.end;
12518 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12522 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12530 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12534 if (
type == PM_TOKEN_STRING_CONTENT) {
12535 pm_token_buffer_flush(parser, &token_buffer);
12541 assert(
false &&
"unreachable");
12544 was_line_continuation =
false;
12547 if (parser->current.end > parser->current.start) {
12548 parser->current.end = parser->end;
12549 pm_token_buffer_flush(parser, &token_buffer);
12550 LEX(PM_TOKEN_STRING_CONTENT);
12555 parser->current.end = parser->end;
12556 pm_token_buffer_flush(parser, &token_buffer);
12557 LEX(PM_TOKEN_STRING_CONTENT);
12561 assert(
false &&
"unreachable");
12579 PM_BINDING_POWER_UNSET = 0,
12580 PM_BINDING_POWER_STATEMENT = 2,
12581 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12582 PM_BINDING_POWER_MODIFIER = 6,
12583 PM_BINDING_POWER_COMPOSITION = 8,
12584 PM_BINDING_POWER_NOT = 10,
12585 PM_BINDING_POWER_MATCH = 12,
12586 PM_BINDING_POWER_DEFINED = 14,
12587 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12588 PM_BINDING_POWER_ASSIGNMENT = 18,
12589 PM_BINDING_POWER_TERNARY = 20,
12590 PM_BINDING_POWER_RANGE = 22,
12591 PM_BINDING_POWER_LOGICAL_OR = 24,
12592 PM_BINDING_POWER_LOGICAL_AND = 26,
12593 PM_BINDING_POWER_EQUALITY = 28,
12594 PM_BINDING_POWER_COMPARISON = 30,
12595 PM_BINDING_POWER_BITWISE_OR = 32,
12596 PM_BINDING_POWER_BITWISE_AND = 34,
12597 PM_BINDING_POWER_SHIFT = 36,
12598 PM_BINDING_POWER_TERM = 38,
12599 PM_BINDING_POWER_FACTOR = 40,
12600 PM_BINDING_POWER_UMINUS = 42,
12601 PM_BINDING_POWER_EXPONENT = 44,
12602 PM_BINDING_POWER_UNARY = 46,
12603 PM_BINDING_POWER_INDEX = 48,
12604 PM_BINDING_POWER_CALL = 50,
12605 PM_BINDING_POWER_MAX = 52
12606} pm_binding_power_t;
12629#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12630#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12631#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12632#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12633#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12637 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12640 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12641 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12642 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12643 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12646 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12647 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12650 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12651 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12654 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12655 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12656 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12657 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12658 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12659 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12660 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12661 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12662 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12663 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12664 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12665 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12666 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12667 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12670 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12673 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12674 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12675 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12676 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12679 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12682 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12685 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12686 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12687 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12688 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12689 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12690 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12693 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12694 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12695 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12696 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12699 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12700 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12703 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12706 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12707 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12710 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12711 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12714 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12715 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12716 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12717 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12720 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12721 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12724 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12725 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12728 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12729 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12730 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12733 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12736 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12737 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12738 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12741#undef BINDING_POWER_ASSIGNMENT
12742#undef LEFT_ASSOCIATIVE
12743#undef RIGHT_ASSOCIATIVE
12744#undef RIGHT_ASSOCIATIVE_UNARY
12751 return parser->current.type ==
type;
12758match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12759 return match1(parser, type1) || match1(parser, type2);
12766match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12767 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12774match4(
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) {
12775 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12782match5(
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) {
12783 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5);
12790match6(
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) {
12791 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
12798match8(
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) {
12799 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);
12810 if (match1(parser,
type)) {
12811 parser_lex(parser);
12822accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12823 if (match2(parser, type1, type2)) {
12824 parser_lex(parser);
12842expect1(
pm_parser_t *parser, pm_token_type_t
type, pm_diagnostic_id_t diag_id) {
12843 if (accept1(parser,
type))
return;
12845 const uint8_t *location = parser->previous.
end;
12846 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12848 parser->previous.
start = location;
12849 parser->previous.
type = 0;
12857expect2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
12858 if (accept2(parser, type1, type2))
return;
12860 const uint8_t *location = parser->previous.
end;
12861 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12863 parser->previous.
start = location;
12864 parser->previous.
type = 0;
12872expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12873 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12874 parser_lex(parser);
12876 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12877 parser->previous.
start = parser->previous.
end;
12878 parser->previous.
type = 0;
12890 if (accept1(parser,
type))
return;
12892 const uint8_t *start = opening->
start;
12893 pm_parser_err(parser, U32(start - parser->start), U32(opening->
end - start), diag_id);
12895 parser->previous.
start = parser->previous.
end;
12896 parser->previous.
type = 0;
12900#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
12901#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
12902#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
12903#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
12914#define PM_PARSE_ACCEPTS_STATEMENT ((uint8_t) 0x10)
12917parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
12924parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
12925 pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
12926 pm_assert_value_expression(parser, node);
12949token_begins_expression_p(pm_token_type_t
type) {
12951 case PM_TOKEN_EQUAL_GREATER:
12952 case PM_TOKEN_KEYWORD_IN:
12956 case PM_TOKEN_BRACE_RIGHT:
12957 case PM_TOKEN_BRACKET_RIGHT:
12958 case PM_TOKEN_COLON:
12959 case PM_TOKEN_COMMA:
12960 case PM_TOKEN_EMBEXPR_END:
12962 case PM_TOKEN_LAMBDA_BEGIN:
12963 case PM_TOKEN_KEYWORD_DO:
12964 case PM_TOKEN_KEYWORD_DO_BLOCK:
12965 case PM_TOKEN_KEYWORD_DO_LAMBDA:
12966 case PM_TOKEN_KEYWORD_DO_LOOP:
12967 case PM_TOKEN_KEYWORD_END:
12968 case PM_TOKEN_KEYWORD_ELSE:
12969 case PM_TOKEN_KEYWORD_ELSIF:
12970 case PM_TOKEN_KEYWORD_ENSURE:
12971 case PM_TOKEN_KEYWORD_THEN:
12972 case PM_TOKEN_KEYWORD_RESCUE:
12973 case PM_TOKEN_KEYWORD_WHEN:
12974 case PM_TOKEN_NEWLINE:
12975 case PM_TOKEN_PARENTHESIS_RIGHT:
12976 case PM_TOKEN_SEMICOLON:
12982 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12984 case PM_TOKEN_UAMPERSAND:
12988 case PM_TOKEN_UCOLON_COLON:
12989 case PM_TOKEN_UMINUS:
12990 case PM_TOKEN_UMINUS_NUM:
12991 case PM_TOKEN_UPLUS:
12992 case PM_TOKEN_BANG:
12993 case PM_TOKEN_TILDE:
12994 case PM_TOKEN_UDOT_DOT:
12995 case PM_TOKEN_UDOT_DOT_DOT:
13002 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13022token_begins_pattern_p(pm_token_type_t
type) {
13024 token_begins_expression_p(
type) ||
13025 type == PM_TOKEN_USTAR ||
13026 type == PM_TOKEN_USTAR_STAR ||
13027 type == PM_TOKEN_CARET
13036parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
13037 if (accept1(parser, PM_TOKEN_USTAR)) {
13039 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));
13040 return UP(pm_splat_node_create(parser, &
operator, expression));
13043 return parse_value_expression(parser, binding_power, flags, diag_id, depth);
13047pm_node_unreference_each(
const pm_node_t *node,
void *data) {
13048 switch (PM_NODE_TYPE(node)) {
13053 case PM_BREAK_NODE:
13055 case PM_REDO_NODE: {
13059 while (index < parser->current_block_exits->size) {
13060 pm_node_t *block_exit = parser->current_block_exits->
nodes[index];
13062 if (block_exit == node) {
13063 if (index + 1 < parser->current_block_exits->
size) {
13065 &parser->current_block_exits->
nodes[index],
13066 &parser->current_block_exits->
nodes[index + 1],
13067 (parser->current_block_exits->
size - index - 1) *
sizeof(
pm_node_t *)
13070 parser->current_block_exits->
size--;
13085 case PM_LOCAL_VARIABLE_READ_NODE:
13086 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13088 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
13090 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13091 if (implicit_parameters->
nodes[index] == node) {
13095 if (index != implicit_parameters->
size - 1) {
13096 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13099 implicit_parameters->
size--;
13118 pm_visit_node(node, pm_node_unreference_each, parser);
13131 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *name_field);
13132 size_t length = constant->length;
13133 uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
13135 memcpy(name, constant->start, length);
13136 name[length] =
'=';
13138 *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
13149 switch (PM_NODE_TYPE(target)) {
13150 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13151 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13152 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13153 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13154 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13155 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13156 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13160 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
13176 switch (PM_NODE_TYPE(target)) {
13177 case PM_ERROR_RECOVERY_NODE:
13179 case PM_SOURCE_ENCODING_NODE:
13180 case PM_FALSE_NODE:
13181 case PM_SOURCE_FILE_NODE:
13182 case PM_SOURCE_LINE_NODE:
13185 case PM_TRUE_NODE: {
13188 return parse_unwriteable_target(parser, target);
13190 case PM_CLASS_VARIABLE_READ_NODE:
13192 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13194 case PM_CONSTANT_PATH_NODE:
13195 if (context_def_p(parser)) {
13196 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13200 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13203 case PM_CONSTANT_READ_NODE:
13204 if (context_def_p(parser)) {
13205 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13209 target->
type = PM_CONSTANT_TARGET_NODE;
13212 case PM_BACK_REFERENCE_READ_NODE:
13213 case PM_NUMBERED_REFERENCE_READ_NODE:
13214 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13215 return UP(pm_error_recovery_node_create_unexpected(parser, target));
13216 case PM_GLOBAL_VARIABLE_READ_NODE:
13218 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13220 case PM_LOCAL_VARIABLE_READ_NODE: {
13221 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13222 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
13223 pm_node_unreference(parser, target);
13227 uint32_t name = cast->
name;
13228 uint32_t depth = cast->
depth;
13229 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13232 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13236 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13238 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
13240 pm_node_unreference(parser, target);
13244 case PM_INSTANCE_VARIABLE_READ_NODE:
13246 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13248 case PM_MULTI_TARGET_NODE:
13249 if (splat_parent) {
13252 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13256 case PM_SPLAT_NODE: {
13265 case PM_CALL_NODE: {
13277 (call->
block == NULL)
13290 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
13292 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
13296 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13297 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13300 parse_write_name(parser, &call->
name);
13301 return UP(pm_call_target_node_create(parser, call));
13308 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13309 return UP(pm_index_target_node_create(parser, call));
13317 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13328 pm_node_t *result = parse_target(parser, target, multiple,
false);
13333 !match1(parser, PM_TOKEN_EQUAL) &&
13334 !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
13335 !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13337 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13349 pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
13351 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13352 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
13363 switch (PM_NODE_TYPE(target)) {
13364 case PM_ERROR_RECOVERY_NODE:
13366 case PM_CLASS_VARIABLE_READ_NODE: {
13370 case PM_CONSTANT_PATH_NODE: {
13373 if (context_def_p(parser)) {
13374 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13377 return parse_shareable_constant_write(parser, node);
13379 case PM_CONSTANT_READ_NODE: {
13382 if (context_def_p(parser)) {
13383 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13386 return parse_shareable_constant_write(parser, node);
13388 case PM_BACK_REFERENCE_READ_NODE:
13389 case PM_NUMBERED_REFERENCE_READ_NODE:
13390 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13392 case PM_GLOBAL_VARIABLE_READ_NODE: {
13396 case PM_LOCAL_VARIABLE_READ_NODE: {
13401 uint32_t depth = local_read->
depth;
13402 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13404 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13405 pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13406 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
13407 pm_node_unreference(parser, target);
13410 pm_locals_unread(&scope->locals, name);
13412 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
13414 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13416 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
13418 pm_node_unreference(parser, target);
13422 case PM_INSTANCE_VARIABLE_READ_NODE: {
13426 case PM_MULTI_TARGET_NODE:
13428 case PM_SPLAT_NODE: {
13436 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
13438 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
13440 case PM_CALL_NODE: {
13452 (call->
block == NULL)
13466 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
13467 pm_parser_local_add_location(parser, &message_loc, 0);
13469 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));
13470 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
13489 pm_arguments_node_arguments_append(parser->arena, arguments, value);
13490 PM_NODE_LENGTH_SET_NODE(call, arguments);
13491 call->
equal_loc = TOK2LOC(parser,
operator);
13493 parse_write_name(parser, &call->
name);
13494 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13503 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13505 call->
arguments = pm_arguments_node_create(parser);
13508 pm_arguments_node_arguments_append(parser->arena, call->
arguments, value);
13509 PM_NODE_LENGTH_SET_NODE(target, value);
13512 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13513 call->
equal_loc = TOK2LOC(parser,
operator);
13517 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13532 pm_node_unreference(parser, value);
13539 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13552 switch (PM_NODE_TYPE(target)) {
13553 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13554 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13555 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13556 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13557 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13558 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13559 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13580parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13581 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13584 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13586 while (accept1(parser, PM_TOKEN_COMMA)) {
13587 if (accept1(parser, PM_TOKEN_USTAR)) {
13592 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13595 pm_token_t star_operator = parser->previous;
13598 if (token_begins_expression_p(parser->current.type)) {
13599 name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13600 name = parse_target(parser, name,
true,
true);
13603 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13604 pm_multi_target_node_targets_append(parser, result, splat);
13606 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
13607 context_push(parser, PM_CONTEXT_MULTI_TARGET);
13608 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13609 target = parse_target(parser, target,
true,
false);
13611 pm_multi_target_node_targets_append(parser, result, target);
13612 context_pop(parser);
13613 }
else if (token_begins_expression_p(parser->current.type)) {
13614 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13615 target = parse_target(parser, target,
true,
false);
13617 pm_multi_target_node_targets_append(parser, result, target);
13618 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13621 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
13622 pm_multi_target_node_targets_append(parser, result, rest);
13635parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13636 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13641 if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
13642 accept1(parser, PM_TOKEN_NEWLINE);
13646 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13647 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13657parse_statements(
pm_parser_t *parser, pm_context_t context, uint16_t depth) {
13660 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13663 if (context_terminator(context, &parser->current))
return NULL;
13669 context_push(parser, context);
13672 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13673 pm_statements_node_body_append(parser, statements, node,
true);
13677 if (parser->recovering) {
13680 if (context_terminator(context, &parser->current)) parser->recovering =
false;
13686 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13689 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13690 if (context_terminator(context, &parser->current))
break;
13700 if (context_terminator(context, &parser->current))
break;
13712 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
13713 parser_lex(parser);
13719 if (match1(parser, PM_TOKEN_EOF)) {
13720 parser->recovering =
true;
13724 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13725 if (context_terminator(context, &parser->current))
break;
13726 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13730 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
13731 parser->previous.
start = parser->previous.
end;
13732 parser->previous.
type = 0;
13736 context_pop(parser);
13738 bool last_value =
true;
13740 case PM_CONTEXT_BEGIN_ENSURE:
13741 case PM_CONTEXT_DEF_ENSURE:
13742 last_value =
false;
13747 pm_void_statements_check(parser, statements, last_value);
13758 pm_static_literal_inspect(&buffer, &parser->line_offsets, parser->start, parser->start_line, parser->encoding, duplicated);
13760 pm_diagnostic_list_append_format(
13761 &parser->metadata_arena,
13762 &parser->warning_list,
13765 PM_WARN_DUPLICATED_HASH_KEY,
13766 (
int) pm_buffer_length(&buffer),
13767 pm_buffer_value(&buffer),
13768 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line
13771 pm_buffer_cleanup(&buffer);
13780 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
true);
13782 if (duplicated != NULL) {
13783 pm_hash_key_duplicated_warn(parser, duplicated, node);
13798 for (
size_t index = 0; index < elements->
size; index++) {
13801 switch (PM_NODE_TYPE(element)) {
13802 case PM_ASSOC_NODE: {
13804 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, key,
true);
13806 if (duplicated != NULL && PM_NODE_START(duplicated) < boundary) {
13807 pm_hash_key_duplicated_warn(parser, duplicated, key);
13812 case PM_ASSOC_SPLAT_NODE: {
13815 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13816 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, boundary);
13835 if ((previous = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
false)) != NULL) {
13836 pm_diagnostic_list_append_format(
13837 &parser->metadata_arena,
13838 &parser->warning_list,
13839 PM_NODE_START(node),
13840 PM_NODE_LENGTH(node),
13841 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13842 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line,
13843 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).
line
13853 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13854 bool contains_keyword_splat =
false;
13859 switch (parser->current.type) {
13860 case PM_TOKEN_USTAR_STAR: {
13861 parser_lex(parser);
13865 if (token_begins_expression_p(parser->current.type)) {
13866 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));
13870 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13871 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, PM_NODE_START(value));
13874 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13877 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13878 contains_keyword_splat =
true;
13881 case PM_TOKEN_LABEL: {
13883 parser_lex(parser);
13885 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13886 pm_hash_key_static_literals_add(parser, literals, key);
13890 if (token_begins_expression_p(parser->current.type)) {
13891 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13893 if (parser->encoding->isupper_char(label.
start, (label.
end - 1) - label.
start)) {
13894 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13895 value = UP(pm_constant_read_node_create(parser, &constant));
13900 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13901 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13903 depth = pm_parser_local_depth(parser, &identifier);
13907 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13909 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13914 value = UP(pm_implicit_node_create(parser, value));
13917 element = UP(pm_assoc_node_create(parser, key, NULL, value));
13921 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));
13925 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13926 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13929 pm_hash_key_static_literals_add(parser, literals, key);
13932 if (!pm_symbol_node_label_p(parser, key)) {
13933 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13934 operator = parser->previous;
13937 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));
13938 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
13943 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13944 pm_hash_node_elements_append(parser->arena, (
pm_hash_node_t *) node, element);
13950 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13954 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13958 if (token_begins_expression_p(parser->current.type))
continue;
13964 return contains_keyword_splat;
13969 if (pm_symbol_node_label_p(parser, argument)) {
13973 switch (PM_NODE_TYPE(argument)) {
13974 case PM_CALL_NODE: {
13977 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13980 if (cast->
block != NULL) {
13988 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
13997 arguments->
arguments = pm_arguments_node_create(parser);
14000 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, argument);
14011 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
14030 call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE) &&
14045 switch (PM_NODE_TYPE(node)) {
14046 case PM_CALL_NODE: {
14051 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)) {
14056 if (pm_constant_path_command_call_p(parser, call)) {
14063 return pm_command_call_value_p(parser, call->
receiver);
14068 case PM_SUPER_NODE: {
14075 !(cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE));
14077 case PM_YIELD_NODE: {
14081 case PM_RESCUE_MODIFIER_NODE:
14083 case PM_DEF_NODE: {
14087 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
14090 return pm_command_call_value_p(parser, body);
14106pm_block_call_p(
const pm_node_t *node) {
14107 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
14138 if (PM_NODE_TYPE_P(node, PM_SUPER_NODE)) {
14150parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
14151 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
14156 match2(parser, terminator, PM_TOKEN_EOF) ||
14157 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14158 context_terminator(parser->current_context->context, &parser->current)
14163 bool parsed_first_argument =
false;
14164 bool parsed_bare_hash =
false;
14165 bool parsed_block_argument =
false;
14166 bool parsed_forwarding_arguments =
false;
14168 while (!match1(parser, PM_TOKEN_EOF)) {
14169 if (parsed_forwarding_arguments) {
14170 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14175 switch (parser->current.type) {
14176 case PM_TOKEN_USTAR_STAR:
14177 case PM_TOKEN_LABEL: {
14178 if (parsed_bare_hash) {
14179 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14183 argument = UP(hash);
14186 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
14188 parse_arguments_append(parser, arguments, argument);
14190 pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14191 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14192 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14194 pm_static_literals_free(&hash_keys);
14195 parsed_bare_hash =
true;
14199 case PM_TOKEN_UAMPERSAND: {
14200 parser_lex(parser);
14204 if (token_begins_expression_p(parser->current.type)) {
14205 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14207 pm_parser_scope_forwarding_block_check(parser, &
operator);
14210 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
14211 if (parsed_block_argument) {
14212 parse_arguments_append(parser, arguments, argument);
14214 arguments->
block = argument;
14217 if (match1(parser, PM_TOKEN_COMMA)) {
14218 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14221 parsed_block_argument =
true;
14224 case PM_TOKEN_USTAR: {
14225 parser_lex(parser);
14228 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14229 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14230 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
14231 if (parsed_bare_hash) {
14232 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14235 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));
14237 if (parsed_bare_hash) {
14238 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);
14241 argument = UP(pm_splat_node_create(parser, &
operator, expression));
14244 parse_arguments_append(parser, arguments, argument);
14247 case PM_TOKEN_UDOT_DOT_DOT: {
14248 if (accepts_forwarding) {
14249 parser_lex(parser);
14251 if (token_begins_expression_p(parser->current.type)) {
14256 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));
14261 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14263 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14266 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
14268 pm_parser_scope_forwarding_all_check(parser, &parser->previous);
14269 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14270 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14273 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->previous));
14274 parse_arguments_append(parser, arguments, argument);
14275 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14277 parsed_forwarding_arguments =
true;
14284 if (argument == NULL) {
14285 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (!parsed_first_argument ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0u) | PM_PARSE_ACCEPTS_LABEL), PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14288 bool contains_keywords =
false;
14289 bool contains_keyword_splat =
false;
14291 if (argument_allowed_for_bare_hash(parser, argument)) {
14292 if (parsed_bare_hash) {
14293 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14302 if (pm_command_call_value_p(parser, argument) || pm_block_call_p(argument)) {
14303 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->previous.
type));
14307 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
14308 operator = parser->previous;
14312 contains_keywords =
true;
14316 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14319 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));
14320 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
14322 pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
14323 argument = UP(bare_hash);
14326 if (accept1(parser, PM_TOKEN_COMMA) && (
14327 token_begins_expression_p(parser->current.type) ||
14328 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14330 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
14333 pm_static_literals_free(&hash_keys);
14334 parsed_bare_hash =
true;
14337 parse_arguments_append(parser, arguments, argument);
14339 pm_node_flags_t node_flags = 0;
14340 if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14341 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14342 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14348 parsed_first_argument =
true;
14351 if (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_NODE) || parser->recovering)
break;
14356 bool accepted_newline =
false;
14357 if (terminator != PM_TOKEN_EOF) {
14358 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14361 if (parser->previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14365 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14368 if (accepted_newline) {
14369 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14375 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
14378 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14390 if (match1(parser, terminator)) {
14396 if (parsed_forwarding_arguments) {
14397 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14416parse_required_destructured_parameter(
pm_parser_t *parser) {
14417 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14420 pm_multi_target_node_opening_set(parser, node, &parser->previous);
14429 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14430 param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14431 pm_multi_target_node_targets_append(parser, node, param);
14432 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14436 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
14437 param = UP(parse_required_destructured_parameter(parser));
14438 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14442 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14444 value = UP(pm_required_parameter_node_create(parser, &name));
14445 if (pm_parser_parameter_name_check(parser, &name)) {
14446 pm_node_flag_set_repeated_parameter(value);
14448 pm_parser_local_add_token(parser, &name, 1);
14451 param = UP(pm_splat_node_create(parser, &star, value));
14453 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14456 param = UP(pm_required_parameter_node_create(parser, &name));
14457 if (pm_parser_parameter_name_check(parser, &name)) {
14458 pm_node_flag_set_repeated_parameter(param);
14460 pm_parser_local_add_token(parser, &name, 1);
14463 pm_multi_target_node_targets_append(parser, node, param);
14464 }
while (accept1(parser, PM_TOKEN_COMMA));
14466 accept1(parser, PM_TOKEN_NEWLINE);
14467 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14468 pm_multi_target_node_closing_set(parser, node, &parser->previous);
14478 PM_PARAMETERS_NO_CHANGE = 0,
14479 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14480 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14481 PM_PARAMETERS_ORDER_KEYWORDS,
14482 PM_PARAMETERS_ORDER_REST,
14483 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14484 PM_PARAMETERS_ORDER_OPTIONAL,
14485 PM_PARAMETERS_ORDER_NAMED,
14486 PM_PARAMETERS_ORDER_NONE,
14487} pm_parameters_order_t;
14492static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14493 [0] = PM_PARAMETERS_NO_CHANGE,
14494 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14495 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14496 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14497 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14498 [PM_TOKEN_PARENTHESIS_LEFT_GROUPING] = PM_PARAMETERS_ORDER_NAMED,
14499 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14500 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14501 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14502 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14503 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14504 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14516 pm_parameters_order_t state = parameters_ordering[token->type];
14517 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14521 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14522 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14524 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14528 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14529 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14531 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14532 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14534 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14536 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14540 if (state < *current) *current = state;
14545parse_parameters_handle_trailing_comma(
14548 pm_parameters_order_t order,
14550 bool allows_trailing_comma
14552 if (!allows_trailing_comma) {
14553 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14558 if (order >= PM_PARAMETERS_ORDER_NAMED) {
14560 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14562 if (params->
rest == NULL) {
14563 pm_parameters_node_rest_set(params, param);
14565 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14566 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14570 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14575 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
14576 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14587 pm_binding_power_t binding_power,
14588 bool uses_parentheses,
14589 bool allows_trailing_comma,
14590 bool allows_forwarding_parameters,
14591 bool accepts_blocks_in_defaults,
14593 pm_diagnostic_id_t diag_id_forwarding,
14596 pm_do_loop_stack_push(parser,
false);
14599 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14602 bool parsing =
true;
14604 switch (parser->current.type) {
14605 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
14606 update_parameter_state(parser, &parser->current, &order);
14607 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
14609 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14610 pm_parameters_node_requireds_append(parser->arena, params, param);
14612 pm_parameters_node_posts_append(parser->arena, params, param);
14616 case PM_TOKEN_UAMPERSAND:
14617 case PM_TOKEN_AMPERSAND: {
14618 update_parameter_state(parser, &parser->current, &order);
14619 parser_lex(parser);
14624 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14625 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->previous);
14629 bool repeated =
false;
14630 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14631 name = parser->previous;
14632 repeated = pm_parser_parameter_name_check(parser, &name);
14633 pm_parser_local_add_token(parser, &name, 1);
14635 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
14638 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
14640 pm_node_flag_set_repeated_parameter(param);
14644 if (params->
block == NULL) {
14645 pm_parameters_node_block_set(params, param);
14647 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
14648 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14653 case PM_TOKEN_UDOT_DOT_DOT: {
14654 if (!allows_forwarding_parameters) {
14655 pm_parser_err_current(parser, diag_id_forwarding);
14658 bool succeeded = update_parameter_state(parser, &parser->current, &order);
14659 parser_lex(parser);
14661 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
14668 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, keyword_rest)));
14669 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14673 pm_parameters_node_keyword_rest_set(params, UP(param));
14676 case PM_TOKEN_CLASS_VARIABLE:
14677 case PM_TOKEN_IDENTIFIER:
14678 case PM_TOKEN_CONSTANT:
14679 case PM_TOKEN_INSTANCE_VARIABLE:
14680 case PM_TOKEN_GLOBAL_VARIABLE:
14681 case PM_TOKEN_METHOD_NAME: {
14682 parser_lex(parser);
14683 switch (parser->previous.
type) {
14684 case PM_TOKEN_CONSTANT:
14685 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14687 case PM_TOKEN_INSTANCE_VARIABLE:
14688 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14690 case PM_TOKEN_GLOBAL_VARIABLE:
14691 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14693 case PM_TOKEN_CLASS_VARIABLE:
14694 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14696 case PM_TOKEN_METHOD_NAME:
14697 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14702 if (parser->current.type == PM_TOKEN_EQUAL) {
14703 update_parameter_state(parser, &parser->current, &order);
14705 update_parameter_state(parser, &parser->previous, &order);
14709 bool repeated = pm_parser_parameter_name_check(parser, &name);
14710 pm_parser_local_add_token(parser, &name, 1);
14712 if (match1(parser, PM_TOKEN_EQUAL)) {
14714 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14715 parser_lex(parser);
14718 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14720 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14721 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14722 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14727 pm_node_flag_set_repeated_parameter(UP(param));
14729 pm_parameters_node_optionals_append(parser->arena, params, param);
14734 if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14735 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
14738 context_pop(parser);
14743 if (parser->recovering) {
14747 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14750 pm_node_flag_set_repeated_parameter(UP(param));
14752 pm_parameters_node_requireds_append(parser->arena, params, UP(param));
14756 pm_node_flag_set_repeated_parameter(UP(param));
14758 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14763 case PM_TOKEN_LABEL: {
14764 if (!uses_parentheses && !in_block) parser->in_keyword_arg =
true;
14765 update_parameter_state(parser, &parser->current, &order);
14767 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14768 parser_lex(parser);
14774 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)) {
14775 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14776 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14777 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14780 bool repeated = pm_parser_parameter_name_check(parser, &local);
14781 pm_parser_local_add_token(parser, &local, 1);
14783 switch (parser->current.type) {
14784 case PM_TOKEN_COMMA:
14785 case PM_TOKEN_PARENTHESIS_RIGHT:
14786 case PM_TOKEN_PIPE: {
14787 context_pop(parser);
14789 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14791 pm_node_flag_set_repeated_parameter(param);
14794 pm_parameters_node_keywords_append(parser->arena, params, param);
14797 case PM_TOKEN_SEMICOLON:
14798 case PM_TOKEN_NEWLINE: {
14799 context_pop(parser);
14801 if (uses_parentheses) {
14806 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14808 pm_node_flag_set_repeated_parameter(param);
14811 pm_parameters_node_keywords_append(parser->arena, params, param);
14817 if (token_begins_expression_p(parser->current.type)) {
14819 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14821 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14822 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));
14823 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14825 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14826 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
14829 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14832 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14836 pm_node_flag_set_repeated_parameter(param);
14839 context_pop(parser);
14840 pm_parameters_node_keywords_append(parser->arena, params, param);
14845 if (parser->recovering) {
14852 parser->in_keyword_arg =
false;
14855 case PM_TOKEN_USTAR:
14856 case PM_TOKEN_STAR: {
14857 update_parameter_state(parser, &parser->current, &order);
14858 parser_lex(parser);
14862 bool repeated =
false;
14864 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14865 name = parser->previous;
14866 repeated = pm_parser_parameter_name_check(parser, &name);
14867 pm_parser_local_add_token(parser, &name, 1);
14869 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
14872 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14874 pm_node_flag_set_repeated_parameter(param);
14877 if (params->
rest == NULL) {
14878 pm_parameters_node_rest_set(params, param);
14880 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14881 pm_parameters_node_posts_append(parser->arena, params, param);
14886 case PM_TOKEN_STAR_STAR:
14887 case PM_TOKEN_USTAR_STAR: {
14888 pm_parameters_order_t previous_order = order;
14889 update_parameter_state(parser, &parser->current, &order);
14890 parser_lex(parser);
14895 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14896 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14897 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14900 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
14904 bool repeated =
false;
14905 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14906 name = parser->previous;
14907 repeated = pm_parser_parameter_name_check(parser, &name);
14908 pm_parser_local_add_token(parser, &name, 1);
14910 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
14913 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14915 pm_node_flag_set_repeated_parameter(param);
14920 pm_parameters_node_keyword_rest_set(params, param);
14922 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14923 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14929 if (parser->previous.
type == PM_TOKEN_COMMA) {
14930 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
14940 if (!parsing)
break;
14942 bool accepted_newline =
false;
14943 if (uses_parentheses) {
14944 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14947 if (accept1(parser, PM_TOKEN_COMMA)) {
14950 if (accepted_newline) {
14951 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14959 pm_do_loop_stack_pop(parser);
14962 if (PM_NODE_START(params) == PM_NODE_END(params)) {
14975 if (parser->heredoc_end == NULL) {
14979 return parser->line_offsets.
size - 1;
14985 return (
size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
14994token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14995 const uint8_t *cursor = parser->start + parser->line_offsets.
offsets[newline_index];
14996 const uint8_t *end = token->start;
15000 newline_index == 0 &&
15001 parser->start[0] == 0xef &&
15002 parser->start[1] == 0xbb &&
15003 parser->start[2] == 0xbf
15006 int64_t column = 0;
15007 for (; cursor < end; cursor++) {
15010 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15017 if (break_on_non_space)
return -1;
15030parser_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) {
15032 if (!parser->warn_mismatched_indentation)
return;
15035 size_t closing_newline_index = token_newline_index(parser);
15036 if (opening_newline_index == closing_newline_index)
return;
15041 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15042 if (!if_after_else && (opening_column == -1))
return;
15046 pm_token_t *closing_token = &parser->current;
15049 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15050 if ((closing_column == -1) || (opening_column == closing_column))
return;
15054 if (allow_indent && (closing_column > opening_column))
return;
15057 PM_PARSER_WARN_FORMAT(
15059 PM_TOKEN_START(parser, closing_token),
15060 PM_TOKEN_LENGTH(closing_token),
15061 PM_WARN_INDENTATION_MISMATCH,
15062 (
int) (closing_token->
end - closing_token->
start),
15063 (
const char *) closing_token->
start,
15064 (
int) (opening_token->
end - opening_token->
start),
15065 (
const char *) opening_token->
start,
15066 ((int32_t) opening_newline_index) + parser->start_line
15071 PM_RESCUES_BEGIN = 1,
15078} pm_rescues_type_t;
15088 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15089 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15090 parser_lex(parser);
15092 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
15094 switch (parser->current.type) {
15095 case PM_TOKEN_EQUAL_GREATER: {
15099 parser_lex(parser);
15100 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15102 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15103 reference = parse_target(parser, reference,
false,
false);
15105 pm_rescue_node_reference_set(rescue, reference);
15108 case PM_TOKEN_NEWLINE:
15109 case PM_TOKEN_SEMICOLON:
15110 case PM_TOKEN_KEYWORD_THEN:
15115 if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
15120 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15121 pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
15125 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15129 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15130 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15132 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15133 reference = parse_target(parser, reference,
false,
false);
15135 pm_rescue_node_reference_set(rescue, reference);
15138 }
while (accept1(parser, PM_TOKEN_COMMA));
15143 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15144 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15148 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15152 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15153 pm_accepts_block_stack_push(parser,
true);
15154 pm_context_t context;
15157 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_RESCUE;
break;
15158 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_RESCUE;
break;
15159 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_RESCUE;
break;
15160 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_RESCUE;
break;
15161 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE;
break;
15162 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE;
break;
15163 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE;
break;
15164 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15168 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15170 pm_accepts_block_stack_pop(parser);
15171 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15174 if (current == NULL) {
15175 pm_begin_node_rescue_clause_set(parent_node, rescue);
15177 pm_rescue_node_subsequent_set(current, rescue);
15186 if (current != NULL) {
15189 while (clause != NULL) {
15190 PM_NODE_LENGTH_SET_NODE(clause, current);
15196 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15197 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15198 opening_newline_index = token_newline_index(parser);
15200 else_keyword = parser->current;
15201 opening = &else_keyword;
15203 parser_lex(parser);
15204 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15207 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15208 pm_accepts_block_stack_push(parser,
true);
15209 pm_context_t context;
15212 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ELSE;
break;
15213 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ELSE;
break;
15214 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ELSE;
break;
15215 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ELSE;
break;
15216 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE;
break;
15217 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE;
break;
15218 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE;
break;
15219 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_ELSE;
break;
15222 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15223 pm_accepts_block_stack_pop(parser);
15225 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15228 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
15229 pm_begin_node_else_clause_set(parent_node, else_clause);
15233 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
15236 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15237 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15238 pm_token_t ensure_keyword = parser->current;
15240 parser_lex(parser);
15241 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15244 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15245 pm_accepts_block_stack_push(parser,
true);
15246 pm_context_t context;
15249 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ENSURE;
break;
15250 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ENSURE;
break;
15251 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ENSURE;
break;
15252 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ENSURE;
break;
15253 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE;
break;
15254 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE;
break;
15255 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE;
break;
15256 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15259 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15260 pm_accepts_block_stack_pop(parser);
15262 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15265 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
15266 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15269 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15270 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15271 pm_begin_node_end_keyword_set(parser, parent_node, &parser->current);
15274 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
15284 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
15285 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15288 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
15297parse_block_parameters(
15299 bool allows_trailing_comma,
15301 bool is_lambda_literal,
15302 bool accepts_blocks_in_defaults,
15306 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15307 if (!is_lambda_literal) {
15308 context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
15310 parameters = parse_parameters(
15312 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15314 allows_trailing_comma,
15316 accepts_blocks_in_defaults,
15318 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
15319 (uint16_t) (depth + 1)
15321 if (!is_lambda_literal) {
15322 context_pop(parser);
15327 if (opening != NULL) {
15328 accept1(parser, PM_TOKEN_NEWLINE);
15330 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15332 switch (parser->current.type) {
15333 case PM_TOKEN_CONSTANT:
15334 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15335 parser_lex(parser);
15337 case PM_TOKEN_INSTANCE_VARIABLE:
15338 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15339 parser_lex(parser);
15341 case PM_TOKEN_GLOBAL_VARIABLE:
15342 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15343 parser_lex(parser);
15345 case PM_TOKEN_CLASS_VARIABLE:
15346 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15347 parser_lex(parser);
15350 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15354 bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
15355 pm_parser_local_add_token(parser, &parser->previous, 1);
15358 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
15360 pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
15361 }
while (accept1(parser, PM_TOKEN_COMMA));
15365 return block_parameters;
15373outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15374 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15375 if (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15386static const char *
const pm_numbered_parameter_names[] = {
15387 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15397 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
15401 if (parameters != NULL) {
15403 if (implicit_parameters->
size > 0) {
15406 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15407 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15408 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15409 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15411 assert(
false &&
"unreachable");
15420 if (implicit_parameters->
size == 0) {
15427 uint8_t numbered_parameter = 0;
15428 bool it_parameter =
false;
15430 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15433 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15434 if (it_parameter) {
15435 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15436 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15437 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15438 }
else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
15439 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15440 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
15441 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->
location.
start + 1] -
'0'));
15443 assert(
false &&
"unreachable");
15445 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15446 if (numbered_parameter > 0) {
15447 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15449 it_parameter =
true;
15454 if (numbered_parameter > 0) {
15457 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15458 scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15460 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
15463 if (it_parameter) {
15464 return UP(pm_it_parameters_node_create(parser, opening, closing));
15474parse_block(
pm_parser_t *parser, uint16_t depth) {
15476 accept1(parser, PM_TOKEN_NEWLINE);
15482 bool do_block = opening.
type != PM_TOKEN_BRACE_LEFT && opening.
type != PM_TOKEN_BRACE_LEFT_ARGUMENT;
15483 if (do_block) pm_accepts_block_stack_push(parser,
true);
15484 pm_parser_scope_push(parser,
false);
15488 if (accept1(parser, PM_TOKEN_PIPE)) {
15489 pm_token_t block_parameters_opening = parser->previous;
15490 if (match1(parser, PM_TOKEN_PIPE)) {
15491 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15492 parser->command_start =
true;
15493 parser_lex(parser);
15495 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15496 accept1(parser, PM_TOKEN_NEWLINE);
15497 parser->command_start =
true;
15498 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15501 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
15504 accept1(parser, PM_TOKEN_NEWLINE);
15508 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15509 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
15512 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
15514 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15515 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15516 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)));
15519 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15520 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15521 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
15527 pm_accepts_block_stack_pop(parser);
15528 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
15532 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
15533 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
15535 pm_parser_scope_pop(parser);
15536 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
15551parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool full_arguments, uint8_t flags, uint16_t depth) {
15556 !token_begins_expression_p(parser->current.type) &&
15557 !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)
15562 bool found =
false;
15563 bool parsed_command_args =
false;
15565 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15567 arguments->
opening_loc = TOK2LOC(parser, &parser->previous);
15569 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15570 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15572 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
15580 if (!full_arguments && parser->previous.
type == PM_TOKEN_COMMA) {
15581 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15584 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15585 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
15586 parser->previous.
start = parser->previous.
end;
15587 parser->previous.
type = 0;
15590 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15592 }
else if ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
15594 parsed_command_args =
true;
15604 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);
15605 if (lookahead_delimiter) pm_accepts_block_stack_pop(parser);
15606 pm_accepts_block_stack_push(parser,
false);
15607 if (lookahead_delimiter) pm_accepts_block_stack_push(parser,
true);
15612 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
15617 if (parser->previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15618 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15626 bool lookahead_brace = match2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT);
15627 if (lookahead_brace) pm_accepts_block_stack_pop(parser);
15628 pm_accepts_block_stack_pop(parser);
15629 if (lookahead_brace) pm_accepts_block_stack_push(parser,
true);
15635 if (full_arguments) {
15638 if (accept2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT)) {
15640 block = parse_block(parser, (uint16_t) (depth + 1));
15641 pm_arguments_validate_block(parser, arguments, block);
15642 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15644 block = parse_block(parser, (uint16_t) (depth + 1));
15645 }
else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
15647 block = parse_block(parser, (uint16_t) (depth + 1));
15650 if (block != NULL) {
15652 arguments->
block = UP(block);
15654 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
15656 if (arguments->
block != NULL) {
15658 arguments->
arguments = pm_arguments_node_create(parser);
15660 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, arguments->
block);
15662 arguments->
block = UP(block);
15676 bool in_sclass =
false;
15677 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15678 switch (context_node->context) {
15679 case PM_CONTEXT_BEGIN_ELSE:
15680 case PM_CONTEXT_BEGIN_ENSURE:
15681 case PM_CONTEXT_BEGIN_RESCUE:
15682 case PM_CONTEXT_BEGIN:
15683 case PM_CONTEXT_CASE_IN:
15684 case PM_CONTEXT_CASE_WHEN:
15685 case PM_CONTEXT_DEFAULT_PARAMS:
15686 case PM_CONTEXT_DEFINED:
15687 case PM_CONTEXT_ELSE:
15688 case PM_CONTEXT_ELSIF:
15689 case PM_CONTEXT_EMBEXPR:
15690 case PM_CONTEXT_FOR_INDEX:
15691 case PM_CONTEXT_FOR:
15692 case PM_CONTEXT_IF:
15693 case PM_CONTEXT_LOOP_PREDICATE:
15694 case PM_CONTEXT_MAIN:
15695 case PM_CONTEXT_MULTI_TARGET:
15696 case PM_CONTEXT_PARENS:
15697 case PM_CONTEXT_POSTEXE:
15698 case PM_CONTEXT_PREDICATE:
15699 case PM_CONTEXT_PREEXE:
15700 case PM_CONTEXT_RESCUE_MODIFIER:
15701 case PM_CONTEXT_TERNARY:
15702 case PM_CONTEXT_UNLESS:
15703 case PM_CONTEXT_UNTIL:
15704 case PM_CONTEXT_WHILE:
15708 case PM_CONTEXT_SCLASS_ELSE:
15709 case PM_CONTEXT_SCLASS_ENSURE:
15710 case PM_CONTEXT_SCLASS_RESCUE:
15711 case PM_CONTEXT_SCLASS:
15714 case PM_CONTEXT_CLASS_ELSE:
15715 case PM_CONTEXT_CLASS_ENSURE:
15716 case PM_CONTEXT_CLASS_RESCUE:
15717 case PM_CONTEXT_CLASS:
15718 case PM_CONTEXT_MODULE_ELSE:
15719 case PM_CONTEXT_MODULE_ENSURE:
15720 case PM_CONTEXT_MODULE_RESCUE:
15721 case PM_CONTEXT_MODULE:
15723 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15725 case PM_CONTEXT_BLOCK_BRACES:
15726 case PM_CONTEXT_BLOCK_ELSE:
15727 case PM_CONTEXT_BLOCK_ENSURE:
15728 case PM_CONTEXT_BLOCK_KEYWORDS:
15729 case PM_CONTEXT_BLOCK_RESCUE:
15730 case PM_CONTEXT_BLOCK_PARAMETERS:
15731 case PM_CONTEXT_DEF_ELSE:
15732 case PM_CONTEXT_DEF_ENSURE:
15733 case PM_CONTEXT_DEF_PARAMS:
15734 case PM_CONTEXT_DEF_RESCUE:
15735 case PM_CONTEXT_DEF:
15736 case PM_CONTEXT_LAMBDA_BRACES:
15737 case PM_CONTEXT_LAMBDA_DO_END:
15738 case PM_CONTEXT_LAMBDA_ELSE:
15739 case PM_CONTEXT_LAMBDA_ENSURE:
15740 case PM_CONTEXT_LAMBDA_RESCUE:
15744 case PM_CONTEXT_NONE:
15746 assert(
false &&
"unreachable");
15750 if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
15751 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15761 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15762 switch (context_node->context) {
15763 case PM_CONTEXT_BLOCK_BRACES:
15764 case PM_CONTEXT_BLOCK_KEYWORDS:
15765 case PM_CONTEXT_BLOCK_ELSE:
15766 case PM_CONTEXT_BLOCK_ENSURE:
15767 case PM_CONTEXT_BLOCK_PARAMETERS:
15768 case PM_CONTEXT_BLOCK_RESCUE:
15769 case PM_CONTEXT_DEFINED:
15770 case PM_CONTEXT_FOR:
15771 case PM_CONTEXT_LAMBDA_BRACES:
15772 case PM_CONTEXT_LAMBDA_DO_END:
15773 case PM_CONTEXT_LAMBDA_ELSE:
15774 case PM_CONTEXT_LAMBDA_ENSURE:
15775 case PM_CONTEXT_LAMBDA_RESCUE:
15776 case PM_CONTEXT_LOOP_PREDICATE:
15777 case PM_CONTEXT_UNTIL:
15778 case PM_CONTEXT_WHILE:
15782 case PM_CONTEXT_POSTEXE:
15784 if (context_node->context == PM_CONTEXT_POSTEXE) {
15785 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
15790 case PM_CONTEXT_DEF:
15791 case PM_CONTEXT_DEF_PARAMS:
15792 case PM_CONTEXT_DEF_ELSE:
15793 case PM_CONTEXT_DEF_ENSURE:
15794 case PM_CONTEXT_DEF_RESCUE:
15795 case PM_CONTEXT_MAIN:
15796 case PM_CONTEXT_PREEXE:
15797 case PM_CONTEXT_SCLASS:
15798 case PM_CONTEXT_SCLASS_ELSE:
15799 case PM_CONTEXT_SCLASS_ENSURE:
15800 case PM_CONTEXT_SCLASS_RESCUE:
15810 assert(parser->current_block_exits != NULL);
15811 pm_node_list_append(parser->arena, parser->current_block_exits, node);
15813 case PM_CONTEXT_BEGIN_ELSE:
15814 case PM_CONTEXT_BEGIN_ENSURE:
15815 case PM_CONTEXT_BEGIN_RESCUE:
15816 case PM_CONTEXT_BEGIN:
15817 case PM_CONTEXT_CASE_IN:
15818 case PM_CONTEXT_CASE_WHEN:
15819 case PM_CONTEXT_CLASS_ELSE:
15820 case PM_CONTEXT_CLASS_ENSURE:
15821 case PM_CONTEXT_CLASS_RESCUE:
15822 case PM_CONTEXT_CLASS:
15823 case PM_CONTEXT_DEFAULT_PARAMS:
15824 case PM_CONTEXT_ELSE:
15825 case PM_CONTEXT_ELSIF:
15826 case PM_CONTEXT_EMBEXPR:
15827 case PM_CONTEXT_FOR_INDEX:
15828 case PM_CONTEXT_IF:
15829 case PM_CONTEXT_MODULE_ELSE:
15830 case PM_CONTEXT_MODULE_ENSURE:
15831 case PM_CONTEXT_MODULE_RESCUE:
15832 case PM_CONTEXT_MODULE:
15833 case PM_CONTEXT_MULTI_TARGET:
15834 case PM_CONTEXT_PARENS:
15835 case PM_CONTEXT_PREDICATE:
15836 case PM_CONTEXT_RESCUE_MODIFIER:
15837 case PM_CONTEXT_TERNARY:
15838 case PM_CONTEXT_UNLESS:
15842 case PM_CONTEXT_NONE:
15844 assert(
false &&
"unreachable");
15856 pm_node_list_t *previous_block_exits = parser->current_block_exits;
15857 parser->current_block_exits = current_block_exits;
15858 return previous_block_exits;
15872 switch (PM_NODE_TYPE(block_exit)) {
15873 case PM_BREAK_NODE:
type =
"break";
break;
15874 case PM_NEXT_NODE:
type =
"next";
break;
15875 case PM_REDO_NODE:
type =
"redo";
break;
15876 default: assert(
false &&
"unreachable");
type =
"";
break;
15879 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15882 parser->current_block_exits = previous_block_exits;
15891 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15895 parser->current_block_exits = previous_block_exits;
15896 }
else if (previous_block_exits != NULL) {
15902 pm_node_list_concat(parser->arena, previous_block_exits, parser->current_block_exits);
15903 parser->current_block_exits = previous_block_exits;
15908 flush_block_exits(parser, previous_block_exits);
15913parse_predicate(
pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context,
pm_token_t *then_keyword, uint16_t depth) {
15914 context_push(parser, PM_CONTEXT_PREDICATE);
15915 pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
15916 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));
15919 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15921 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15922 predicate_closed =
true;
15923 *then_keyword = parser->previous;
15926 if (!predicate_closed) {
15927 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15930 context_pop(parser);
15935parse_conditional(
pm_parser_t *parser, pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15937 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15942 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, context, &then_keyword, (uint16_t) (depth + 1));
15945 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15946 pm_accepts_block_stack_push(parser,
true);
15947 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15948 pm_accepts_block_stack_pop(parser);
15949 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15955 case PM_CONTEXT_IF:
15956 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15958 case PM_CONTEXT_UNLESS:
15959 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
15962 assert(
false &&
"unreachable");
15970 if (context == PM_CONTEXT_IF) {
15971 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15972 if (parser_end_of_line_p(parser)) {
15973 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
15976 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15978 parser_lex(parser);
15980 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15981 pm_accepts_block_stack_push(parser,
true);
15983 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
15984 pm_accepts_block_stack_pop(parser);
15985 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15987 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15993 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15994 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15995 opening_newline_index = token_newline_index(parser);
15997 parser_lex(parser);
16000 pm_accepts_block_stack_push(parser,
true);
16001 pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
16002 pm_accepts_block_stack_pop(parser);
16004 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16005 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
16006 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
16008 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
16011 case PM_CONTEXT_IF:
16012 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
16014 case PM_CONTEXT_UNLESS:
16018 assert(
false &&
"unreachable");
16022 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
16023 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
16028 case PM_CONTEXT_IF: {
16030 bool recursing =
true;
16032 while (recursing) {
16033 switch (PM_NODE_TYPE(current)) {
16035 pm_if_node_end_keyword_loc_set(parser, (
pm_if_node_t *) current, &parser->previous);
16037 recursing = current != NULL;
16040 pm_else_node_end_keyword_loc_set(parser, (
pm_else_node_t *) current, &parser->previous);
16051 case PM_CONTEXT_UNLESS:
16052 pm_unless_node_end_keyword_loc_set(parser, (
pm_unless_node_t *) parent, &parser->previous);
16055 assert(
false &&
"unreachable");
16059 pop_block_exits(parser, previous_block_exits);
16067#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16068 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16069 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16070 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: \
16071 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16072 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16073 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16074 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16075 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16076 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16077 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16083#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16084 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16085 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16086 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16087 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16088 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16089 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16090 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16097#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16098 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16099 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16100 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_XSTRING_BEGIN: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16101 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16102 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16103 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16104 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16105 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16111#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16112 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16113 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16114 case PM_TOKEN_CLASS_VARIABLE
16120#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16121 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16122 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16123 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16127PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16135 if (explicit_encoding != NULL) {
16136 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
16139 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16140 }
else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
16145 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16156parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16157 switch (parser->current.type) {
16164 case PM_TOKEN_STRING_CONTENT: {
16165 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16166 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
16168 parser_lex(parser);
16177 case PM_TOKEN_EMBEXPR_BEGIN: {
16180 parser->explicit_encoding = NULL;
16182 pm_lex_state_t state = parser->lex_state;
16183 int brace_nesting = parser->brace_nesting;
16185 parser->brace_nesting = 0;
16186 lex_state_set(parser, PM_LEX_STATE_BEG);
16187 parser_lex(parser);
16192 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
16193 statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
16196 parser->brace_nesting = brace_nesting;
16197 lex_state_set(parser, state);
16198 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16203 if (statements != NULL && statements->
body.
size == 1) {
16204 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16207 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
16216 case PM_TOKEN_EMBVAR: {
16219 parser->explicit_encoding = NULL;
16221 lex_state_set(parser, PM_LEX_STATE_BEG);
16222 parser_lex(parser);
16227 switch (parser->current.type) {
16230 case PM_TOKEN_BACK_REFERENCE:
16231 parser_lex(parser);
16232 variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
16236 case PM_TOKEN_NUMBERED_REFERENCE:
16237 parser_lex(parser);
16238 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16242 case PM_TOKEN_GLOBAL_VARIABLE:
16243 parser_lex(parser);
16244 variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
16248 case PM_TOKEN_INSTANCE_VARIABLE:
16249 parser_lex(parser);
16250 variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
16254 case PM_TOKEN_CLASS_VARIABLE:
16255 parser_lex(parser);
16256 variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
16262 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16263 variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16267 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
16270 parser_lex(parser);
16271 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16281static const uint8_t *
16282parse_operator_symbol_name(
const pm_token_t *name) {
16283 switch (name->
type) {
16284 case PM_TOKEN_TILDE:
16285 case PM_TOKEN_BANG:
16286 if (name->
end[-1] ==
'@')
return name->
end - 1;
16295 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
16296 const uint8_t *end = parse_operator_symbol_name(&parser->current);
16298 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16299 parser_lex(parser);
16301 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, end);
16302 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16314 const pm_token_t opening = parser->previous;
16316 if (lex_mode->mode != PM_LEX_STRING) {
16317 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16319 switch (parser->current.type) {
16320 case PM_CASE_OPERATOR:
16321 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16322 case PM_TOKEN_IDENTIFIER:
16323 case PM_TOKEN_CONSTANT:
16324 case PM_TOKEN_INSTANCE_VARIABLE:
16325 case PM_TOKEN_METHOD_NAME:
16326 case PM_TOKEN_CLASS_VARIABLE:
16327 case PM_TOKEN_GLOBAL_VARIABLE:
16328 case PM_TOKEN_NUMBERED_REFERENCE:
16329 case PM_TOKEN_BACK_REFERENCE:
16330 case PM_CASE_KEYWORD:
16331 parser_lex(parser);
16334 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16338 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
16339 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16340 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16345 if (lex_mode->as.string.interpolation) {
16347 if (match1(parser, PM_TOKEN_STRING_END)) {
16348 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16349 parser_lex(parser);
16351 .
type = PM_TOKEN_STRING_CONTENT,
16352 .start = parser->previous.
start,
16353 .end = parser->previous.
start
16356 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
16360 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16364 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16365 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16366 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16368 return UP(pm_string_node_to_symbol_node(parser, (
pm_string_node_t *) part, &opening, &parser->previous));
16372 if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16374 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16375 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16376 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16380 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16381 if (match1(parser, PM_TOKEN_EOF)) {
16382 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16384 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16387 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16394 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16395 content = parser->current;
16396 unescaped = parser->current_string;
16397 parser_lex(parser);
16408 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16410 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16411 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16413 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
16414 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16416 if (next_state != PM_LEX_STATE_NONE) {
16417 lex_state_set(parser, next_state);
16420 parser_lex(parser);
16421 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16423 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16427 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.
end, .end = parser->previous.
end };
16428 pm_string_shared_init(&unescaped, content.
start, content.
end);
16431 if (next_state != PM_LEX_STATE_NONE) {
16432 lex_state_set(parser, next_state);
16435 if (match1(parser, PM_TOKEN_EOF)) {
16436 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16438 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16441 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
false)));
16449parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16450 switch (parser->current.type) {
16451 case PM_CASE_OPERATOR:
16452 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
16453 case PM_CASE_KEYWORD:
16454 case PM_TOKEN_CONSTANT:
16455 case PM_TOKEN_IDENTIFIER:
16456 case PM_TOKEN_METHOD_NAME: {
16457 parser_lex(parser);
16459 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16460 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16461 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16465 case PM_TOKEN_SYMBOL_BEGIN: {
16467 parser_lex(parser);
16469 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16472 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16473 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16484parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16485 switch (parser->current.type) {
16486 case PM_CASE_OPERATOR:
16487 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16488 case PM_CASE_KEYWORD:
16489 case PM_TOKEN_CONSTANT:
16490 case PM_TOKEN_IDENTIFIER:
16491 case PM_TOKEN_METHOD_NAME: {
16492 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16493 parser_lex(parser);
16495 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16496 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16497 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16501 case PM_TOKEN_SYMBOL_BEGIN: {
16503 parser_lex(parser);
16505 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16507 case PM_TOKEN_BACK_REFERENCE:
16508 parser_lex(parser);
16509 return UP(pm_back_reference_read_node_create(parser, &parser->previous));
16510 case PM_TOKEN_NUMBERED_REFERENCE:
16511 parser_lex(parser);
16512 return UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16513 case PM_TOKEN_GLOBAL_VARIABLE:
16514 parser_lex(parser);
16515 return UP(pm_global_variable_read_node_create(parser, &parser->previous));
16517 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16518 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16528 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
16530 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
16532 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16533 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth,
false));
16536 pm_scope_t *current_scope = parser->current_scope;
16537 if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16538 if (is_numbered_param) {
16543 uint8_t maximum = (uint8_t) (parser->previous.
start[1] -
'0');
16544 for (uint8_t number = 1; number <= maximum; number++) {
16545 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16548 if (!match1(parser, PM_TOKEN_EQUAL)) {
16549 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
16552 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0,
false));
16553 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16556 }
else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.
start, parser->previous.
end)) {
16557 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16558 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16572 pm_node_flags_t flags = 0;
16574 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.
end[-1] !=
'!') && (parser->previous.
end[-1] !=
'?')) {
16575 pm_node_t *node = parse_variable(parser);
16576 if (node != NULL)
return node;
16577 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16580 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
16581 pm_node_flag_set(UP(node), flags);
16592parse_method_definition_name(
pm_parser_t *parser) {
16593 switch (parser->current.type) {
16594 case PM_CASE_KEYWORD:
16595 case PM_TOKEN_CONSTANT:
16596 case PM_TOKEN_METHOD_NAME:
16597 parser_lex(parser);
16598 return parser->previous;
16599 case PM_TOKEN_IDENTIFIER:
16600 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
16601 parser_lex(parser);
16602 return parser->previous;
16603 case PM_CASE_OPERATOR:
16604 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16605 parser_lex(parser);
16606 return parser->previous;
16608 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
16609 return (
pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end };
16620 if (string->
type != PM_STRING_OWNED) {
16621 size_t length = pm_string_length(
string);
16622 writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(
string), length,
PRISM_ALIGNOF(uint8_t));
16623 pm_string_constant_init(
string, (
const char *) writable, length);
16625 writable = (uint8_t *) string->
source;
16631 size_t dest_length = pm_string_length(
string);
16632 const uint8_t *source_cursor = writable;
16633 const uint8_t *source_end = source_cursor + dest_length;
16638 size_t trimmed_whitespace = 0;
16644 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16645 if (*source_cursor ==
'\t') {
16646 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16647 if (trimmed_whitespace > common_whitespace)
break;
16649 trimmed_whitespace++;
16656 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
16657 string->length = dest_length;
16667 const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->
content_loc);
16668 return pm_memchr(cursor,
'\\', string_node->
content_loc.
length, parser->encoding_changed, parser->encoding) == NULL;
16680 bool dedent_next =
true;
16684 size_t write_index = 0;
16691 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16692 nodes->
nodes[write_index++] = node;
16693 dedent_next =
false;
16699 parse_heredoc_dedent_string(parser->arena, &string_node->
unescaped, common_whitespace);
16702 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16704 nodes->
nodes[write_index++] = node;
16708 dedent_next =
true;
16711 nodes->
size = write_index;
16718parse_strings_empty_content(
const uint8_t *location) {
16719 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16727 assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
16728 bool concating =
false;
16730 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16736 assert(lex_mode->mode == PM_LEX_STRING);
16737 bool lex_interpolation = lex_mode->as.string.interpolation;
16738 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
16741 parser_lex(parser);
16743 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16744 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16748 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
16749 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->previous);
16753 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16757 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
16758 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
start);
16761 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16762 }
else if (!lex_interpolation) {
16768 if (match1(parser, PM_TOKEN_EOF)) {
16769 unescaped = PM_STRING_EMPTY;
16770 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
16772 unescaped = parser->current_string;
16773 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16774 content = parser->previous;
16788 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16790 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16791 pm_node_list_append(parser->arena, &parts, part);
16794 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16795 pm_node_list_append(parser->arena, &parts, part);
16796 parser_lex(parser);
16797 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16799 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16800 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16801 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16802 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
true)));
16803 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16804 }
else if (match1(parser, PM_TOKEN_EOF)) {
16805 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16806 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16807 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16808 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16810 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.
type));
16811 parser->previous.
start = parser->previous.
end;
16812 parser->previous.
type = 0;
16813 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16815 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16822 const pm_encoding_t *explicit_encoding = parser->explicit_encoding;
16823 parser_lex(parser);
16825 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16826 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16827 pm_node_flag_set(node, parse_unescaped_encoding(parser, explicit_encoding));
16833 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16834 const uint8_t *location = parser->previous.
end;
16835 if (location > parser->start && location[-1] ==
'\n') location--;
16836 pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
16838 parser->previous.
start = parser->previous.
end;
16839 parser->previous.
type = 0;
16841 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16842 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, explicit_encoding, &content, &unescaped,
true)));
16843 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16848 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
16849 pm_node_flag_set(part, parse_unescaped_encoding(parser, explicit_encoding));
16850 pm_node_list_append(parser->arena, &parts, part);
16852 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16853 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16854 pm_node_list_append(parser->arena, &parts, part);
16858 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16859 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16860 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16861 }
else if (match1(parser, PM_TOKEN_EOF)) {
16862 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16863 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16865 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16866 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16876 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16877 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16878 pm_node_list_append(parser->arena, &parts, part);
16882 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16883 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16884 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16885 }
else if (match1(parser, PM_TOKEN_EOF)) {
16886 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16887 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16889 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16890 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16894 if (current == NULL) {
16898 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16909 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16910 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16916 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16917 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16922 pm_interpolated_string_node_append(parser, container, current);
16923 current = UP(container);
16933#define PM_PARSE_PATTERN_SINGLE 0
16934#define PM_PARSE_PATTERN_TOP 1
16935#define PM_PARSE_PATTERN_MULTI 2
16948 if (peek_at(parser, parser->start + location->
start) ==
'_')
return;
16950 if (pm_constant_id_list_includes(captures, capture)) {
16951 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16953 pm_constant_id_list_append(parser->arena, captures, capture);
16964 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16966 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16967 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
16973 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16981 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16982 opening = parser->previous;
16983 accept1(parser, PM_TOKEN_NEWLINE);
16985 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16986 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16987 accept1(parser, PM_TOKEN_NEWLINE);
16988 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16991 closing = parser->previous;
16993 parser_lex(parser);
16994 opening = parser->previous;
16995 accept1(parser, PM_TOKEN_NEWLINE);
16997 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16998 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16999 accept1(parser, PM_TOKEN_NEWLINE);
17000 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17003 closing = parser->previous;
17009 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
17016 switch (PM_NODE_TYPE(inner)) {
17017 case PM_ARRAY_PATTERN_NODE: {
17021 PM_NODE_START_SET_NODE(pattern_node, node);
17022 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17025 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17026 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17028 return UP(pattern_node);
17033 case PM_FIND_PATTERN_NODE: {
17037 PM_NODE_START_SET_NODE(pattern_node, node);
17038 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17041 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17042 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17044 return UP(pattern_node);
17049 case PM_HASH_PATTERN_NODE: {
17053 PM_NODE_START_SET_NODE(pattern_node, node);
17054 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17057 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17058 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17060 return UP(pattern_node);
17072 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17073 pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
17074 return UP(pattern_node);
17082 assert(parser->previous.
type == PM_TOKEN_USTAR);
17089 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17090 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17093 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17094 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17097 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17098 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17099 name = UP(pm_local_variable_target_node_create(
17103 (uint32_t) (depth == -1 ? 0 : depth)
17108 return pm_splat_node_create(parser, &
operator, name);
17116 assert(parser->current.type == PM_TOKEN_USTAR_STAR);
17117 parser_lex(parser);
17122 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17123 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
17126 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17127 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17130 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17131 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17134 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17135 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17136 value = UP(pm_local_variable_target_node_create(
17140 (uint32_t) (depth == -1 ? 0 : depth)
17144 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
17152pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17153 ptrdiff_t length = end - start;
17154 if (length == 0)
return false;
17157 size_t width = char_is_identifier_start(parser, start, end - start);
17158 if (width == 0)
return false;
17161 if (parser->encoding_changed) {
17162 if (parser->encoding->isupper_char(start, length))
return false;
17164 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17169 const uint8_t *cursor = start + width;
17170 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17171 return cursor == end;
17181 const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
17182 const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
17184 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
17187 if (pm_slice_is_valid_local(parser, start, end)) {
17188 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17190 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
17192 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
17193 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
17198 pm_parser_local_add(parser, constant_id, start, end, 0);
17201 parse_pattern_capture(parser, captures, constant_id, value_loc);
17206 (uint32_t) (depth == -1 ? 0 : depth)
17209 return UP(pm_implicit_node_create(parser, UP(target)));
17218 if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, keys, node,
true) != NULL) {
17219 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17232 switch (PM_NODE_TYPE(first_node)) {
17233 case PM_ASSOC_SPLAT_NODE:
17234 case PM_NO_KEYWORDS_PARAMETER_NODE:
17237 case PM_INTERPOLATED_SYMBOL_NODE:
17238 case PM_SYMBOL_NODE: {
17239 if (pm_symbol_node_label_p(parser, first_node)) {
17240 if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
17241 pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17243 parse_pattern_hash_key(parser, &keys, first_node);
17253 if (!token_begins_pattern_p(parser->current.type)) {
17254 if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
17255 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17257 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
17262 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17265 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17266 pm_node_list_append(parser->arena, &assocs, assoc);
17275 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;
17276 pm_parser_err_node(parser, first_node, diag_id);
17278 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
17279 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17281 pm_node_list_append(parser->arena, &assocs, assoc);
17287 while (accept1(parser, PM_TOKEN_COMMA)) {
17293 if (!token_begins_pattern_p(parser->current.type)) {
17295 if (rest != NULL) {
17296 pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17302 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17303 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17305 if (rest == NULL) {
17308 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17309 pm_node_list_append(parser->arena, &assocs, assoc);
17314 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17315 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17317 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17318 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17319 }
else if (!pm_symbol_node_label_p(parser, key)) {
17320 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17322 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
17323 key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17325 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17327 pm_token_t label = { .
type = PM_TOKEN_LABEL, .start = parser->previous.
end, .end = parser->previous.
end };
17328 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
17331 parse_pattern_hash_key(parser, &keys, key);
17339 if (!token_begins_pattern_p(parser->current.type)) {
17340 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
17341 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17343 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
17346 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17349 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
17351 if (rest != NULL) {
17352 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17355 pm_node_list_append(parser->arena, &assocs, assoc);
17362 pm_static_literals_free(&keys);
17371 switch (parser->current.type) {
17372 case PM_TOKEN_IDENTIFIER:
17373 case PM_TOKEN_METHOD_NAME: {
17374 parser_lex(parser);
17375 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17378 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17379 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17382 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17383 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17384 return UP(pm_local_variable_target_node_create(
17388 (uint32_t) (depth == -1 ? 0 : depth)
17391 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17393 parser_lex(parser);
17395 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17398 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
17403 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17405 accept1(parser, PM_TOKEN_NEWLINE);
17406 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17409 switch (PM_NODE_TYPE(inner)) {
17410 case PM_ARRAY_PATTERN_NODE: {
17413 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17414 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17416 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17417 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17419 return UP(pattern_node);
17424 case PM_FIND_PATTERN_NODE: {
17427 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17428 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17430 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17431 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17433 return UP(pattern_node);
17443 pm_array_pattern_node_requireds_append(parser->arena, node, inner);
17446 case PM_TOKEN_BRACE_LEFT_HASH: {
17447 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17448 parser->pattern_matching_newlines =
false;
17452 parser_lex(parser);
17454 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17457 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
17461 switch (parser->current.type) {
17462 case PM_TOKEN_LABEL:
17463 parser_lex(parser);
17464 first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
17466 case PM_TOKEN_USTAR_STAR:
17467 first_node = parse_pattern_keyword_rest(parser, captures);
17469 case PM_TOKEN_STRING_BEGIN:
17470 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));
17473 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
17474 parser_lex(parser);
17476 first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
17481 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17483 accept1(parser, PM_TOKEN_NEWLINE);
17484 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
17487 PM_NODE_START_SET_TOKEN(parser, node, &opening);
17488 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
17494 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17497 case PM_TOKEN_UDOT_DOT:
17498 case PM_TOKEN_UDOT_DOT_DOT: {
17500 parser_lex(parser);
17504 switch (parser->current.type) {
17505 case PM_CASE_PRIMITIVE: {
17506 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));
17507 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17510 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17511 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17512 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17516 case PM_CASE_PRIMITIVE: {
17517 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));
17520 if (pm_symbol_node_label_p(parser, node))
return node;
17523 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17524 pm_parser_err_node(parser, node, diag_id);
17525 return UP(pm_error_recovery_node_create_unexpected(parser, node));
17529 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17535 switch (parser->current.type) {
17536 case PM_CASE_PRIMITIVE: {
17537 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));
17538 return UP(pm_range_node_create(parser, node, &
operator, right));
17541 return UP(pm_range_node_create(parser, node, &
operator, NULL));
17547 case PM_TOKEN_CARET: {
17548 parser_lex(parser);
17553 switch (parser->current.type) {
17554 case PM_TOKEN_IDENTIFIER: {
17555 parser_lex(parser);
17556 pm_node_t *variable = UP(parse_variable(parser));
17558 if (variable == NULL) {
17559 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
17560 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
17563 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17565 case PM_TOKEN_INSTANCE_VARIABLE: {
17566 parser_lex(parser);
17567 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
17569 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17571 case PM_TOKEN_CLASS_VARIABLE: {
17572 parser_lex(parser);
17573 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
17575 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17577 case PM_TOKEN_GLOBAL_VARIABLE: {
17578 parser_lex(parser);
17579 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
17581 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17583 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
17584 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17585 parser->pattern_matching_newlines =
false;
17588 parser_lex(parser);
17590 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));
17591 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17593 accept1(parser, PM_TOKEN_NEWLINE);
17594 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
17595 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->previous));
17600 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17601 pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17602 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17606 case PM_TOKEN_UCOLON_COLON: {
17608 parser_lex(parser);
17610 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17613 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
17615 case PM_TOKEN_CONSTANT: {
17617 parser_lex(parser);
17619 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
17620 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17623 pm_parser_err_current(parser, diag_id);
17624 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17629parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
17630 switch (PM_NODE_TYPE(node)) {
17631 case PM_LOCAL_VARIABLE_TARGET_NODE: {
17633 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17647 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
17657 bool alternation =
false;
17659 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
17660 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
17661 parse_pattern_alternation_error(parser, node);
17664 switch (parser->current.type) {
17665 case PM_TOKEN_IDENTIFIER:
17666 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17667 case PM_TOKEN_BRACE_LEFT_HASH:
17668 case PM_TOKEN_CARET:
17669 case PM_TOKEN_CONSTANT:
17670 case PM_TOKEN_UCOLON_COLON:
17671 case PM_TOKEN_UDOT_DOT:
17672 case PM_TOKEN_UDOT_DOT_DOT:
17673 case PM_CASE_PRIMITIVE: {
17674 if (!alternation) {
17675 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17678 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17680 if (captures->
size) parse_pattern_alternation_error(parser, right);
17681 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17686 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
17687 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17690 parser_lex(parser);
17692 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17693 accept1(parser, PM_TOKEN_NEWLINE);
17694 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17695 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
17697 if (!alternation) {
17700 if (captures->
size) parse_pattern_alternation_error(parser, right);
17701 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17707 pm_parser_err_current(parser, diag_id);
17708 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17710 if (!alternation) {
17713 if (captures->
size) parse_pattern_alternation_error(parser, right);
17714 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
17724 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17726 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17728 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17731 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17732 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17735 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17736 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17741 (uint32_t) (depth == -1 ? 0 : depth)
17744 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17757 bool leading_rest =
false;
17758 bool trailing_rest =
false;
17760 switch (parser->current.type) {
17761 case PM_TOKEN_LABEL: {
17762 parser_lex(parser);
17763 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17764 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17766 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17767 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17772 case PM_TOKEN_USTAR_STAR: {
17773 node = parse_pattern_keyword_rest(parser, captures);
17774 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17776 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17777 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17782 case PM_TOKEN_STRING_BEGIN: {
17785 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17787 if (pm_symbol_node_label_p(parser, node)) {
17788 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17790 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17791 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17797 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17800 case PM_TOKEN_USTAR: {
17801 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17802 parser_lex(parser);
17803 node = UP(parse_pattern_rest(parser, captures));
17804 leading_rest =
true;
17810 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17816 if (pm_symbol_node_label_p(parser, node)) {
17817 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17820 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17825 pm_node_list_append(parser->arena, &nodes, node);
17828 while (accept1(parser, PM_TOKEN_COMMA)) {
17834 if (!token_begins_pattern_p(parser->current.type)) {
17839 if (trailing_rest) {
17840 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17843 node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
17844 pm_node_list_append(parser->arena, &nodes, node);
17845 trailing_rest =
true;
17849 if (accept1(parser, PM_TOKEN_USTAR)) {
17850 node = UP(parse_pattern_rest(parser, captures));
17855 if (trailing_rest) {
17856 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17859 trailing_rest =
true;
17861 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17864 pm_node_list_append(parser->arena, &nodes, node);
17871 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17872 node = UP(pm_find_pattern_node_create(parser, &nodes));
17874 if (nodes.
size == 2) {
17875 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17878 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17880 if (leading_rest && trailing_rest) {
17881 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17886 }
else if (leading_rest) {
17889 node = UP(pm_array_pattern_node_rest_create(parser, node));
17901parse_negative_numeric(
pm_node_t *node) {
17902 switch (PM_NODE_TYPE(node)) {
17903 case PM_INTEGER_NODE: {
17910 case PM_FLOAT_NODE: {
17917 case PM_RATIONAL_NODE: {
17924 case PM_IMAGINARY_NODE:
17930 assert(
false &&
"unreachable");
17941pm_parser_err_prefix(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
17943 case PM_ERR_HASH_KEY: {
17944 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.
type));
17947 case PM_ERR_HASH_VALUE:
17948 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17949 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17952 case PM_ERR_UNARY_RECEIVER: {
17953 const char *human = (parser->current.type == PM_TOKEN_EOF ?
"end-of-input" : pm_token_str(parser->current.type));
17954 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.
start[0]);
17957 case PM_ERR_UNARY_DISALLOWED:
17958 case PM_ERR_EXPECT_ARGUMENT: {
17959 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17963 pm_parser_err_previous(parser, diag_id);
17973#define CONTEXT_NONE 0
17974#define CONTEXT_THROUGH_ENSURE 1
17975#define CONTEXT_THROUGH_ELSE 2
17978 int context = CONTEXT_NONE;
17980 while (context_node != NULL) {
17981 switch (context_node->context) {
17982 case PM_CONTEXT_BEGIN_RESCUE:
17983 case PM_CONTEXT_BLOCK_RESCUE:
17984 case PM_CONTEXT_CLASS_RESCUE:
17985 case PM_CONTEXT_DEF_RESCUE:
17986 case PM_CONTEXT_LAMBDA_RESCUE:
17987 case PM_CONTEXT_MODULE_RESCUE:
17988 case PM_CONTEXT_SCLASS_RESCUE:
17989 case PM_CONTEXT_DEFINED:
17990 case PM_CONTEXT_RESCUE_MODIFIER:
17993 case PM_CONTEXT_CLASS:
17994 case PM_CONTEXT_DEF:
17995 case PM_CONTEXT_DEF_PARAMS:
17996 case PM_CONTEXT_MAIN:
17997 case PM_CONTEXT_MODULE:
17998 case PM_CONTEXT_PREEXE:
17999 case PM_CONTEXT_SCLASS:
18002 if (context == CONTEXT_NONE) {
18003 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
18004 }
else if (context == CONTEXT_THROUGH_ENSURE) {
18005 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
18006 }
else if (context == CONTEXT_THROUGH_ELSE) {
18007 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
18010 case PM_CONTEXT_BEGIN_ELSE:
18011 case PM_CONTEXT_BLOCK_ELSE:
18012 case PM_CONTEXT_CLASS_ELSE:
18013 case PM_CONTEXT_DEF_ELSE:
18014 case PM_CONTEXT_LAMBDA_ELSE:
18015 case PM_CONTEXT_MODULE_ELSE:
18016 case PM_CONTEXT_SCLASS_ELSE:
18019 context = CONTEXT_THROUGH_ELSE;
18021 case PM_CONTEXT_BEGIN_ENSURE:
18022 case PM_CONTEXT_BLOCK_ENSURE:
18023 case PM_CONTEXT_CLASS_ENSURE:
18024 case PM_CONTEXT_DEF_ENSURE:
18025 case PM_CONTEXT_LAMBDA_ENSURE:
18026 case PM_CONTEXT_MODULE_ENSURE:
18027 case PM_CONTEXT_SCLASS_ENSURE:
18030 context = CONTEXT_THROUGH_ENSURE;
18032 case PM_CONTEXT_NONE:
18034 assert(
false &&
"unreachable");
18036 case PM_CONTEXT_BEGIN:
18037 case PM_CONTEXT_BLOCK_BRACES:
18038 case PM_CONTEXT_BLOCK_KEYWORDS:
18039 case PM_CONTEXT_BLOCK_PARAMETERS:
18040 case PM_CONTEXT_CASE_IN:
18041 case PM_CONTEXT_CASE_WHEN:
18042 case PM_CONTEXT_DEFAULT_PARAMS:
18043 case PM_CONTEXT_ELSE:
18044 case PM_CONTEXT_ELSIF:
18045 case PM_CONTEXT_EMBEXPR:
18046 case PM_CONTEXT_FOR_INDEX:
18047 case PM_CONTEXT_FOR:
18048 case PM_CONTEXT_IF:
18049 case PM_CONTEXT_LAMBDA_BRACES:
18050 case PM_CONTEXT_LAMBDA_DO_END:
18051 case PM_CONTEXT_LOOP_PREDICATE:
18052 case PM_CONTEXT_MULTI_TARGET:
18053 case PM_CONTEXT_PARENS:
18054 case PM_CONTEXT_POSTEXE:
18055 case PM_CONTEXT_PREDICATE:
18056 case PM_CONTEXT_TERNARY:
18057 case PM_CONTEXT_UNLESS:
18058 case PM_CONTEXT_UNTIL:
18059 case PM_CONTEXT_WHILE:
18065 context_node = context_node->prev;
18069#undef CONTEXT_ENSURE
18080 while (context_node != NULL) {
18081 switch (context_node->context) {
18082 case PM_CONTEXT_DEF:
18083 case PM_CONTEXT_DEF_PARAMS:
18084 case PM_CONTEXT_DEFINED:
18085 case PM_CONTEXT_DEF_ENSURE:
18086 case PM_CONTEXT_DEF_RESCUE:
18087 case PM_CONTEXT_DEF_ELSE:
18091 case PM_CONTEXT_CLASS:
18092 case PM_CONTEXT_CLASS_ENSURE:
18093 case PM_CONTEXT_CLASS_RESCUE:
18094 case PM_CONTEXT_CLASS_ELSE:
18095 case PM_CONTEXT_MAIN:
18096 case PM_CONTEXT_MODULE:
18097 case PM_CONTEXT_MODULE_ENSURE:
18098 case PM_CONTEXT_MODULE_RESCUE:
18099 case PM_CONTEXT_MODULE_ELSE:
18100 case PM_CONTEXT_SCLASS:
18101 case PM_CONTEXT_SCLASS_RESCUE:
18102 case PM_CONTEXT_SCLASS_ENSURE:
18103 case PM_CONTEXT_SCLASS_ELSE:
18106 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
18108 case PM_CONTEXT_NONE:
18110 assert(
false &&
"unreachable");
18112 case PM_CONTEXT_BEGIN:
18113 case PM_CONTEXT_BEGIN_ELSE:
18114 case PM_CONTEXT_BEGIN_ENSURE:
18115 case PM_CONTEXT_BEGIN_RESCUE:
18116 case PM_CONTEXT_BLOCK_BRACES:
18117 case PM_CONTEXT_BLOCK_KEYWORDS:
18118 case PM_CONTEXT_BLOCK_ELSE:
18119 case PM_CONTEXT_BLOCK_ENSURE:
18120 case PM_CONTEXT_BLOCK_PARAMETERS:
18121 case PM_CONTEXT_BLOCK_RESCUE:
18122 case PM_CONTEXT_CASE_IN:
18123 case PM_CONTEXT_CASE_WHEN:
18124 case PM_CONTEXT_DEFAULT_PARAMS:
18125 case PM_CONTEXT_ELSE:
18126 case PM_CONTEXT_ELSIF:
18127 case PM_CONTEXT_EMBEXPR:
18128 case PM_CONTEXT_FOR_INDEX:
18129 case PM_CONTEXT_FOR:
18130 case PM_CONTEXT_IF:
18131 case PM_CONTEXT_LAMBDA_BRACES:
18132 case PM_CONTEXT_LAMBDA_DO_END:
18133 case PM_CONTEXT_LAMBDA_ELSE:
18134 case PM_CONTEXT_LAMBDA_ENSURE:
18135 case PM_CONTEXT_LAMBDA_RESCUE:
18136 case PM_CONTEXT_LOOP_PREDICATE:
18137 case PM_CONTEXT_MULTI_TARGET:
18138 case PM_CONTEXT_PARENS:
18139 case PM_CONTEXT_POSTEXE:
18140 case PM_CONTEXT_PREDICATE:
18141 case PM_CONTEXT_PREEXE:
18142 case PM_CONTEXT_RESCUE_MODIFIER:
18143 case PM_CONTEXT_TERNARY:
18144 case PM_CONTEXT_UNLESS:
18145 case PM_CONTEXT_UNTIL:
18146 case PM_CONTEXT_WHILE:
18152 context_node = context_node->prev;
18161parse_case(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18162 size_t opening_newline_index = token_newline_index(parser);
18163 parser_lex(parser);
18169 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18171 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18172 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18174 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18176 }
else if (!token_begins_expression_p(parser->current.type)) {
18179 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));
18180 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18183 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18184 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18185 parser_lex(parser);
18186 pop_block_exits(parser, previous_block_exits);
18187 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18188 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->previous));
18195 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18196 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
18202 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18203 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18204 parser_lex(parser);
18207 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18210 if (accept1(parser, PM_TOKEN_USTAR)) {
18212 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));
18214 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18215 pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
18217 if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE))
break;
18219 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));
18220 pm_when_node_conditions_append(parser->arena, when_node, condition);
18224 if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE))
break;
18228 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18229 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18230 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18231 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18234 pm_when_clause_static_literals_add(parser, &literals, condition);
18236 }
while (accept1(parser, PM_TOKEN_COMMA));
18238 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18239 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18240 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18243 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18244 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18247 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18248 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18249 if (statements != NULL) {
18250 pm_when_node_statements_set(when_node, statements);
18254 pm_case_node_condition_append(parser->arena, case_node, UP(when_node));
18260 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18263 pm_static_literals_free(&literals);
18264 node = UP(case_node);
18266 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
18270 if (predicate == NULL) {
18271 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18276 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18277 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18279 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
18280 parser->pattern_matching_newlines =
true;
18282 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18283 parser->command_start =
false;
18284 parser_lex(parser);
18289 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));
18291 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
18296 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18298 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));
18299 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18300 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18302 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));
18303 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18310 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18311 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18312 then_keyword = parser->previous;
18315 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18316 then_keyword = parser->previous;
18322 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18325 statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
18330 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
18331 pm_case_match_node_condition_append(parser->arena, case_node, condition);
18337 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18340 node = UP(case_node);
18343 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18344 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18348 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18349 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
18351 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
18354 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18355 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18361 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18362 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18364 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18365 pm_case_node_end_keyword_loc_set(parser, (
pm_case_node_t *) node, &parser->previous);
18367 pm_case_match_node_end_keyword_loc_set(parser, (
pm_case_match_node_t *) node, &parser->previous);
18370 pop_block_exits(parser, previous_block_exits);
18379parse_class(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18380 size_t opening_newline_index = token_newline_index(parser);
18381 parser_lex(parser);
18383 pm_token_t class_keyword = parser->previous;
18384 pm_do_loop_stack_push(parser,
false);
18387 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18389 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18391 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));
18393 pm_parser_scope_push(parser,
true);
18394 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18395 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
18399 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18400 pm_accepts_block_stack_push(parser,
true);
18401 statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18402 pm_accepts_block_stack_pop(parser);
18405 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18406 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18407 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)));
18409 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18412 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18415 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18417 pm_parser_scope_pop(parser);
18418 pm_do_loop_stack_pop(parser);
18420 flush_block_exits(parser, previous_block_exits);
18421 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->previous));
18424 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));
18426 if (name.
type != PM_TOKEN_CONSTANT) {
18427 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18433 if (match1(parser, PM_TOKEN_LESS)) {
18434 inheritance_operator = parser->current;
18435 lex_state_set(parser, PM_LEX_STATE_BEG);
18437 parser->command_start =
true;
18438 parser_lex(parser);
18440 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));
18445 pm_parser_scope_push(parser,
true);
18447 if (inheritance_operator.
start != NULL) {
18448 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18450 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18454 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18455 pm_accepts_block_stack_push(parser,
true);
18456 statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18457 pm_accepts_block_stack_pop(parser);
18460 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18461 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18462 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)));
18464 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18467 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18469 if (context_def_p(parser)) {
18470 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18474 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18476 pm_parser_scope_pop(parser);
18477 pm_do_loop_stack_pop(parser);
18479 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18480 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18481 if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18482 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18486 pop_block_exits(parser, previous_block_exits);
18487 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
18494parse_def(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
18496 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18499 size_t opening_newline_index = token_newline_index(parser);
18507 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18508 parser_lex(parser);
18512 bool valid_name =
true;
18514 switch (parser->current.type) {
18515 case PM_CASE_OPERATOR:
18516 pm_parser_scope_push(parser,
true);
18517 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18518 parser_lex(parser);
18520 name = parser->previous;
18522 case PM_TOKEN_IDENTIFIER: {
18523 parser_lex(parser);
18525 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18526 receiver = parse_variable_call(parser);
18528 pm_parser_scope_push(parser,
true);
18529 lex_state_set(parser, PM_LEX_STATE_FNAME);
18530 parser_lex(parser);
18532 operator = parser->previous;
18533 name = parse_method_definition_name(parser);
18535 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
18536 pm_parser_scope_push(parser,
true);
18538 name = parser->previous;
18543 case PM_TOKEN_INSTANCE_VARIABLE:
18544 case PM_TOKEN_CLASS_VARIABLE:
18545 case PM_TOKEN_GLOBAL_VARIABLE:
18546 valid_name =
false;
18548 case PM_TOKEN_CONSTANT:
18549 case PM_TOKEN_KEYWORD_NIL:
18550 case PM_TOKEN_KEYWORD_SELF:
18551 case PM_TOKEN_KEYWORD_TRUE:
18552 case PM_TOKEN_KEYWORD_FALSE:
18553 case PM_TOKEN_KEYWORD___FILE__:
18554 case PM_TOKEN_KEYWORD___LINE__:
18555 case PM_TOKEN_KEYWORD___ENCODING__: {
18556 pm_parser_scope_push(parser,
true);
18557 parser_lex(parser);
18561 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18562 lex_state_set(parser, PM_LEX_STATE_FNAME);
18563 parser_lex(parser);
18564 operator = parser->previous;
18566 switch (identifier.
type) {
18567 case PM_TOKEN_CONSTANT:
18568 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18570 case PM_TOKEN_INSTANCE_VARIABLE:
18571 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18573 case PM_TOKEN_CLASS_VARIABLE:
18574 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18576 case PM_TOKEN_GLOBAL_VARIABLE:
18577 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18579 case PM_TOKEN_KEYWORD_NIL:
18580 receiver = UP(pm_nil_node_create(parser, &identifier));
18582 case PM_TOKEN_KEYWORD_SELF:
18583 receiver = UP(pm_self_node_create(parser, &identifier));
18585 case PM_TOKEN_KEYWORD_TRUE:
18586 receiver = UP(pm_true_node_create(parser, &identifier));
18588 case PM_TOKEN_KEYWORD_FALSE:
18589 receiver = UP(pm_false_node_create(parser, &identifier));
18591 case PM_TOKEN_KEYWORD___FILE__:
18592 receiver = UP(pm_source_file_node_create(parser, &identifier));
18594 case PM_TOKEN_KEYWORD___LINE__:
18595 receiver = UP(pm_source_line_node_create(parser, &identifier));
18597 case PM_TOKEN_KEYWORD___ENCODING__:
18598 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18604 name = parse_method_definition_name(parser);
18607 PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.
type));
18614 case PM_TOKEN_PARENTHESIS_LEFT: {
18618 context_pop(parser);
18619 parser_lex(parser);
18622 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));
18624 accept1(parser, PM_TOKEN_NEWLINE);
18625 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18628 lex_state_set(parser, PM_LEX_STATE_FNAME);
18629 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18631 operator = parser->previous;
18632 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18636 pm_parser_scope_push(parser,
true);
18637 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18638 name = parse_method_definition_name(parser);
18642 pm_parser_scope_push(parser,
true);
18643 name = parse_method_definition_name(parser);
18651 bool accept_endless_def =
true;
18652 switch (parser->current.type) {
18653 case PM_TOKEN_PARENTHESIS_LEFT: {
18654 parser_lex(parser);
18655 lparen = parser->previous;
18657 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18661 bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
18662 params = parse_parameters(
18664 PM_BINDING_POWER_DEFINED,
18666 allow_trailing_comma,
18670 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18671 (uint16_t) (depth + 1)
18675 lex_state_set(parser, PM_LEX_STATE_BEG);
18676 parser->command_start =
true;
18678 context_pop(parser);
18679 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18680 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
18681 parser->previous.
start = parser->previous.
end;
18682 parser->previous.
type = 0;
18685 rparen = parser->previous;
18688 case PM_CASE_PARAMETER: {
18691 if (parser->current.type == PM_TOKEN_LABEL) {
18692 lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
18695 params = parse_parameters(
18697 PM_BINDING_POWER_DEFINED,
18703 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18704 (uint16_t) (depth + 1)
18709 accept_endless_def =
false;
18711 context_pop(parser);
18716 context_pop(parser);
18725 if (accept1(parser, PM_TOKEN_EQUAL)) {
18726 if (token_is_setter_name(&name)) {
18727 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18729 if (!accept_endless_def) {
18730 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18733 parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
18734 parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
18736 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");
18738 equal = parser->previous;
18740 context_push(parser, PM_CONTEXT_DEF);
18741 pm_do_loop_stack_push(parser,
false);
18742 statements = UP(pm_statements_node_create(parser));
18744 uint8_t allow_flags;
18745 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
18746 allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
18750 allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18763 pm_accepts_block_stack_push(parser,
true);
18764 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));
18771 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18772 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18773 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18780 while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18781 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18783 pm_token_t rescue_keyword = parser->previous;
18787 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));
18788 context_pop(parser);
18790 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18793 pm_accepts_block_stack_pop(parser);
18798 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(parser, statement)) {
18799 PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18802 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18803 pm_do_loop_stack_pop(parser);
18804 context_pop(parser);
18806 if (lparen.
start == NULL) {
18807 lex_state_set(parser, PM_LEX_STATE_BEG);
18808 parser->command_start =
true;
18809 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18811 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18814 pm_accepts_block_stack_push(parser,
true);
18815 pm_do_loop_stack_push(parser,
false);
18817 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18818 pm_accepts_block_stack_push(parser,
true);
18819 statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18820 pm_accepts_block_stack_pop(parser);
18823 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18824 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18825 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)));
18827 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18830 pm_accepts_block_stack_pop(parser);
18831 pm_do_loop_stack_pop(parser);
18833 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18834 end_keyword = parser->previous;
18838 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18839 pm_parser_scope_pop(parser);
18844 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
18846 flush_block_exits(parser, previous_block_exits);
18848 return UP(pm_def_node_create(
18857 NTOK2PTR(
operator),
18861 NTOK2PTR(end_keyword)
18869parse_module(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18871 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18873 size_t opening_newline_index = token_newline_index(parser);
18874 parser_lex(parser);
18875 pm_token_t module_keyword = parser->previous;
18877 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));
18882 if (PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18883 pop_block_exits(parser, previous_block_exits);
18886 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
18889 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
18892 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18893 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
18899 name = parser->previous;
18900 if (name.
type != PM_TOKEN_CONSTANT) {
18901 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
18904 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)) {
18905 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18908 pm_parser_scope_push(parser,
true);
18909 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
18912 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18913 pm_accepts_block_stack_push(parser,
true);
18914 statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
18915 pm_accepts_block_stack_pop(parser);
18918 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18919 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18920 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)));
18922 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
18926 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18928 pm_parser_scope_pop(parser);
18929 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
18931 if (context_def_p(parser)) {
18932 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
18935 pop_block_exits(parser, previous_block_exits);
18937 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
18944parse_string_array(
pm_parser_t *parser, uint16_t depth) {
18945 parser_lex(parser);
18953 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
18954 switch (parser->current.type) {
18955 case PM_TOKEN_WORDS_SEP: {
18958 parser->explicit_encoding = NULL;
18960 if (current == NULL) {
18967 pm_array_node_elements_append(parser->arena, array, current);
18971 parser_lex(parser);
18974 case PM_TOKEN_STRING_CONTENT: {
18975 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
18976 pm_node_flag_set(
string, parse_unescaped_encoding(parser, parser->explicit_encoding));
18977 parser_lex(parser);
18979 if (current == NULL) {
18985 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
18990 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
18996 pm_interpolated_string_node_append(parser, interpolated, current);
18997 pm_interpolated_string_node_append(parser, interpolated,
string);
18998 current = UP(interpolated);
19000 assert(
false &&
"unreachable");
19005 case PM_TOKEN_EMBVAR: {
19006 if (current == NULL) {
19010 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19011 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19017 pm_interpolated_string_node_append(parser, interpolated, current);
19018 current = UP(interpolated);
19025 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19029 case PM_TOKEN_EMBEXPR_BEGIN: {
19030 if (current == NULL) {
19034 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19035 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19041 pm_interpolated_string_node_append(parser, interpolated, current);
19042 current = UP(interpolated);
19043 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19047 assert(
false &&
"unreachable");
19050 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19055 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19056 parser_lex(parser);
19063 pm_array_node_elements_append(parser->arena, array, current);
19067 if (match1(parser, PM_TOKEN_EOF)) {
19068 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19069 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19071 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19074 pm_array_node_close_set(parser, array, &closing);
19082parse_symbol_array(
pm_parser_t *parser, uint16_t depth) {
19083 parser_lex(parser);
19091 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19092 switch (parser->current.type) {
19093 case PM_TOKEN_WORDS_SEP: {
19096 parser->explicit_encoding = NULL;
19098 if (current == NULL) {
19105 pm_array_node_elements_append(parser->arena, array, current);
19109 parser_lex(parser);
19112 case PM_TOKEN_STRING_CONTENT: {
19113 if (current == NULL) {
19118 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
19119 parser_lex(parser);
19120 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19124 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
19125 parser_lex(parser);
19128 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19135 .
type = PM_TOKEN_STRING_CONTENT,
19140 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
19141 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
19142 parser_lex(parser);
19145 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
19146 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
19148 current = UP(interpolated);
19150 assert(
false &&
"unreachable");
19155 case PM_TOKEN_EMBVAR: {
19156 bool start_location_set =
false;
19157 if (current == NULL) {
19161 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19162 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19169 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19170 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
19171 PM_NODE_START_SET_NODE(interpolated, current);
19172 start_location_set =
true;
19173 current = UP(interpolated);
19180 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19182 if (!start_location_set) {
19183 PM_NODE_START_SET_NODE(current, part);
19187 case PM_TOKEN_EMBEXPR_BEGIN: {
19188 bool start_location_set =
false;
19189 if (current == NULL) {
19193 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19194 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19201 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19202 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
19203 PM_NODE_START_SET_NODE(interpolated, current);
19204 start_location_set =
true;
19205 current = UP(interpolated);
19206 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19210 assert(
false &&
"unreachable");
19213 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19215 if (!start_location_set) {
19216 PM_NODE_START_SET_NODE(current, part);
19221 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19222 parser_lex(parser);
19229 pm_array_node_elements_append(parser->arena, array, current);
19233 if (match1(parser, PM_TOKEN_EOF)) {
19234 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19235 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19237 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19239 pm_array_node_close_set(parser, array, &closing);
19249parse_parentheses(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19251 pm_node_flags_t paren_flags = 0;
19254 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19256 parser_lex(parser);
19258 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19259 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19260 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19267 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
19271 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT) && opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19272 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19275 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19276 pop_block_exits(parser, previous_block_exits);
19277 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
19282 context_push(parser, PM_CONTEXT_PARENS);
19283 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
19284 context_pop(parser);
19289 bool terminator_found =
false;
19291 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19292 terminator_found =
true;
19293 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19294 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
19295 terminator_found =
true;
19298 if (terminator_found) {
19300 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19301 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19302 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19310 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19311 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19312 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19315 parser_lex(parser);
19316 pop_block_exits(parser, previous_block_exits);
19318 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19324 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
19327 multi_target = pm_multi_target_node_create(parser);
19328 pm_multi_target_node_targets_append(parser, multi_target, statement);
19331 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
19332 multi_target->
rparen_loc = TOK2LOC(parser, &parser->previous);
19333 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
19334 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
19337 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
19338 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19339 accept1(parser, PM_TOKEN_NEWLINE);
19341 result = UP(multi_target);
19344 if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
19346 }
else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match2(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_COMMA)) {
19350 }
else if (flags & PM_PARSE_ACCEPTS_STATEMENT) {
19354 if (pm_binding_powers[parser->current.type].binary && !match1(parser, PM_TOKEN_EQUAL)) {
19355 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19357 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
19360 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19361 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
19364 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19374 pm_statements_node_body_append(parser, statements, statement,
true);
19376 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19382 context_push(parser, PM_CONTEXT_PARENS);
19383 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19386 pm_statements_node_body_append(parser, statements, statement,
true);
19390 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
19391 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19396 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
19397 pm_statements_node_body_append(parser, statements, node,
true);
19401 if (parser->recovering) {
19404 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering =
false;
19410 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE))
break;
19414 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19415 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
19416 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
19417 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19419 }
else if (!match1(parser, PM_TOKEN_EOF)) {
19422 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19426 context_pop(parser);
19427 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19436 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19438 pm_multi_target_node_targets_append(parser, multi_target, statement);
19440 statement = UP(multi_target);
19444 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
19445 const uint8_t *offset = parser->start + PM_NODE_END(statement);
19446 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
19447 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
19449 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
19452 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
19456 pop_block_exits(parser, previous_block_exits);
19457 pm_void_statements_check(parser, statements,
true);
19458 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19467parse_splat(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19471 if (token_begins_expression_p(parser->current.type)) {
19472 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19475 return UP(pm_splat_node_create(parser, &
operator, name));
19482parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
19483 switch (parser->current.type) {
19484 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
19485 parser_lex(parser);
19487 pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
19488 bool parsed_bare_hash =
false;
19490 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
19491 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
19495 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19501 if (accept1(parser, PM_TOKEN_COMMA)) {
19504 if (accepted_newline) {
19505 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
19510 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
19511 parser->previous.
start = parser->previous.
end;
19512 parser->previous.
type = 0;
19519 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
19523 if (accept1(parser, PM_TOKEN_USTAR)) {
19527 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
19528 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
19530 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));
19533 element = UP(pm_splat_node_create(parser, &
operator, expression));
19534 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
19535 if (parsed_bare_hash) {
19536 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
19539 element = UP(pm_keyword_hash_node_create(parser));
19542 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)) {
19543 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19546 pm_static_literals_free(&hash_keys);
19547 parsed_bare_hash =
true;
19549 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));
19551 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
19552 if (parsed_bare_hash) {
19553 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
19558 pm_hash_key_static_literals_add(parser, &hash_keys, element);
19561 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
19562 operator = parser->previous;
19565 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));
19566 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(
operator), value));
19567 pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
19569 element = UP(hash);
19570 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19571 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19574 pm_static_literals_free(&hash_keys);
19575 parsed_bare_hash =
true;
19579 pm_array_node_elements_append(parser->arena, array, element);
19580 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
19583 accept1(parser, PM_TOKEN_NEWLINE);
19585 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19586 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
19587 parser->previous.
start = parser->previous.
end;
19588 parser->previous.
type = 0;
19591 pm_array_node_close_set(parser, array, &parser->previous);
19595 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
19596 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
19597 return parse_parentheses(parser, binding_power, flags, depth);
19598 case PM_TOKEN_BRACE_LEFT_HASH: {
19599 parser_lex(parser);
19604 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
19606 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
19607 pm_static_literals_free(&hash_keys);
19609 accept1(parser, PM_TOKEN_NEWLINE);
19612 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
19613 pm_hash_node_closing_loc_set(parser, node, &parser->previous);
19617 case PM_TOKEN_CHARACTER_LITERAL: {
19618 pm_node_t *node = UP(pm_string_node_create_current_string(
19621 .type = PM_TOKEN_STRING_BEGIN,
19622 .start = parser->current.start,
19623 .end = parser->current.start + 1
19626 .type = PM_TOKEN_STRING_CONTENT,
19627 .start = parser->current.start + 1,
19628 .end = parser->current.end
19633 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
19637 parser_lex(parser);
19641 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19642 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19647 case PM_TOKEN_CLASS_VARIABLE: {
19648 parser_lex(parser);
19649 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->previous));
19651 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19652 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19657 case PM_TOKEN_CONSTANT: {
19658 parser_lex(parser);
19664 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
19665 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
19666 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19667 match1(parser, PM_TOKEN_BRACE_LEFT)
19670 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19671 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
19674 pm_node_t *node = UP(pm_constant_read_node_create(parser, &parser->previous));
19676 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19679 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19684 case PM_TOKEN_UCOLON_COLON: {
19685 parser_lex(parser);
19688 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19689 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous));
19691 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19692 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19697 case PM_TOKEN_UDOT_DOT:
19698 case PM_TOKEN_UDOT_DOT_DOT: {
19700 parser_lex(parser);
19702 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));
19708 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
19709 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
19712 return UP(pm_range_node_create(parser, NULL, &
operator, right));
19714 case PM_TOKEN_FLOAT:
19715 parser_lex(parser);
19716 return UP(pm_float_node_create(parser, &parser->previous));
19717 case PM_TOKEN_FLOAT_IMAGINARY:
19718 parser_lex(parser);
19719 return UP(pm_float_node_imaginary_create(parser, &parser->previous));
19720 case PM_TOKEN_FLOAT_RATIONAL:
19721 parser_lex(parser);
19722 return UP(pm_float_node_rational_create(parser, &parser->previous));
19723 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
19724 parser_lex(parser);
19725 return UP(pm_float_node_rational_imaginary_create(parser, &parser->previous));
19726 case PM_TOKEN_NUMBERED_REFERENCE: {
19727 parser_lex(parser);
19728 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
19730 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19731 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19736 case PM_TOKEN_GLOBAL_VARIABLE: {
19737 parser_lex(parser);
19738 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->previous));
19740 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19741 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19746 case PM_TOKEN_BACK_REFERENCE: {
19747 parser_lex(parser);
19748 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->previous));
19750 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19751 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19756 case PM_TOKEN_IDENTIFIER:
19757 case PM_TOKEN_METHOD_NAME: {
19758 parser_lex(parser);
19760 pm_node_t *node = parse_variable_call(parser);
19762 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
19770 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
19773 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
19782 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
19784 PM_NODE_LENGTH_SET_LOCATION(call, end);
19792 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
19793 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19794 match1(parser, PM_TOKEN_BRACE_LEFT)
19797 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19798 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
19800 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
19804 pm_node_unreference(parser, node);
19810 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
19812 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
19813 pm_node_unreference(parser, node);
19816 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
19824 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19825 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19830 case PM_TOKEN_HEREDOC_START: {
19833 assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
19836 size_t common_whitespace = (size_t) -1;
19837 parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
19839 parser_lex(parser);
19845 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19848 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19849 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
19851 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19852 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19854 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19857 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
19858 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
19865 node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19866 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19871 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
19875 cast->
closing_loc = TOK2LOC(parser, &parser->current);
19878 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19880 cast->
base.
type = PM_X_STRING_NODE;
19883 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19884 parse_heredoc_dedent_string(parser->arena, &cast->
unescaped, common_whitespace);
19888 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19894 pm_node_list_append(parser->arena, &parts, part);
19896 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19897 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19898 pm_node_list_append(parser->arena, &parts, part);
19904 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19906 cast->
parts = parts;
19908 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19909 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
19916 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19917 pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
19925 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19927 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19933 parse_heredoc_dedent(parser, nodes, common_whitespace);
19941 pm_lex_mode_t *whitespace_mode = parser->lex_modes.current;
19943 if (whitespace_mode->mode == PM_LEX_HEREDOC && whitespace_mode->as.heredoc.common_whitespace == &common_whitespace) {
19944 whitespace_mode->as.heredoc.common_whitespace = NULL;
19946 whitespace_mode = whitespace_mode->prev;
19947 }
while (whitespace_mode != NULL);
19949 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19950 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19955 case PM_TOKEN_INSTANCE_VARIABLE: {
19956 parser_lex(parser);
19957 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
19959 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19960 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19965 case PM_TOKEN_INTEGER: {
19966 pm_node_flags_t base = parser->integer.base;
19967 parser_lex(parser);
19968 return UP(pm_integer_node_create(parser, base, &parser->previous));
19970 case PM_TOKEN_INTEGER_IMAGINARY: {
19971 pm_node_flags_t base = parser->integer.base;
19972 parser_lex(parser);
19973 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
19975 case PM_TOKEN_INTEGER_RATIONAL: {
19976 pm_node_flags_t base = parser->integer.base;
19977 parser_lex(parser);
19978 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
19980 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
19981 pm_node_flags_t base = parser->integer.base;
19982 parser_lex(parser);
19983 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
19985 case PM_TOKEN_KEYWORD___ENCODING__:
19986 parser_lex(parser);
19987 return UP(pm_source_encoding_node_create(parser, &parser->previous));
19988 case PM_TOKEN_KEYWORD___FILE__:
19989 parser_lex(parser);
19990 return UP(pm_source_file_node_create(parser, &parser->previous));
19991 case PM_TOKEN_KEYWORD___LINE__:
19992 parser_lex(parser);
19993 return UP(pm_source_line_node_create(parser, &parser->previous));
19994 case PM_TOKEN_KEYWORD_ALIAS: {
19995 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
19996 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
19999 parser_lex(parser);
20002 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
20003 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
20005 switch (PM_NODE_TYPE(new_name)) {
20006 case PM_BACK_REFERENCE_READ_NODE:
20007 case PM_NUMBERED_REFERENCE_READ_NODE:
20008 case PM_GLOBAL_VARIABLE_READ_NODE: {
20009 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)) {
20010 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
20011 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
20013 }
else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
20014 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
20015 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
20018 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
20020 case PM_SYMBOL_NODE:
20021 case PM_INTERPOLATED_SYMBOL_NODE: {
20022 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)) {
20023 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
20024 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
20029 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
20032 case PM_TOKEN_KEYWORD_CASE:
20033 return parse_case(parser, flags, depth);
20034 case PM_TOKEN_KEYWORD_BEGIN: {
20035 size_t opening_newline_index = token_newline_index(parser);
20036 parser_lex(parser);
20038 pm_token_t begin_keyword = parser->previous;
20039 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20042 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20045 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
20046 pm_accepts_block_stack_push(parser,
true);
20047 begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
20048 pm_accepts_block_stack_pop(parser);
20049 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20052 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
20053 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
20054 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
20056 PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->previous);
20057 pm_begin_node_end_keyword_set(parser, begin_node, &parser->previous);
20058 pop_block_exits(parser, previous_block_exits);
20059 return UP(begin_node);
20061 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
20063 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20065 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20066 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
20069 parser_lex(parser);
20072 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
20074 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
20076 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
20077 pm_context_t context = parser->current_context->context;
20078 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
20079 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
20082 flush_block_exits(parser, previous_block_exits);
20083 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
20085 case PM_TOKEN_KEYWORD_BREAK:
20086 case PM_TOKEN_KEYWORD_NEXT:
20087 case PM_TOKEN_KEYWORD_RETURN: {
20088 parser_lex(parser);
20094 token_begins_expression_p(parser->current.type) ||
20095 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
20097 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
20099 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
20101 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
20104 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
20105 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.
type));
20114 if (parser->previous.
type == PM_TOKEN_COMMA && match1(parser, PM_TOKEN_EOF)) {
20115 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
20122 if (arguments.
block != NULL) {
20123 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20124 pm_node_unreference(parser, arguments.
block);
20125 arguments.
block = NULL;
20129 switch (keyword.
type) {
20130 case PM_TOKEN_KEYWORD_BREAK: {
20132 if (!parser->partial_script) parse_block_exit(parser, node);
20135 case PM_TOKEN_KEYWORD_NEXT: {
20137 if (!parser->partial_script) parse_block_exit(parser, node);
20140 case PM_TOKEN_KEYWORD_RETURN: {
20142 parse_return(parser, node);
20146 assert(
false &&
"unreachable");
20147 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20150 case PM_TOKEN_KEYWORD_SUPER: {
20151 parser_lex(parser);
20155 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20160 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
20162 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
20165 return UP(pm_super_node_create(parser, &keyword, &arguments));
20167 case PM_TOKEN_KEYWORD_YIELD: {
20168 parser_lex(parser);
20172 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
20178 if (arguments.
block != NULL) {
20179 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20180 pm_node_unreference(parser, arguments.
block);
20181 arguments.
block = NULL;
20185 if (!parser->parsing_eval && !parser->partial_script) parse_yield(parser, node);
20189 case PM_TOKEN_KEYWORD_CLASS:
20190 return parse_class(parser, flags, depth);
20191 case PM_TOKEN_KEYWORD_DEF:
20192 return parse_def(parser, binding_power, flags, depth);
20193 case PM_TOKEN_KEYWORD_DEFINED: {
20194 parser_lex(parser);
20201 context_push(parser, PM_CONTEXT_DEFINED);
20202 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
20204 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20205 lparen = parser->previous;
20207 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20208 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20211 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));
20213 if (!parser->recovering) {
20214 accept1(parser, PM_TOKEN_NEWLINE);
20215 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20216 rparen = parser->previous;
20220 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
20223 context_pop(parser);
20224 return UP(pm_defined_node_create(
20232 case PM_TOKEN_KEYWORD_END_UPCASE: {
20233 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20234 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
20237 parser_lex(parser);
20240 if (context_def_p(parser)) {
20241 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
20244 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
20246 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
20248 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
20249 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
20251 case PM_TOKEN_KEYWORD_FALSE:
20252 parser_lex(parser);
20253 return UP(pm_false_node_create(parser, &parser->previous));
20254 case PM_TOKEN_KEYWORD_FOR: {
20255 size_t opening_newline_index = token_newline_index(parser);
20256 parser_lex(parser);
20261 context_push(parser, PM_CONTEXT_FOR_INDEX);
20264 if (accept1(parser, PM_TOKEN_USTAR)) {
20265 index = parse_splat(parser, flags, depth);
20266 }
else if (token_begins_expression_p(parser->current.type)) {
20267 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
20269 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
20270 index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
20274 if (match1(parser, PM_TOKEN_COMMA)) {
20275 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20277 index = parse_target(parser, index,
false,
false);
20280 context_pop(parser);
20281 pm_do_loop_stack_push(parser,
true);
20283 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
20286 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));
20287 pm_do_loop_stack_pop(parser);
20290 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20291 do_keyword = parser->previous;
20293 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
20294 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
20299 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20300 statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
20303 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
20304 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
20306 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous));
20308 case PM_TOKEN_KEYWORD_IF:
20309 if (parser_end_of_line_p(parser)) {
20310 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
20313 size_t opening_newline_index = token_newline_index(parser);
20314 bool if_after_else = parser->previous.
type == PM_TOKEN_KEYWORD_ELSE;
20315 parser_lex(parser);
20317 return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
20318 case PM_TOKEN_KEYWORD_UNDEF: {
20319 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20320 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
20323 parser_lex(parser);
20324 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
20325 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20327 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20329 pm_undef_node_append(parser->arena, undef, name);
20331 while (match1(parser, PM_TOKEN_COMMA)) {
20332 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
20333 parser_lex(parser);
20334 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20336 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20340 pm_undef_node_append(parser->arena, undef, name);
20346 case PM_TOKEN_KEYWORD_NOT: {
20347 parser_lex(parser);
20360 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
20361 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
20362 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
20364 accept1(parser, PM_TOKEN_NEWLINE);
20365 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
20368 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
20371 accept1(parser, PM_TOKEN_NEWLINE);
20373 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20376 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20377 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20379 arguments.
opening_loc = TOK2LOC(parser, &lparen);
20380 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));
20382 if (!parser->recovering) {
20383 accept1(parser, PM_TOKEN_NEWLINE);
20384 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20385 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
20389 receiver = parse_expression(parser, PM_BINDING_POWER_NOT, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | PM_PARSE_ACCEPTS_COMMAND_CALL), PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
20392 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
20394 case PM_TOKEN_KEYWORD_UNLESS: {
20395 size_t opening_newline_index = token_newline_index(parser);
20396 parser_lex(parser);
20398 return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
20400 case PM_TOKEN_KEYWORD_MODULE:
20401 return parse_module(parser, flags, depth);
20402 case PM_TOKEN_KEYWORD_NIL:
20403 parser_lex(parser);
20404 return UP(pm_nil_node_create(parser, &parser->previous));
20405 case PM_TOKEN_KEYWORD_REDO: {
20406 parser_lex(parser);
20408 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
20409 if (!parser->partial_script) parse_block_exit(parser, node);
20413 case PM_TOKEN_KEYWORD_RETRY: {
20414 parser_lex(parser);
20416 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
20417 parse_retry(parser, node);
20421 case PM_TOKEN_KEYWORD_SELF:
20422 parser_lex(parser);
20423 return UP(pm_self_node_create(parser, &parser->previous));
20424 case PM_TOKEN_KEYWORD_TRUE:
20425 parser_lex(parser);
20426 return UP(pm_true_node_create(parser, &parser->previous));
20427 case PM_TOKEN_KEYWORD_UNTIL: {
20428 size_t opening_newline_index = token_newline_index(parser);
20430 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20431 pm_do_loop_stack_push(parser,
true);
20433 parser_lex(parser);
20435 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));
20437 pm_do_loop_stack_pop(parser);
20438 context_pop(parser);
20441 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20442 do_keyword = parser->previous;
20444 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20448 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20449 pm_accepts_block_stack_push(parser,
true);
20450 statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20451 pm_accepts_block_stack_pop(parser);
20452 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20455 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20456 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
20458 return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20460 case PM_TOKEN_KEYWORD_WHILE: {
20461 size_t opening_newline_index = token_newline_index(parser);
20463 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20464 pm_do_loop_stack_push(parser,
true);
20466 parser_lex(parser);
20468 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));
20470 pm_do_loop_stack_pop(parser);
20471 context_pop(parser);
20474 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20475 do_keyword = parser->previous;
20477 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20481 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20482 pm_accepts_block_stack_push(parser,
true);
20483 statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20484 pm_accepts_block_stack_pop(parser);
20485 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20488 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20489 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
20491 return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20493 case PM_TOKEN_PERCENT_LOWER_I: {
20494 parser_lex(parser);
20499 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20500 accept1(parser, PM_TOKEN_WORDS_SEP);
20501 if (match1(parser, PM_TOKEN_STRING_END))
break;
20505 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20507 if (current == NULL) {
20508 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20509 parser_lex(parser);
20510 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20511 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20512 parser_lex(parser);
20514 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20517 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20518 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20519 parser_lex(parser);
20522 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20523 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20526 current = UP(interpolated);
20528 assert(
false &&
"unreachable");
20533 pm_array_node_elements_append(parser->arena, array, current);
20536 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20541 if (match1(parser, PM_TOKEN_EOF)) {
20542 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20543 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20545 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20547 pm_array_node_close_set(parser, array, &closing);
20551 case PM_TOKEN_PERCENT_UPPER_I:
20552 return parse_symbol_array(parser, depth);
20553 case PM_TOKEN_PERCENT_LOWER_W: {
20554 parser_lex(parser);
20559 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20560 accept1(parser, PM_TOKEN_WORDS_SEP);
20561 if (match1(parser, PM_TOKEN_STRING_END))
break;
20565 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20566 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20569 if (current == NULL) {
20571 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20573 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20575 pm_interpolated_string_node_append(parser, interpolated, current);
20576 pm_interpolated_string_node_append(parser, interpolated,
string);
20577 current = UP(interpolated);
20579 assert(
false &&
"unreachable");
20581 parser_lex(parser);
20585 pm_array_node_elements_append(parser->arena, array, current);
20588 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20593 if (match1(parser, PM_TOKEN_EOF)) {
20594 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20595 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20597 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20600 pm_array_node_close_set(parser, array, &closing);
20603 case PM_TOKEN_PERCENT_UPPER_W:
20604 return parse_string_array(parser, depth);
20605 case PM_TOKEN_REGEXP_BEGIN: {
20607 parser_lex(parser);
20609 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20614 .
type = PM_TOKEN_STRING_CONTENT,
20615 .start = parser->previous.
end,
20616 .end = parser->previous.
end
20619 parser_lex(parser);
20622 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20628 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20635 parser_lex(parser);
20640 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20647 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20648 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20656 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20658 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20659 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
20663 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20666 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20671 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20677 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20678 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20679 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20684 if (match1(parser, PM_TOKEN_EOF)) {
20685 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20686 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20688 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20691 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20692 return UP(interpolated);
20694 case PM_TOKEN_XSTRING_BEGIN:
20695 case PM_TOKEN_PERCENT_LOWER_X: {
20696 parser_lex(parser);
20703 if (match1(parser, PM_TOKEN_STRING_END)) {
20708 .
type = PM_TOKEN_STRING_CONTENT,
20709 .start = parser->previous.
end,
20710 .end = parser->previous.
end
20713 parser_lex(parser);
20714 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
20719 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20726 parser_lex(parser);
20728 if (match1(parser, PM_TOKEN_STRING_END)) {
20729 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
20730 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
20731 parser_lex(parser);
20737 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20739 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20740 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
20742 pm_interpolated_xstring_node_append(parser->arena, node, part);
20747 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20751 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20752 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20753 pm_interpolated_xstring_node_append(parser->arena, node, part);
20758 if (match1(parser, PM_TOKEN_EOF)) {
20759 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20760 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20762 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20764 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
20768 case PM_TOKEN_USTAR: {
20769 parser_lex(parser);
20774 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20775 pm_parser_err_prefix(parser, diag_id);
20776 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20779 pm_node_t *splat = parse_splat(parser, flags, depth);
20781 if (match1(parser, PM_TOKEN_COMMA)) {
20782 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20784 return parse_target_validate(parser, splat,
true);
20787 case PM_TOKEN_BANG: {
20788 if (binding_power > PM_BINDING_POWER_UNARY) {
20789 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20792 parser_lex(parser);
20795 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));
20796 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20798 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20801 case PM_TOKEN_TILDE: {
20802 if (binding_power > PM_BINDING_POWER_UNARY) {
20803 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20805 parser_lex(parser);
20808 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));
20809 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20813 case PM_TOKEN_UMINUS: {
20814 if (binding_power > PM_BINDING_POWER_UNARY) {
20815 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20817 parser_lex(parser);
20820 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));
20821 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20825 case PM_TOKEN_UMINUS_NUM: {
20826 parser_lex(parser);
20829 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));
20831 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20832 pm_token_t exponent_operator = parser->previous;
20833 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));
20834 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20835 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20837 switch (PM_NODE_TYPE(node)) {
20838 case PM_INTEGER_NODE:
20839 case PM_FLOAT_NODE:
20840 case PM_RATIONAL_NODE:
20841 case PM_IMAGINARY_NODE:
20842 parse_negative_numeric(node);
20845 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20852 case PM_TOKEN_MINUS_GREATER: {
20853 int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
20854 parser->lambda_enclosure_nesting = parser->enclosure_nesting;
20856 size_t opening_newline_index = token_newline_index(parser);
20857 parser_lex(parser);
20860 pm_parser_scope_push(parser,
false);
20864 switch (parser->current.type) {
20865 case PM_TOKEN_PARENTHESIS_LEFT: {
20867 parser_lex(parser);
20869 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20870 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20872 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20875 accept1(parser, PM_TOKEN_NEWLINE);
20876 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20878 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
20881 case PM_CASE_PARAMETER: {
20882 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
20886 block_parameters = NULL;
20894 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20895 opening = parser->previous;
20897 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20898 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
20901 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20909 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
20910 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20918 pm_accepts_block_stack_push(parser,
true);
20919 expect1(parser, PM_TOKEN_KEYWORD_DO_LAMBDA, PM_ERR_LAMBDA_OPEN);
20920 opening = parser->previous;
20926 parser->lambda_enclosure_nesting = -1;
20928 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20929 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
20932 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20933 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20934 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)));
20936 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20939 pm_accepts_block_stack_pop(parser);
20944 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
20945 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20949 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
20950 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->previous);
20952 pm_parser_scope_pop(parser);
20954 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->previous, parameters, body));
20956 case PM_TOKEN_UPLUS: {
20957 if (binding_power > PM_BINDING_POWER_UNARY) {
20958 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20960 parser_lex(parser);
20963 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));
20964 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20968 case PM_TOKEN_STRING_BEGIN:
20969 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
20970 case PM_TOKEN_SYMBOL_BEGIN: {
20972 parser_lex(parser);
20974 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20977 pm_context_t recoverable = context_recoverable(parser, &parser->current);
20979 if (recoverable != PM_CONTEXT_NONE) {
20980 parser->recovering =
true;
20985 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20986 pm_parser_err_prefix(parser, diag_id);
20992 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
20993 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20997 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
20999 pm_parser_err_prefix(parser, diag_id);
21002 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
21008parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth);
21018parse_rescue_modifier_terminator(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
21019 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
21020 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21021 parser_lex(parser);
21022 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));
21036parse_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) {
21037 pm_node_t *value = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) : (previous_binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0))), diag_id, (uint16_t) (depth + 1));
21043 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(parser, value) || pm_block_call_p(value))) {
21044 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21045 parser_lex(parser);
21046 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));
21051 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21052 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21055 parser_lex(parser);
21060 bool statement_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21061 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21063 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21064 context_pop(parser);
21069 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21070 parse_rescue_modifier_terminator(parser, flags, depth);
21073 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21085 switch (PM_NODE_TYPE(node)) {
21086 case PM_BEGIN_NODE: {
21091 case PM_LOCAL_VARIABLE_WRITE_NODE: {
21093 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
21096 case PM_PARENTHESES_NODE: {
21098 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
21101 case PM_STATEMENTS_NODE: {
21106 parse_assignment_value_local(parser, statement);
21128parse_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) {
21129 bool statement_level = (previous_binding_power == PM_BINDING_POWER_STATEMENT) || (flags & PM_PARSE_ACCEPTS_STATEMENT);
21131 bool permitted =
true;
21132 if (!statement_level && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
21137 uint8_t command_call_flag = (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT)
21138 ? (uint8_t) (flags & PM_PARSE_ACCEPTS_COMMAND_CALL)
21139 : ((previous_binding_power < PM_BINDING_POWER_MODIFIER || statement_level) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0);
21141 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));
21142 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
21144 parse_assignment_value_local(parser, value);
21145 bool single_value =
true;
21150 if (statement_level && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
21151 single_value =
false;
21154 pm_array_node_elements_append(parser->arena, array, value);
21157 while (accept1(parser, PM_TOKEN_COMMA)) {
21158 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
21160 pm_array_node_elements_append(parser->arena, array, element);
21161 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
21163 parse_assignment_value_local(parser, element);
21171 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))) {
21172 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21173 parser_lex(parser);
21174 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));
21179 bool multiple_assignment = (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1));
21180 if ((single_value || multiple_assignment) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21181 bool command_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21190 if (multiple_assignment && command_value)
return value;
21192 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21195 parser_lex(parser);
21201 bool statement_value = multiple_assignment || command_value;
21202 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21204 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21205 context_pop(parser);
21210 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21211 parse_rescue_modifier_terminator(parser, flags, depth);
21214 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21233parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth) {
21238 if (match1(parser, PM_TOKEN_USTAR)) {
21240 parser_lex(parser);
21241 value = parse_splat(parser, flags, depth);
21248 value = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, flags | PM_PARSE_ACCEPTS_STATEMENT, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21249 multiple = match1(parser, PM_TOKEN_COMMA) || PM_NODE_TYPE_P(value, PM_MULTI_TARGET_NODE);
21253 pm_node_t *target = parse_targets_validate(parser, value, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21260 if (!match1(parser, PM_TOKEN_EQUAL)) {
21261 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
21266 parser_lex(parser);
21268 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));
21269 value = parse_write(parser, target, &
operator, values);
21276 if (!PM_NODE_TYPE_P(value, PM_MATCH_REQUIRED_NODE) && !PM_NODE_TYPE_P(value, PM_MATCH_PREDICATE_NODE)) {
21277 parse_rescue_modifier_terminator(parser, flags, depth);
21285 return parse_expression(parser, PM_BINDING_POWER_DEFINED, flags, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21298 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
21299 pm_node_unreference(parser, UP(call_node->
arguments));
21303 if (call_node->
block != NULL) {
21304 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
21305 pm_node_unreference(parser, UP(call_node->
block));
21306 call_node->
block = NULL;
21311pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21314 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21315 uint8_t value = escape_hexadecimal_digit(*cursor);
21318 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21319 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21323 pm_buffer_append_byte(unescaped, value);
21325 pm_buffer_append_string(unescaped,
"\\x", 2);
21332pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21333 uint8_t value = (uint8_t) (*cursor -
'0');
21336 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21337 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21340 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21341 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21346 pm_buffer_append_byte(unescaped, value);
21352 const uint8_t *start = cursor - 1;
21355 if (cursor >= end) {
21356 pm_buffer_append_string(unescaped,
"\\u", 2);
21360 if (*cursor !=
'{') {
21361 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21362 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21364 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21365 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21368 return cursor + length;
21373 while (cursor < end && *cursor ==
' ') cursor++;
21375 if (cursor >= end)
break;
21376 if (*cursor ==
'}') {
21381 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21385 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21387 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21395pm_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) {
21396 const uint8_t *end = source + length;
21397 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21400 if (++cursor >= end) {
21401 pm_buffer_append_byte(unescaped,
'\\');
21407 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21409 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21410 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21413 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
21416 pm_buffer_append_byte(unescaped,
'\\');
21420 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->encoding_changed, parser->encoding);
21421 if (next_cursor == NULL)
break;
21423 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21424 cursor = next_cursor;
21427 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21439 const uint8_t *source = pm_string_source(capture);
21440 size_t length = pm_string_length(capture);
21451 const uint8_t *cursor = pm_memchr(source,
'\\', length, parser->encoding_changed, parser->encoding);
21452 if (PRISM_UNLIKELY(cursor != NULL)) {
21453 pm_named_capture_escape(parser, &unescaped, source, length, cursor, shared ? NULL : &call->receiver->location);
21454 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21455 length = pm_buffer_length(&unescaped);
21458 const uint8_t *start;
21459 const uint8_t *end;
21464 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21465 pm_buffer_cleanup(&unescaped);
21473 end = source + length;
21474 name = pm_parser_constant_id_raw(parser, start, end);
21478 start = parser->start + PM_NODE_START(call->
receiver);
21479 end = parser->start + PM_NODE_END(call->
receiver);
21481 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
21482 memcpy(memory, source, length);
21483 name = pm_parser_constant_id_owned(parser, memory, length);
21488 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21489 pm_constant_id_list_append(parser->arena, names, name);
21492 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21495 if (pm_local_is_keyword((
const char *) source, length)) {
21496 pm_buffer_cleanup(&unescaped);
21502 pm_parser_local_add(parser, name, start, end, 0);
21507 if (callback_data->match == NULL) {
21508 callback_data->match = pm_match_write_node_create(parser, call);
21513 pm_token_t token = { .type = 0, .start = start, .end = end };
21515 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &token_loc, name, depth == -1 ? 0 : (uint32_t) depth));
21516 pm_node_list_append(parser->arena, &callback_data->match->
targets, target);
21519 pm_buffer_cleanup(&unescaped);
21535 pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content),
false, extended_mode, parse_regular_expression_named_capture, &callback_data);
21537 if (callback_data.match != NULL) {
21538 return UP(callback_data.match);
21545parse_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) {
21548 switch (token.type) {
21549 case PM_TOKEN_EQUAL: {
21550 switch (PM_NODE_TYPE(node)) {
21551 case PM_CALL_NODE: {
21557 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21558 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
21562 case PM_CASE_WRITABLE: {
21566 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21567 pm_parser_local_add_location(parser, &node->
location, 0);
21570 parser_lex(parser);
21571 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));
21573 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
21574 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21577 return parse_write(parser, node, &token, value);
21579 case PM_SPLAT_NODE: {
21581 pm_multi_target_node_targets_append(parser, multi_target, node);
21583 parser_lex(parser);
21584 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));
21585 return parse_write(parser, UP(multi_target), &token, value);
21587 case PM_SOURCE_ENCODING_NODE:
21588 case PM_FALSE_NODE:
21589 case PM_SOURCE_FILE_NODE:
21590 case PM_SOURCE_LINE_NODE:
21593 case PM_TRUE_NODE: {
21596 parser_lex(parser);
21597 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21598 return parse_unwriteable_write(parser, node, &token, value);
21604 parser_lex(parser);
21605 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21609 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21610 switch (PM_NODE_TYPE(node)) {
21611 case PM_BACK_REFERENCE_READ_NODE:
21612 case PM_NUMBERED_REFERENCE_READ_NODE:
21613 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21615 case PM_GLOBAL_VARIABLE_READ_NODE: {
21616 parser_lex(parser);
21618 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21619 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
21623 case PM_CLASS_VARIABLE_READ_NODE: {
21624 parser_lex(parser);
21626 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21631 case PM_CONSTANT_PATH_NODE: {
21632 parser_lex(parser);
21634 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21637 return parse_shareable_constant_write(parser, write);
21639 case PM_CONSTANT_READ_NODE: {
21640 parser_lex(parser);
21642 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21645 if (context_def_p(parser)) {
21646 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21649 return parse_shareable_constant_write(parser, write);
21651 case PM_INSTANCE_VARIABLE_READ_NODE: {
21652 parser_lex(parser);
21654 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21659 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21661 parser_lex(parser);
21663 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21664 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
21666 pm_node_unreference(parser, node);
21669 case PM_LOCAL_VARIABLE_READ_NODE: {
21670 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21672 pm_node_unreference(parser, node);
21676 parser_lex(parser);
21678 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21679 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21683 case PM_CALL_NODE: {
21689 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21692 parser_lex(parser);
21694 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21695 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21702 parser_lex(parser);
21707 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21708 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21709 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
21713 if (pm_call_node_writable_p(parser, cast)) {
21714 parse_write_name(parser, &cast->
name);
21716 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21719 parse_call_operator_write(parser, cast, &token);
21720 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21721 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
21723 case PM_MULTI_WRITE_NODE: {
21724 parser_lex(parser);
21725 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21729 parser_lex(parser);
21734 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21738 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21739 switch (PM_NODE_TYPE(node)) {
21740 case PM_BACK_REFERENCE_READ_NODE:
21741 case PM_NUMBERED_REFERENCE_READ_NODE:
21742 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21744 case PM_GLOBAL_VARIABLE_READ_NODE: {
21745 parser_lex(parser);
21747 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21748 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
21752 case PM_CLASS_VARIABLE_READ_NODE: {
21753 parser_lex(parser);
21755 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21760 case PM_CONSTANT_PATH_NODE: {
21761 parser_lex(parser);
21763 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21766 return parse_shareable_constant_write(parser, write);
21768 case PM_CONSTANT_READ_NODE: {
21769 parser_lex(parser);
21771 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21774 if (context_def_p(parser)) {
21775 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21778 return parse_shareable_constant_write(parser, write);
21780 case PM_INSTANCE_VARIABLE_READ_NODE: {
21781 parser_lex(parser);
21783 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21788 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21790 parser_lex(parser);
21792 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21793 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
21795 pm_node_unreference(parser, node);
21798 case PM_LOCAL_VARIABLE_READ_NODE: {
21799 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21800 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21801 pm_node_unreference(parser, node);
21805 parser_lex(parser);
21807 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21808 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21812 case PM_CALL_NODE: {
21818 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21821 parser_lex(parser);
21823 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21824 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21831 parser_lex(parser);
21836 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21837 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21838 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
21842 if (pm_call_node_writable_p(parser, cast)) {
21843 parse_write_name(parser, &cast->
name);
21845 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21848 parse_call_operator_write(parser, cast, &token);
21849 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21850 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
21852 case PM_MULTI_WRITE_NODE: {
21853 parser_lex(parser);
21854 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21858 parser_lex(parser);
21863 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21867 case PM_TOKEN_AMPERSAND_EQUAL:
21868 case PM_TOKEN_CARET_EQUAL:
21869 case PM_TOKEN_GREATER_GREATER_EQUAL:
21870 case PM_TOKEN_LESS_LESS_EQUAL:
21871 case PM_TOKEN_MINUS_EQUAL:
21872 case PM_TOKEN_PERCENT_EQUAL:
21873 case PM_TOKEN_PIPE_EQUAL:
21874 case PM_TOKEN_PLUS_EQUAL:
21875 case PM_TOKEN_SLASH_EQUAL:
21876 case PM_TOKEN_STAR_EQUAL:
21877 case PM_TOKEN_STAR_STAR_EQUAL: {
21878 switch (PM_NODE_TYPE(node)) {
21879 case PM_BACK_REFERENCE_READ_NODE:
21880 case PM_NUMBERED_REFERENCE_READ_NODE:
21881 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21883 case PM_GLOBAL_VARIABLE_READ_NODE: {
21884 parser_lex(parser);
21886 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21887 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
21891 case PM_CLASS_VARIABLE_READ_NODE: {
21892 parser_lex(parser);
21894 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21899 case PM_CONSTANT_PATH_NODE: {
21900 parser_lex(parser);
21902 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21905 return parse_shareable_constant_write(parser, write);
21907 case PM_CONSTANT_READ_NODE: {
21908 parser_lex(parser);
21910 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21913 if (context_def_p(parser)) {
21914 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21917 return parse_shareable_constant_write(parser, write);
21919 case PM_INSTANCE_VARIABLE_READ_NODE: {
21920 parser_lex(parser);
21922 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21927 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21929 parser_lex(parser);
21931 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21932 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21934 pm_node_unreference(parser, node);
21937 case PM_LOCAL_VARIABLE_READ_NODE: {
21938 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21939 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21940 pm_node_unreference(parser, node);
21944 parser_lex(parser);
21946 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21947 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21951 case PM_CALL_NODE: {
21952 parser_lex(parser);
21958 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21961 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21962 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21970 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21971 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21972 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21976 if (pm_call_node_writable_p(parser, cast)) {
21977 parse_write_name(parser, &cast->
name);
21979 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21982 parse_call_operator_write(parser, cast, &token);
21983 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21984 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21986 case PM_MULTI_WRITE_NODE: {
21987 parser_lex(parser);
21988 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21992 parser_lex(parser);
21997 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
22001 case PM_TOKEN_AMPERSAND_AMPERSAND:
22002 case PM_TOKEN_KEYWORD_AND: {
22003 parser_lex(parser);
22005 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));
22006 return UP(pm_and_node_create(parser, node, &token, right));
22008 case PM_TOKEN_KEYWORD_OR:
22009 case PM_TOKEN_PIPE_PIPE: {
22010 parser_lex(parser);
22012 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));
22013 return UP(pm_or_node_create(parser, node, &token, right));
22015 case PM_TOKEN_EQUAL_TILDE: {
22023 parser_lex(parser);
22024 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));
22027 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
22033 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
22040 bool interpolated =
false;
22041 size_t total_length = 0;
22045 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
22046 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
22048 interpolated =
true;
22053 if (!interpolated && total_length > 0) {
22054 void *memory =
xmalloc(total_length);
22055 if (!memory) abort();
22057 uint8_t *cursor = memory;
22060 size_t length = pm_string_length(unescaped);
22062 memcpy(cursor, pm_string_source(unescaped), length);
22067 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
22069 result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
22070 pm_string_cleanup(&owned);
22072 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
22083 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
22085 if (name_data.match != NULL) {
22086 result = UP(name_data.match);
22092 case PM_TOKEN_UAMPERSAND:
22093 case PM_TOKEN_USTAR:
22094 case PM_TOKEN_USTAR_STAR:
22097 case PM_TOKEN_BANG_EQUAL:
22098 case PM_TOKEN_BANG_TILDE:
22099 case PM_TOKEN_EQUAL_EQUAL:
22100 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
22101 case PM_TOKEN_LESS_EQUAL_GREATER:
22102 case PM_TOKEN_CARET:
22103 case PM_TOKEN_PIPE:
22104 case PM_TOKEN_AMPERSAND:
22105 case PM_TOKEN_GREATER_GREATER:
22106 case PM_TOKEN_LESS_LESS:
22107 case PM_TOKEN_MINUS:
22108 case PM_TOKEN_PLUS:
22109 case PM_TOKEN_PERCENT:
22110 case PM_TOKEN_SLASH:
22111 case PM_TOKEN_STAR:
22112 case PM_TOKEN_STAR_STAR: {
22113 parser_lex(parser);
22115 switch (PM_NODE_TYPE(node)) {
22116 case PM_RESCUE_MODIFIER_NODE: {
22119 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22123 case PM_AND_NODE: {
22125 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22126 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22132 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22133 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22141 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));
22142 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
22144 case PM_TOKEN_GREATER:
22145 case PM_TOKEN_GREATER_EQUAL:
22146 case PM_TOKEN_LESS:
22147 case PM_TOKEN_LESS_EQUAL: {
22148 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
22149 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
22152 parser_lex(parser);
22153 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));
22154 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
22156 case PM_TOKEN_AMPERSAND_DOT:
22157 case PM_TOKEN_DOT: {
22158 parser_lex(parser);
22163 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
22164 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22165 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
22168 switch (PM_NODE_TYPE(node)) {
22169 case PM_RESCUE_MODIFIER_NODE: {
22172 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22176 case PM_AND_NODE: {
22178 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22179 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22185 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22186 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22196 switch (parser->current.type) {
22197 case PM_CASE_OPERATOR:
22198 case PM_CASE_KEYWORD:
22199 case PM_TOKEN_CONSTANT:
22200 case PM_TOKEN_IDENTIFIER:
22201 case PM_TOKEN_METHOD_NAME: {
22202 parser_lex(parser);
22203 message = parser->previous;
22207 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
22208 message = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
22212 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22213 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
22216 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
22219 match1(parser, PM_TOKEN_COMMA)
22221 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22226 case PM_TOKEN_DOT_DOT:
22227 case PM_TOKEN_DOT_DOT_DOT: {
22228 parser_lex(parser);
22231 if (token_begins_expression_p(parser->current.type)) {
22232 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22235 return UP(pm_range_node_create(parser, node, &token, right));
22237 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
22239 parser_lex(parser);
22241 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));
22242 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
22244 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
22246 parser_lex(parser);
22248 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));
22249 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
22251 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
22252 parser_lex(parser);
22254 pm_statements_node_body_append(parser, statements, node,
true);
22256 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));
22257 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));
22259 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
22260 parser_lex(parser);
22262 pm_statements_node_body_append(parser, statements, node,
true);
22264 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));
22265 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));
22267 case PM_TOKEN_QUESTION_MARK: {
22268 context_push(parser, PM_CONTEXT_TERNARY);
22270 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22273 parser_lex(parser);
22275 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));
22277 if (parser->recovering) {
22285 pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
22287 context_pop(parser);
22288 pop_block_exits(parser, previous_block_exits);
22289 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
22292 accept1(parser, PM_TOKEN_NEWLINE);
22293 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
22296 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));
22298 context_pop(parser);
22299 pop_block_exits(parser, previous_block_exits);
22300 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
22302 case PM_TOKEN_COLON_COLON: {
22303 parser_lex(parser);
22306 switch (parser->current.type) {
22307 case PM_TOKEN_CONSTANT: {
22308 parser_lex(parser);
22312 (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
22313 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && (token_begins_expression_p(parser->current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
22324 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22325 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
22328 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
22332 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22333 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22338 case PM_CASE_OPERATOR:
22339 case PM_CASE_KEYWORD:
22340 case PM_TOKEN_IDENTIFIER:
22341 case PM_TOKEN_METHOD_NAME: {
22342 parser_lex(parser);
22348 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22349 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22352 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22353 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22358 case PM_TOKEN_PARENTHESIS_LEFT: {
22362 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22364 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
22367 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
22368 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
22372 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22373 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
22374 parser_lex(parser);
22375 accept1(parser, PM_TOKEN_NEWLINE);
22377 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));
22378 context_pop(parser);
22380 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
22382 case PM_TOKEN_BRACKET_LEFT: {
22383 parser_lex(parser);
22386 arguments.
opening_loc = TOK2LOC(parser, &parser->previous);
22388 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22389 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
22390 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22393 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
22397 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22398 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22399 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22406 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22407 block = parse_block(parser, (uint16_t) (depth + 1));
22408 pm_arguments_validate_block(parser, &arguments, block);
22409 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22410 block = parse_block(parser, (uint16_t) (depth + 1));
22413 if (block != NULL) {
22414 if (arguments.
block != NULL) {
22415 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
22417 arguments.
arguments = pm_arguments_node_create(parser);
22419 pm_arguments_node_arguments_append(parser->arena, arguments.
arguments, arguments.
block);
22422 arguments.
block = UP(block);
22425 return UP(pm_call_node_aref_create(parser, node, &arguments));
22427 case PM_TOKEN_KEYWORD_IN: {
22428 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22429 parser->pattern_matching_newlines =
true;
22432 parser->command_start =
false;
22433 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22434 parser_lex(parser);
22437 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));
22439 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22441 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
22443 case PM_TOKEN_EQUAL_GREATER: {
22444 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22445 parser->pattern_matching_newlines =
true;
22448 parser->command_start =
false;
22449 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22450 parser_lex(parser);
22453 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));
22455 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22457 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
22460 assert(
false &&
"unreachable");
22465#undef PM_PARSE_PATTERN_SINGLE
22466#undef PM_PARSE_PATTERN_TOP
22467#undef PM_PARSE_PATTERN_MULTI
22483 pm_binding_power_t left = pm_binding_powers[parser->current.type].
left;
22485 switch (PM_NODE_TYPE(node)) {
22486 case PM_MULTI_WRITE_NODE:
22487 case PM_RETURN_NODE:
22488 case PM_BREAK_NODE:
22490 return left > PM_BINDING_POWER_MODIFIER;
22491 case PM_CLASS_VARIABLE_WRITE_NODE:
22492 case PM_CONSTANT_PATH_WRITE_NODE:
22493 case PM_CONSTANT_WRITE_NODE:
22494 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22495 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22496 case PM_LOCAL_VARIABLE_WRITE_NODE:
22497 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
22498 case PM_CALL_NODE: {
22501 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
22502 return left > PM_BINDING_POWER_MODIFIER;
22508 if (pm_command_call_value_p(parser, node)) {
22509 return left > PM_BINDING_POWER_COMPOSITION;
22515 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22517 case PM_SUPER_NODE:
22518 case PM_YIELD_NODE:
22521 if (pm_command_call_value_p(parser, node)) {
22522 return left > PM_BINDING_POWER_COMPOSITION;
22527 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22532 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(parser, node);
22533 case PM_RESCUE_MODIFIER_NODE:
22537 if (left > PM_BINDING_POWER_MODIFIER) {
22540 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
22557parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
22558 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
22559 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22560 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
22563 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
22568 switch (PM_NODE_TYPE(node)) {
22569 case PM_ERROR_RECOVERY_NODE:
22571 case PM_PRE_EXECUTION_NODE:
22573 case PM_POST_EXECUTION_NODE:
22574 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22575 case PM_ALIAS_METHOD_NODE:
22576 case PM_UNDEF_NODE:
22577 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
22582 case PM_SUPER_NODE:
22583 case PM_YIELD_NODE:
22585 if (parse_expression_terminator(parser, node)) {
22589 case PM_SYMBOL_NODE:
22590 if (pm_symbol_node_label_p(parser, node)) {
22601 pm_token_type_t current_token_type;
22604 current_token_type = parser->current.type,
22605 current_binding_powers = pm_binding_powers[current_token_type],
22606 binding_power <= current_binding_powers.
left &&
22607 current_binding_powers.
binary
22609 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
22610 if (parse_expression_terminator(parser, node))
return node;
22614 if (current_binding_powers.
nonassoc) {
22622 if (next_binding_powers.
nonassoc && next_binding_powers.
left == current_binding_powers.
left) {
22623 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));
22634 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22635 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22636 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));
22640 if (PM_BINDING_POWER_TERM <= next_binding_powers.
left) {
22643 }
else if (current_binding_powers.
left <= next_binding_powers.
left) {
22648 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
22657 switch (node->
type) {
22658 case PM_CALL_NODE: {
22672 cast->
block == NULL &&
22682 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22685 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22690 case PM_CONSTANT_PATH_NODE:
22693 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22698 if (context_terminator(parser->current_context->context, &parser->current)) {
22701 !next_binding_powers.
binary ||
22702 binding_power > next_binding_powers.
left ||
22703 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
22719 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22720 if (statements == NULL) {
22721 statements = pm_statements_node_create(parser);
22725 pm_arguments_node_arguments_append(
22728 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
22731 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
22734 pm_parser_constant_id_constant(parser,
"print", 5)
22738 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22739 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22740 if (statements == NULL) {
22741 statements = pm_statements_node_create(parser);
22745 pm_arguments_node_arguments_append(
22748 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
22751 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22752 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
22756 pm_parser_constant_id_constant(parser,
"$F", 2),
22760 pm_statements_node_body_prepend(parser->arena, statements, UP(write));
22764 pm_arguments_node_arguments_append(
22767 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
22770 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22772 pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
22774 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
22776 UP(pm_true_node_synthesized_create(parser))
22779 pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
22780 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22784 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
22786 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
22790 statements = wrapped_statements;
22804 if (parser->current_scope == NULL) {
22805 pm_parser_scope_push(parser,
true);
22809 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22811 parser_lex(parser);
22814 if (statements != NULL && !parser->parsing_eval) {
22818 assert(statements->
body.
size > 0);
22819 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22823 pm_locals_order(parser, &parser->current_scope->locals, &locals,
true);
22824 pm_parser_scope_pop(parser);
22829 statements = wrap_statements(parser, statements);
22831 flush_block_exits(parser, previous_block_exits);
22837 if (statements == NULL) {
22838 statements = pm_statements_node_create(parser);
22842 return UP(pm_program_node_create(parser, &locals, statements));
22859pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22860 size_t little_length = strlen(little);
22862 for (
const char *max = big + big_length - little_length; big <= max; big++) {
22863 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22870#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22878pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22879 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22880 pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
22891 const char *switches = pm_strnstr(engine,
" -", length);
22892 if (switches == NULL)
return;
22895 options->shebang_callback(
22897 (
const uint8_t *) (switches + 1),
22898 length - ((
size_t) (switches - engine)) - 1,
22899 options->shebang_callback_data
22902 size_t encoding_length;
22903 if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
22904 const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
22905 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22908 parser->command_line = next_options.command_line;
22909 parser->frozen_string_literal = next_options.frozen_string_literal;
22917 assert(arena != NULL);
22918 assert(source != NULL);
22922 .metadata_arena = { 0 },
22924 .lex_state = PM_LEX_STATE_BEG,
22925 .enclosure_nesting = 0,
22926 .lambda_enclosure_nesting = -1,
22927 .brace_nesting = 0,
22928 .do_loop_stack = 0,
22929 .accepts_block_stack = 0,
22932 .stack = {{ .mode = PM_LEX_DEFAULT }},
22933 .current = &parser->lex_modes.stack[0],
22936 .end = source + size,
22937 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22938 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22939 .next_start = NULL,
22940 .heredoc_end = NULL,
22942 .comment_list = { 0 },
22943 .magic_comment_list = { 0 },
22944 .warning_list = { 0 },
22945 .error_list = { 0 },
22946 .current_scope = NULL,
22947 .current_context = NULL,
22948 .encoding = PM_ENCODING_UTF_8_ENTRY,
22949 .encoding_changed_callback = NULL,
22950 .encoding_comment_start = source,
22951 .lex_callback = { 0 },
22953 .constant_pool = { 0 },
22954 .line_offsets = { 0 },
22956 .current_string = PM_STRING_EMPTY,
22958 .explicit_encoding = NULL,
22960 .parsing_eval =
false,
22961 .partial_script =
false,
22962 .command_start =
true,
22963 .recovering =
false,
22964 .continuable =
true,
22965 .encoding_locked =
false,
22966 .encoding_changed =
false,
22967 .pattern_matching_newlines =
false,
22968 .in_keyword_arg =
false,
22969 .current_block_exits = NULL,
22970 .semantic_token_seen =
false,
22972 .warn_mismatched_indentation =
true
22980 if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
22981 if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
22988 uint32_t constant_size = ((uint32_t) size) / 120;
22989 pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
22994 size_t newline_size = size / 22;
22995 pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
22998 if (options != NULL) {
23000 parser->filepath = options->filepath;
23003 parser->start_line = options->line;
23006 size_t encoding_length = pm_string_length(&options->encoding);
23007 if (encoding_length > 0) {
23008 const uint8_t *encoding_source = pm_string_source(&options->encoding);
23009 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23013 parser->encoding_locked = options->encoding_locked;
23016 parser->frozen_string_literal = options->frozen_string_literal;
23019 parser->command_line = options->command_line;
23022 parser->version = options->version;
23025 parser->partial_script = options->partial_script;
23028 parser->parsing_eval = options->scopes_count > 0;
23029 if (parser->parsing_eval) parser->warn_mismatched_indentation =
false;
23031 for (
size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
23033 pm_parser_scope_push(parser, scope_index == 0);
23037 parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
23039 for (
size_t local_index = 0; local_index < scope->locals_count; local_index++) {
23040 const pm_string_t *local = pm_options_scope_local(scope, local_index);
23042 const uint8_t *source = pm_string_source(local);
23043 size_t length = pm_string_length(local);
23045 uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
23046 memcpy(allocated, source, length);
23047 pm_parser_local_add_owned(parser, allocated, length);
23054 if (parser->version == PM_OPTIONS_VERSION_UNSET) {
23055 parser->version = PM_OPTIONS_VERSION_LATEST;
23058 pm_accepts_block_stack_push(parser,
true);
23061 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
23062 parser->current.end += 3;
23063 parser->encoding_comment_start += 3;
23065 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
23066 parser->encoding = PM_ENCODING_UTF_8_ENTRY;
23067 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
23074 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
23091 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
23092 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
23094 if (length > 2 && parser->current.end[0] ==
'#' && parser->current.end[1] ==
'!') {
23095 const char *engine;
23097 if ((engine = pm_strnstr((
const char *) parser->start,
"ruby", length)) != NULL) {
23098 if (newline != NULL) {
23099 parser->encoding_comment_start = newline + 1;
23101 if (options == NULL || options->main_script) {
23102 pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
23106 if (options != NULL && options->main_script && options->shebang_callback != NULL) {
23107 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->start)));
23110 search_shebang =
false;
23111 }
else if (options != NULL && options->main_script && !parser->parsing_eval) {
23112 search_shebang =
true;
23118 if (search_shebang) {
23121 bool found_shebang =
false;
23125 const uint8_t *cursor = parser->start;
23129 const uint8_t *newline = next_newline(cursor, parser->end - cursor);
23131 while (newline != NULL) {
23132 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
23134 cursor = newline + 1;
23135 newline = next_newline(cursor, parser->end - cursor);
23137 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
23138 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
23139 const char *engine;
23140 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
23141 found_shebang =
true;
23143 if (newline != NULL) {
23144 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
23145 parser->encoding_comment_start = newline + 1;
23148 if (options != NULL && options->shebang_callback != NULL) {
23149 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
23157 if (found_shebang) {
23158 parser->previous = (
pm_token_t) { .
type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23159 parser->current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23161 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
23162 pm_line_offset_list_clear(&parser->line_offsets);
23169 parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
23182 if (parser == NULL) abort();
23184 pm_parser_init(arena, parser, source, size, options);
23193 pm_string_cleanup(&parser->filepath);
23194 pm_arena_cleanup(&parser->metadata_arena);
23196 while (parser->current_scope != NULL) {
23201 pm_parser_scope_pop(parser);
23204 while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
23205 lex_mode_pop(parser);
23214 pm_parser_cleanup(parser);
23224pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
23226 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
23227 case PM_ERR_BEGIN_UPCASE_BRACE:
23228 case PM_ERR_CLASS_VARIABLE_BARE:
23229 case PM_ERR_END_UPCASE_BRACE:
23230 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
23231 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
23232 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
23233 case PM_ERR_EXPRESSION_NOT_WRITABLE:
23234 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
23235 case PM_ERR_FLOAT_PARSE:
23236 case PM_ERR_GLOBAL_VARIABLE_BARE:
23237 case PM_ERR_HASH_KEY:
23238 case PM_ERR_HEREDOC_IDENTIFIER:
23239 case PM_ERR_INSTANCE_VARIABLE_BARE:
23240 case PM_ERR_INVALID_BLOCK_EXIT:
23241 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
23242 case PM_ERR_INVALID_FLOAT_EXPONENT:
23243 case PM_ERR_INVALID_NUMBER_BINARY:
23244 case PM_ERR_INVALID_NUMBER_DECIMAL:
23245 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
23246 case PM_ERR_INVALID_NUMBER_OCTAL:
23247 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
23248 case PM_ERR_NO_LOCAL_VARIABLE:
23249 case PM_ERR_PARAMETER_ORDER:
23250 case PM_ERR_STATEMENT_UNDEF:
23251 case PM_ERR_VOID_EXPRESSION:
23294 if (parser->error_list.size == 0) {
23295 parser->continuable =
false;
23299 if (!parser->continuable)
return;
23301 size_t source_length = (size_t) (parser->end - parser->start);
23304 bool has_non_stray_error =
false;
23306 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)) {
23307 has_non_stray_error =
true;
23315 size_t non_stray_min_start = SIZE_MAX;
23318 size_t error_start = (size_t) error->location.start;
23319 size_t error_end = error_start + (size_t) error->location.length;
23320 bool at_eof = error_end >= source_length;
23323 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
23324 parser->continuable =
false;
23329 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
23330 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
23331 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
23340 if (non_stray_min_start < error_start)
continue;
23347 if (at_eof && error_start > 0) {
23349 if (error->location.length == 1) {
23350 const uint8_t *
byte = parser->start + error_start;
23351 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
23352 parser->continuable =
false;
23362 if (has_non_stray_error)
continue;
23369 if (error->location.length == 1) {
23370 const uint8_t *
byte = parser->start + error_start;
23371 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
23375 parser->continuable =
false;
23385 pm_node_t *node = parse_program(parser);
23386 pm_parse_continuable(parser);
23398 bool eof = pm_source_stream_read(source);
23403 while (!eof && tmp->error_list.size > 0) {
23404 eof = pm_source_stream_read(source);
23407 pm_arena_cleanup(arena);
23409 tmp =
pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
23417#undef PM_CASE_KEYWORD
23418#undef PM_CASE_OPERATOR
23419#undef PM_CASE_WRITABLE
23420#undef PM_STRING_EMPTY
23425#ifndef PRISM_EXCLUDE_SERIALIZATION
23429 pm_buffer_append_string(buffer,
"PRISM", 5);
23433 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23441 pm_serialize_header(buffer);
23442 pm_serialize_content(parser, node, buffer);
23443 pm_buffer_append_byte(buffer,
'\0');
23451pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23453 pm_options_read(&options, data);
23457 pm_parser_init(&arena, &parser, source, size, &options);
23461 pm_serialize_header(buffer);
23462 pm_serialize_content(&parser, node, buffer);
23463 pm_buffer_append_byte(buffer,
'\0');
23465 pm_parser_cleanup(&parser);
23466 pm_arena_cleanup(&arena);
23467 pm_options_cleanup(&options);
23479 pm_options_read(&options, data);
23481 pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
23482 pm_serialize_header(buffer);
23483 pm_serialize_content(parser, node, buffer);
23484 pm_buffer_append_byte(buffer,
'\0');
23487 pm_arena_cleanup(&arena);
23488 pm_options_cleanup(&options);
23502 pm_options_read(&options, data);
23506 pm_parser_init(&arena, &parser, source, size, &options);
23510 int8_t result = -1;
23511 if (parser.error_list.size > 0) {
23512 const char *encoding_name = parser.encoding->name;
23513 pm_buffer_append_string(buffer, encoding_name, strlen(encoding_name));
23514 pm_buffer_append_byte(buffer,
'\0');
23516 result = (int8_t) pm_errors_format(&parser, buffer, format_type);
23519 pm_parser_cleanup(&parser);
23520 pm_arena_cleanup(&arena);
23521 pm_options_cleanup(&options);
23530pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23532 pm_options_read(&options, data);
23536 pm_parser_init(&arena, &parser, source, size, &options);
23539 pm_serialize_header(buffer);
23540 pm_serialize_encoding(parser.encoding, buffer);
23541 pm_buffer_append_varsint(buffer, parser.start_line);
23542 pm_serialize_line_offset_list(&parser.line_offsets, buffer);
23543 pm_serialize_comment_list(&parser.comment_list, buffer);
23545 pm_parser_cleanup(&parser);
23546 pm_arena_cleanup(&arena);
23547 pm_options_cleanup(&options);
#define PRISM_ALIGNOF
Get the alignment requirement of a type.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
A header file that defines macros to exclude certain features of the prism library.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
int len
Length of the buffer.
#define PRISM_INLINE
Old Visual Studio versions do not support the inline keyword, so we need to define it to be __inline.
VALUE type(ANYARGS)
ANYARGS-ed function type.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should not be frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
String literals may be frozen or mutable depending on the implementation default.
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
PRISM_EXPORTED_FUNCTION PRISM_NODISCARD pm_parser_t * pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) PRISM_NONNULL(1)
Allocate and initialize a parser with the given start and end pointers.
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser) PRISM_NONNULL(1)
Free both the memory held by the given parser and the parser itself.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1)
Initiate the parser with the given parser.
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
The version of the Prism library.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
The functions related to serializing the AST to a binary format.
Functions for parsing streams.
PM_NODE_ALIGNAS struct pm_node * left
AndNode::left.
PM_NODE_ALIGNAS struct pm_node * right
AndNode::right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode::arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode::elements.
PM_NODE_ALIGNAS struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
PM_NODE_ALIGNAS struct pm_node * value
AssocNode::value.
PM_NODE_ALIGNAS struct pm_node * key
AssocNode::key.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
BeginNode::else_clause.
PM_NODE_ALIGNAS struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
PM_NODE_ALIGNAS struct pm_statements_node * statements
BeginNode::statements.
PM_NODE_ALIGNAS struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
pm_node_t base
The embedded base node.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
pm_constant_id_t name
CallNode::name.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
CallNode::arguments.
pm_location_t equal_loc
CallNode::equal_loc.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
PM_NODE_ALIGNAS struct pm_node * block
CallNode::block.
PM_NODE_ALIGNAS struct pm_node * receiver
CallNode::receiver.
struct pm_node_list conditions
CaseMatchNode::conditions.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
CaseMatchNode::else_clause.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
CaseNode::else_clause.
struct pm_node_list conditions
CaseNode::conditions.
size_t size
The number of constant ids in the list.
pm_location_t equal_loc
DefNode::equal_loc.
PM_NODE_ALIGNAS struct pm_node * body
DefNode::body.
PM_NODE_ALIGNAS struct pm_statements_node * statements
ElseNode::statements.
PM_NODE_ALIGNAS struct pm_statements_node * statements
EnsureNode::statements.
pm_location_t opening_loc
FindPatternNode::opening_loc.
PM_NODE_ALIGNAS struct pm_node * constant
FindPatternNode::constant.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
GlobalVariableTargetNode.
struct pm_node_list elements
HashNode::elements.
PM_NODE_ALIGNAS struct pm_node * constant
HashPatternNode::constant.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_location_t closing_loc
HashPatternNode::closing_loc.
PM_NODE_ALIGNAS struct pm_statements_node * statements
IfNode::statements.
PM_NODE_ALIGNAS struct pm_node * subsequent
IfNode::subsequent.
PM_NODE_ALIGNAS struct pm_statements_node * statements
InNode::statements.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
int32_t line
The line number.
uint32_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
uint32_t depth
LocalVariableWriteNode::depth.
pm_constant_id_t name
LocalVariableWriteNode::name.
This struct represents a slice in the source code, defined by an offset and a length.
uint32_t start
The offset of the location from the start of the source.
uint32_t length
The length of the location.
struct pm_node_list targets
MatchWriteNode::targets.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_location_t location
This is the location of the node in the source.
PM_NODE_ALIGNAS struct pm_node * right
OrNode::right.
PM_NODE_ALIGNAS struct pm_node * left
OrNode::left.
PM_NODE_ALIGNAS struct pm_node * block
ParametersNode::block.
PM_NODE_ALIGNAS struct pm_node * rest
ParametersNode::rest.
PM_NODE_ALIGNAS struct pm_node * keyword_rest
ParametersNode::keyword_rest.
PM_NODE_ALIGNAS struct pm_node * body
ParenthesesNode::body.
PM_NODE_ALIGNAS struct pm_node * right
RangeNode::right.
PM_NODE_ALIGNAS struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
PM_NODE_ALIGNAS struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
PM_NODE_ALIGNAS struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
PM_NODE_ALIGNAS struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
pm_node_t base
The embedded base node.
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t content_loc
StringNode::content_loc.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
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 value_loc
SymbolNode::value_loc.
pm_string_t unescaped
SymbolNode::unescaped.
When we're lexing certain types (strings, symbols, lists, etc.) we have string content associated wit...
pm_buffer_t buffer
The buffer that we're using to keep track of the string content.
const uint8_t * cursor
The cursor into the source string that points to how far we have currently copied into the buffer.
This struct represents a token in the Ruby source.
const uint8_t * end
A pointer to the end location of the token in the source.
const uint8_t * start
A pointer to the start location of the token in the source.
pm_token_type_t type
The type of the token.
PM_NODE_ALIGNAS struct pm_statements_node * statements
UnlessNode::statements.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
UnlessNode::else_clause.
PM_NODE_ALIGNAS struct pm_statements_node * statements
WhenNode::statements.
pm_location_t lparen_loc
YieldNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
YieldNode::arguments.
#define PRISM_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.