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_STRING_FLAGS_FROZEN;
6468 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
6469 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6474 return pm_source_file_node_new(
6478 PM_LOCATION_INIT_TOKEN(parser, file_keyword),
6486static pm_source_line_node_t *
6487pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6488 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6490 return pm_source_line_node_new(
6493 PM_NODE_FLAG_STATIC_LITERAL,
6494 PM_LOCATION_INIT_TOKEN(parser, token)
6501static pm_splat_node_t *
6502pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6503 return pm_splat_node_new(
6507 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
6508 TOK2LOC(parser, operator),
6516static pm_statements_node_t *
6517pm_statements_node_create(pm_parser_t *parser) {
6518 return pm_statements_node_new(
6522 PM_LOCATION_INIT_UNSET,
6523 ((pm_node_list_t) { 0 })
6531pm_statements_node_body_length(pm_statements_node_t *node) {
6532 return node && node->body.size;
6539static PRISM_INLINE void
6540pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6541 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6542 PM_NODE_START_SET_NODE(node, statement);
6545 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6546 PM_NODE_LENGTH_SET_NODE(node, statement);
6554pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6555 pm_statements_node_body_update(node, statement);
6557 if (node->body.size > 0) {
6558 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6560 switch (PM_NODE_TYPE(previous)) {
6565 case PM_RETURN_NODE:
6566 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6573 pm_node_list_append(parser->arena, &node->body, statement);
6574 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6581pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
6582 pm_statements_node_body_update(node, statement);
6583 pm_node_list_prepend(arena, &node->body, statement);
6584 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6590static PRISM_INLINE pm_string_node_t *
6591pm_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) {
6592 pm_node_flags_t flags = 0;
6594 switch (parser->frozen_string_literal) {
6595 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6596 flags = PM_STRING_FLAGS_MUTABLE;
6598 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6599 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6603 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6604 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6606 return pm_string_node_new(
6610 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6611 NTOK2LOC(parser, opening),
6612 TOK2LOC(parser, content),
6613 NTOK2LOC(parser, closing),
6621static pm_string_node_t *
6622pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6623 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6630static pm_string_node_t *
6631pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6632 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6633 parser->current_string = PM_STRING_EMPTY;
6640static pm_super_node_t *
6641pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6642 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6644 const pm_location_t *end = pm_arguments_end(arguments);
6645 assert(end != NULL && "unreachable");
6647 return pm_super_node_new(
6651 ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
6652 TOK2LOC(parser, keyword),
6653 arguments->opening_loc,
6654 arguments->arguments,
6655 arguments->closing_loc,
6665pm_ascii_only_p(const pm_string_t *contents) {
6666 const size_t length = pm_string_length(contents);
6667 const uint8_t *source = pm_string_source(contents);
6669 for (size_t index = 0; index < length; index++) {
6670 if (source[index] & 0x80) return false;
6680parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6681 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6682 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6685 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6698parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6699 const pm_encoding_t *encoding = parser->encoding;
6701 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6702 size_t width = encoding->char_width(cursor, end - cursor);
6705 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6722static PRISM_INLINE pm_node_flags_t
6723parse_symbol_encoding(pm_parser_t *parser, const pm_encoding_t *explicit_encoding, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6724 if (explicit_encoding != NULL) {
6725 // A Symbol may optionally have its encoding explicitly set. This will
6726 // happen if an escape sequence results in a non-ASCII code point.
6727 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6728 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6729 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6730 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6731 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6732 } else if (validate) {
6733 parse_symbol_encoding_validate_other(parser, location, contents);
6735 } else if (pm_ascii_only_p(contents)) {
6736 // Ruby stipulates that all source files must use an ASCII-compatible
6737 // encoding. Thus, all symbols appearing in source are eligible for
6738 // "downgrading" to US-ASCII.
6739 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6740 } else if (validate) {
6741 parse_symbol_encoding_validate_other(parser, location, contents);
6751static pm_symbol_node_t *
6752pm_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) {
6753 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6754 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6756 return pm_symbol_node_new(
6759 PM_NODE_FLAG_STATIC_LITERAL | flags,
6760 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6761 NTOK2LOC(parser, opening),
6762 NTOK2LOC(parser, value),
6763 NTOK2LOC(parser, closing),
6771static PRISM_INLINE pm_symbol_node_t *
6772pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6773 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6779static pm_symbol_node_t *
6780pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6781 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));
6782 parser->current_string = PM_STRING_EMPTY;
6789static pm_symbol_node_t *
6790pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6791 assert(token->type == PM_TOKEN_LABEL);
6793 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6794 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6795 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6797 assert((label.end - label.start) >= 0);
6798 pm_string_shared_init(&node->unescaped, label.start, label.end);
6799 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, parser->explicit_encoding, &label, &node->unescaped, false));
6807static pm_symbol_node_t *
6808pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6809 pm_symbol_node_t *node = pm_symbol_node_new(
6812 PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
6813 PM_LOCATION_INIT_UNSET,
6814 ((pm_location_t) { 0 }),
6815 ((pm_location_t) { 0 }),
6816 ((pm_location_t) { 0 }),
6817 ((pm_string_t) { 0 })
6820 pm_string_constant_init(&node->unescaped, content, strlen(content));
6828pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6829 const pm_location_t *location = NULL;
6831 switch (PM_NODE_TYPE(node)) {
6832 case PM_SYMBOL_NODE: {
6833 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6834 if (cast->closing_loc.length > 0) {
6835 location = &cast->closing_loc;
6839 case PM_INTERPOLATED_SYMBOL_NODE: {
6840 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6841 if (cast->closing_loc.length > 0) {
6842 location = &cast->closing_loc;
6850 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6856static pm_symbol_node_t *
6857pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6858 pm_symbol_node_t *new_node = pm_symbol_node_new(
6861 PM_NODE_FLAG_STATIC_LITERAL,
6862 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6863 TOK2LOC(parser, opening),
6865 TOK2LOC(parser, closing),
6869 pm_token_t content = {
6870 .type = PM_TOKEN_IDENTIFIER,
6871 .start = parser->start + node->content_loc.start,
6872 .end = parser->start + node->content_loc.start + node->content_loc.length
6875 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, parser->explicit_encoding, &content, &node->unescaped, true));
6877 /* The old node is arena-allocated so no explicit free is needed. */
6884static pm_string_node_t *
6885pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6886 pm_node_flags_t flags = 0;
6888 switch (parser->frozen_string_literal) {
6889 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6890 flags = PM_STRING_FLAGS_MUTABLE;
6892 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6893 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6897 pm_string_node_t *new_node = pm_string_node_new(
6901 PM_LOCATION_INIT_NODE(node),
6908 /* The old node is arena-allocated so no explicit free is needed. */
6915static pm_true_node_t *
6916pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6917 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6919 return pm_true_node_new(
6922 PM_NODE_FLAG_STATIC_LITERAL,
6923 PM_LOCATION_INIT_TOKEN(parser, token)
6930static pm_true_node_t *
6931pm_true_node_synthesized_create(pm_parser_t *parser) {
6932 return pm_true_node_new(
6935 PM_NODE_FLAG_STATIC_LITERAL,
6936 PM_LOCATION_INIT_UNSET
6943static pm_undef_node_t *
6944pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6945 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6947 return pm_undef_node_new(
6951 PM_LOCATION_INIT_TOKEN(parser, token),
6952 ((pm_node_list_t) { 0 }),
6953 TOK2LOC(parser, token)
6961pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6962 PM_NODE_LENGTH_SET_NODE(node, name);
6963 pm_node_list_append(arena, &node->names, name);
6969static pm_unless_node_t *
6970pm_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) {
6971 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6972 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6974 return pm_unless_node_new(
6977 PM_NODE_FLAG_NEWLINE,
6978 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
6979 TOK2LOC(parser, keyword),
6981 NTOK2LOC(parser, then_keyword),
6984 ((pm_location_t) { 0 })
6991static pm_unless_node_t *
6992pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6993 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6995 pm_statements_node_t *statements = pm_statements_node_create(parser);
6996 pm_statements_node_body_append(parser, statements, statement, true);
6998 return pm_unless_node_new(
7001 PM_NODE_FLAG_NEWLINE,
7002 PM_LOCATION_INIT_NODES(statement, predicate),
7003 TOK2LOC(parser, unless_keyword),
7005 ((pm_location_t) { 0 }),
7008 ((pm_location_t) { 0 })
7012static PRISM_INLINE void
7013pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
7014 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
7015 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
7024pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7025 assert(parser->current_block_exits != NULL);
7027 // All of the block exits that we want to remove should be within the
7028 // statements, and since we are modifying the statements, we shouldn't have
7029 // to check the end location.
7030 uint32_t start = statements->base.location.start;
7032 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7033 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7034 if (block_exit->location.start < start) break;
7036 // Implicitly remove from the list by lowering the size.
7037 parser->current_block_exits->size--;
7044static pm_until_node_t *
7045pm_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) {
7046 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7048 return pm_until_node_new(
7052 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7053 TOK2LOC(parser, keyword),
7054 NTOK2LOC(parser, do_keyword),
7055 TOK2LOC(parser, closing),
7064static pm_until_node_t *
7065pm_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) {
7066 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7067 pm_loop_modifier_block_exits(parser, statements);
7069 return pm_until_node_new(
7073 PM_LOCATION_INIT_NODES(statements, predicate),
7074 TOK2LOC(parser, keyword),
7075 ((pm_location_t) { 0 }),
7076 ((pm_location_t) { 0 }),
7085static pm_when_node_t *
7086pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7087 return pm_when_node_new(
7091 PM_LOCATION_INIT_TOKEN(parser, keyword),
7092 TOK2LOC(parser, keyword),
7093 ((pm_node_list_t) { 0 }),
7094 ((pm_location_t) { 0 }),
7103pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
7104 PM_NODE_LENGTH_SET_NODE(node, condition);
7105 pm_node_list_append(arena, &node->conditions, condition);
7111static PRISM_INLINE void
7112pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
7113 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
7114 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
7121pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7122 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
7123 PM_NODE_LENGTH_SET_NODE(node, statements);
7126 node->statements = statements;
7132static pm_while_node_t *
7133pm_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) {
7134 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7136 return pm_while_node_new(
7140 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7141 TOK2LOC(parser, keyword),
7142 NTOK2LOC(parser, do_keyword),
7143 TOK2LOC(parser, closing),
7152static pm_while_node_t *
7153pm_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) {
7154 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7155 pm_loop_modifier_block_exits(parser, statements);
7157 return pm_while_node_new(
7161 PM_LOCATION_INIT_NODES(statements, predicate),
7162 TOK2LOC(parser, keyword),
7163 ((pm_location_t) { 0 }),
7164 ((pm_location_t) { 0 }),
7173static pm_while_node_t *
7174pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7175 return pm_while_node_new(
7179 PM_LOCATION_INIT_UNSET,
7180 ((pm_location_t) { 0 }),
7181 ((pm_location_t) { 0 }),
7182 ((pm_location_t) { 0 }),
7192static pm_x_string_node_t *
7193pm_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) {
7194 return pm_x_string_node_new(
7197 PM_STRING_FLAGS_FROZEN,
7198 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
7199 TOK2LOC(parser, opening),
7200 TOK2LOC(parser, content),
7201 TOK2LOC(parser, closing),
7209static PRISM_INLINE pm_x_string_node_t *
7210pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7211 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7217static pm_yield_node_t *
7218pm_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) {
7219 uint32_t start = PM_TOKEN_START(parser, keyword);
7222 if (rparen_loc->length > 0) {
7223 end = PM_LOCATION_END(rparen_loc);
7224 } else if (arguments != NULL) {
7225 end = PM_NODE_END(arguments);
7226 } else if (lparen_loc->length > 0) {
7227 end = PM_LOCATION_END(lparen_loc);
7229 end = PM_TOKEN_END(parser, keyword);
7232 return pm_yield_node_new(
7236 ((pm_location_t) { .start = start, .length = U32(end - start) }),
7237 TOK2LOC(parser, keyword),
7249pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7250 pm_scope_t *scope = parser->current_scope;
7253 while (scope != NULL) {
7254 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7255 if (scope->closed) break;
7257 scope = scope->previous;
7269static PRISM_INLINE int
7270pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7271 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7277static PRISM_INLINE void
7278pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7279 pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
7285static pm_constant_id_t
7286pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7287 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
7288 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7295static PRISM_INLINE pm_constant_id_t
7296pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
7297 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
7303static PRISM_INLINE pm_constant_id_t
7304pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7305 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
7311static pm_constant_id_t
7312pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7313 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7314 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7321static pm_constant_id_t
7322pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7323 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7324 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7336pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7337 // We want to check whether the parameter name is a numbered parameter or
7339 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7341 // Otherwise we'll fetch the constant id for the parameter name and check
7342 // whether it's already in the current scope.
7343 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7345 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7346 // Add an error if the parameter doesn't start with _ and has been seen before
7347 if ((name->start < name->end) && (*name->start != '_')) {
7348 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7359pm_parser_scope_pop(pm_parser_t *parser) {
7360 pm_scope_t *scope = parser->current_scope;
7361 parser->current_scope = scope->previous;
7362 pm_locals_free(&scope->locals);
7363 xfree_sized(scope, sizeof(pm_scope_t));
7366/******************************************************************************/
7368/******************************************************************************/
7373static PRISM_INLINE void
7374pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7375 *stack = (*stack << 1) | (value & 1);
7381static PRISM_INLINE void
7382pm_state_stack_pop(pm_state_stack_t *stack) {
7389static PRISM_INLINE bool
7390pm_state_stack_p(const pm_state_stack_t *stack) {
7394static PRISM_INLINE void
7395pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7396 // Use the negation of the value to prevent stack overflow.
7397 pm_state_stack_push(&parser->accepts_block_stack, !value);
7400static PRISM_INLINE void
7401pm_accepts_block_stack_pop(pm_parser_t *parser) {
7402 pm_state_stack_pop(&parser->accepts_block_stack);
7405static PRISM_INLINE bool
7406pm_accepts_block_stack_p(pm_parser_t *parser) {
7407 return !pm_state_stack_p(&parser->accepts_block_stack);
7410static PRISM_INLINE void
7411pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7412 pm_state_stack_push(&parser->do_loop_stack, value);
7415static PRISM_INLINE void
7416pm_do_loop_stack_pop(pm_parser_t *parser) {
7417 pm_state_stack_pop(&parser->do_loop_stack);
7420static PRISM_INLINE bool
7421pm_do_loop_stack_p(pm_parser_t *parser) {
7422 return pm_state_stack_p(&parser->do_loop_stack);
7449static PRISM_INLINE void
7450pm_enclosure_frame_push(pm_parser_t *parser) {
7451 pm_do_loop_stack_push(parser, false);
7452 pm_accepts_block_stack_push(parser, true);
7455static PRISM_INLINE void
7456pm_enclosure_frame_pop(pm_parser_t *parser) {
7457 pm_do_loop_stack_pop(parser);
7458 pm_accepts_block_stack_pop(parser);
7461/******************************************************************************/
7462/* Lexer check helpers */
7463/******************************************************************************/
7469static PRISM_INLINE uint8_t
7470peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7471 if (cursor < parser->end) {
7483static PRISM_INLINE uint8_t
7484peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7485 return peek_at(parser, parser->current.end + offset);
7492static PRISM_INLINE uint8_t
7493peek(const pm_parser_t *parser) {
7494 return peek_at(parser, parser->current.end);
7501static PRISM_INLINE bool
7502match(pm_parser_t *parser, uint8_t value) {
7503 if (peek(parser) == value) {
7504 parser->current.end++;
7514static PRISM_INLINE size_t
7515match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7516 if (peek_at(parser, cursor) == '\n') {
7519 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7530static PRISM_INLINE size_t
7531match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7532 return match_eol_at(parser, parser->current.end + offset);
7540static PRISM_INLINE size_t
7541match_eol(pm_parser_t *parser) {
7542 return match_eol_at(parser, parser->current.end);
7548static PRISM_INLINE const uint8_t *
7549next_newline(const uint8_t *cursor, ptrdiff_t length) {
7550 assert(length >= 0);
7552 // Note that it's okay for us to use memchr here to look for \n because none
7553 // of the encodings that we support have \n as a component of a multi-byte
7555 return memchr(cursor, '\n', (size_t) length);
7561static PRISM_INLINE bool
7562ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7563 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));
7571parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7572 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7574 if (encoding != NULL) {
7575 if (parser->encoding != encoding) {
7576 parser->encoding = encoding;
7577 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7580 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7592parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7593 const uint8_t *cursor = parser->current.start + 1;
7594 const uint8_t *end = parser->current.end;
7596 bool separator = false;
7598 if (end - cursor <= 6) return;
7599 switch (cursor[6]) {
7600 case 'C': case 'c': cursor += 6; continue;
7601 case 'O': case 'o': cursor += 5; continue;
7602 case 'D': case 'd': cursor += 4; continue;
7603 case 'I': case 'i': cursor += 3; continue;
7604 case 'N': case 'n': cursor += 2; continue;
7605 case 'G': case 'g': cursor += 1; continue;
7612 if (pm_char_is_whitespace(*cursor)) break;
7615 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7621 if (++cursor >= end) return;
7622 } while (pm_char_is_whitespace(*cursor));
7624 if (separator) break;
7625 if (*cursor != '=' && *cursor != ':') return;
7631 const uint8_t *value_start = cursor;
7632 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7634 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7635 // If we were unable to parse the encoding value, then we've got an
7636 // issue because we didn't understand the encoding that the user was
7637 // trying to use. In this case we'll keep using the default encoding but
7638 // add an error to the parser to indicate an unsuccessful parse.
7639 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7644 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7645 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7646 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7647} pm_magic_comment_boolean_value_t;
7653static pm_magic_comment_boolean_value_t
7654parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7655 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7656 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7657 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7658 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7660 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7664static PRISM_INLINE bool
7665pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7666 return b == '\'' || b == '"' || b == ':' || b == ';';
7675parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7679 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1,
'*', (
size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7680 if (cursor[-1] ==
'-' && cursor + 1 < end && cursor[1] ==
'-') {
7698parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7701 const uint8_t *start = parser->current.start + 1;
7702 const uint8_t *end = parser->current.end;
7703 if (end - start <= 7)
return false;
7705 const uint8_t *cursor;
7706 bool indicator =
false;
7708 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7711 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7723 if (pm_memchr(start,
':', (
size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
7729 start += pm_strspn_whitespace(start, end - start);
7733 while (cursor < end) {
7735 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7738 const uint8_t *key_start = cursor;
7739 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7741 const uint8_t *key_end = cursor;
7742 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7743 if (cursor == end)
break;
7745 if (*cursor ==
':') {
7748 if (!indicator)
return false;
7752 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7753 if (cursor == end)
break;
7755 const uint8_t *value_start;
7756 const uint8_t *value_end;
7758 if (*cursor ==
'"') {
7759 value_start = ++cursor;
7760 for (; cursor < end && *cursor !=
'"'; cursor++) {
7761 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7764 if (cursor < end && *cursor ==
'"') cursor++;
7766 value_start = cursor;
7767 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7772 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7774 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7775 if (cursor != end)
return false;
7781 const size_t key_length = (size_t) (key_end - key_start);
7782 const uint8_t *dash = pm_memchr(key_start,
'-', key_length, parser->encoding_changed, parser->encoding);
7785 pm_string_shared_init(&key, key_start, key_end);
7787 uint8_t *buffer =
xmalloc(key_length);
7788 if (buffer == NULL)
break;
7790 memcpy(buffer, key_start, key_length);
7791 buffer[dash - key_start] =
'_';
7793 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7794 buffer[dash - key_start] =
'_';
7797 pm_string_owned_init(&key, buffer, key_length);
7802 const uint8_t *key_source = pm_string_source(&key);
7803 uint32_t value_length = (uint32_t) (value_end - value_start);
7807 if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7809 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7810 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7812 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7816 if (key_length == 11) {
7817 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7818 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7819 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7820 PM_PARSER_WARN_TOKEN_FORMAT(
7823 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7825 (
const char *) key_source,
7827 (
const char *) value_start
7830 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7831 parser->warn_mismatched_indentation =
false;
7833 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7834 parser->warn_mismatched_indentation =
true;
7838 }
else if (key_length == 21) {
7839 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7842 if (semantic_token_seen) {
7843 pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7845 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7846 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7847 PM_PARSER_WARN_TOKEN_FORMAT(
7850 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7852 (
const char *) key_source,
7854 (
const char *) value_start
7857 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7860 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7866 }
else if (key_length == 24) {
7867 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7868 const uint8_t *cursor = parser->current.start;
7869 while ((cursor > parser->start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7871 if (!((cursor == parser->start) || (cursor[-1] ==
'\n'))) {
7872 pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7873 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7874 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7875 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7876 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7877 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7878 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7879 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7880 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7882 PM_PARSER_WARN_TOKEN_FORMAT(
7885 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7887 (
const char *) key_source,
7889 (
const char *) value_start
7897 pm_string_cleanup(&key);
7914static const uint32_t context_terminators[] = {
7915 [PM_CONTEXT_NONE] = 0,
7916 [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7917 [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7918 [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7919 [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7920 [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7921 [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7922 [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7923 [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7924 [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
7925 [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7926 [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7927 [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7928 [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7929 [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7930 [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7931 [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7932 [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7933 [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7934 [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7935 [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7936 [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
7937 [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
7938 [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7939 [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
7940 [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7941 [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
7942 [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
7943 [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
7944 [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7945 [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7946 [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7947 [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7948 [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7949 [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7950 [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
7951 [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
7952 [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7953 [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7954 [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7955 [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7956 [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
7957 [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7958 [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7959 [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7960 [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7961 [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
7962 [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7963 [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7964 [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7965 [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7966 [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
7967 [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7968 [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
7969 [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
7973context_terminator(pm_context_t context,
pm_token_t *token) {
7974 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7985 while (context_node != NULL) {
7986 if (context_terminator(context_node->context, token))
return context_node->context;
7987 context_node = context_node->prev;
7990 return PM_CONTEXT_NONE;
7994context_push(
pm_parser_t *parser, pm_context_t context) {
7996 if (context_node == NULL)
return false;
8000 if (parser->current_context == NULL) {
8001 parser->current_context = context_node;
8003 context_node->prev = parser->current_context;
8004 parser->current_context = context_node;
8014 parser->current_context = prev;
8018context_p(
const pm_parser_t *parser, pm_context_t context) {
8021 while (context_node != NULL) {
8022 if (context_node->context == context)
return true;
8023 context_node = context_node->prev;
8033 while (context_node != NULL) {
8034 switch (context_node->context) {
8035 case PM_CONTEXT_DEF:
8036 case PM_CONTEXT_DEF_PARAMS:
8037 case PM_CONTEXT_DEF_ENSURE:
8038 case PM_CONTEXT_DEF_RESCUE:
8039 case PM_CONTEXT_DEF_ELSE:
8041 case PM_CONTEXT_CLASS:
8042 case PM_CONTEXT_CLASS_ENSURE:
8043 case PM_CONTEXT_CLASS_RESCUE:
8044 case PM_CONTEXT_CLASS_ELSE:
8045 case PM_CONTEXT_MODULE:
8046 case PM_CONTEXT_MODULE_ENSURE:
8047 case PM_CONTEXT_MODULE_RESCUE:
8048 case PM_CONTEXT_MODULE_ELSE:
8049 case PM_CONTEXT_SCLASS:
8050 case PM_CONTEXT_SCLASS_ENSURE:
8051 case PM_CONTEXT_SCLASS_RESCUE:
8052 case PM_CONTEXT_SCLASS_ELSE:
8055 context_node = context_node->prev;
8067context_human(pm_context_t context) {
8069 case PM_CONTEXT_NONE:
8070 assert(
false &&
"unreachable");
8072 case PM_CONTEXT_BEGIN:
return "begin statement";
8073 case PM_CONTEXT_BLOCK_BRACES:
return "'{'..'}' block";
8074 case PM_CONTEXT_BLOCK_KEYWORDS:
return "'do'..'end' block";
8075 case PM_CONTEXT_BLOCK_PARAMETERS:
return "'|'..'|' block parameter";
8076 case PM_CONTEXT_CASE_WHEN:
return "'when' clause";
8077 case PM_CONTEXT_CASE_IN:
return "'in' clause";
8078 case PM_CONTEXT_CLASS:
return "class definition";
8079 case PM_CONTEXT_DEF:
return "method definition";
8080 case PM_CONTEXT_DEF_PARAMS:
return "method parameters";
8081 case PM_CONTEXT_DEFAULT_PARAMS:
return "parameter default value";
8082 case PM_CONTEXT_DEFINED:
return "'defined?' expression";
8083 case PM_CONTEXT_ELSE:
8084 case PM_CONTEXT_BEGIN_ELSE:
8085 case PM_CONTEXT_BLOCK_ELSE:
8086 case PM_CONTEXT_CLASS_ELSE:
8087 case PM_CONTEXT_DEF_ELSE:
8088 case PM_CONTEXT_LAMBDA_ELSE:
8089 case PM_CONTEXT_MODULE_ELSE:
8090 case PM_CONTEXT_SCLASS_ELSE:
return "'else' clause";
8091 case PM_CONTEXT_ELSIF:
return "'elsif' clause";
8092 case PM_CONTEXT_EMBEXPR:
return "embedded expression";
8093 case PM_CONTEXT_BEGIN_ENSURE:
8094 case PM_CONTEXT_BLOCK_ENSURE:
8095 case PM_CONTEXT_CLASS_ENSURE:
8096 case PM_CONTEXT_DEF_ENSURE:
8097 case PM_CONTEXT_LAMBDA_ENSURE:
8098 case PM_CONTEXT_MODULE_ENSURE:
8099 case PM_CONTEXT_SCLASS_ENSURE:
return "'ensure' clause";
8100 case PM_CONTEXT_FOR:
return "for loop";
8101 case PM_CONTEXT_FOR_INDEX:
return "for loop index";
8102 case PM_CONTEXT_IF:
return "if statement";
8103 case PM_CONTEXT_LAMBDA_BRACES:
return "'{'..'}' lambda block";
8104 case PM_CONTEXT_LAMBDA_DO_END:
return "'do'..'end' lambda block";
8105 case PM_CONTEXT_LOOP_PREDICATE:
return "loop predicate";
8106 case PM_CONTEXT_MAIN:
return "top level context";
8107 case PM_CONTEXT_MODULE:
return "module definition";
8108 case PM_CONTEXT_MULTI_TARGET:
return "multiple targets";
8109 case PM_CONTEXT_PARENS:
return "parentheses";
8110 case PM_CONTEXT_POSTEXE:
return "'END' block";
8111 case PM_CONTEXT_PREDICATE:
return "predicate";
8112 case PM_CONTEXT_PREEXE:
return "'BEGIN' block";
8113 case PM_CONTEXT_BEGIN_RESCUE:
8114 case PM_CONTEXT_BLOCK_RESCUE:
8115 case PM_CONTEXT_CLASS_RESCUE:
8116 case PM_CONTEXT_DEF_RESCUE:
8117 case PM_CONTEXT_LAMBDA_RESCUE:
8118 case PM_CONTEXT_MODULE_RESCUE:
8119 case PM_CONTEXT_RESCUE_MODIFIER:
8120 case PM_CONTEXT_SCLASS_RESCUE:
return "'rescue' clause";
8121 case PM_CONTEXT_SCLASS:
return "singleton class definition";
8122 case PM_CONTEXT_TERNARY:
return "ternary expression";
8123 case PM_CONTEXT_UNLESS:
return "unless statement";
8124 case PM_CONTEXT_UNTIL:
return "until statement";
8125 case PM_CONTEXT_WHILE:
return "while statement";
8128 assert(
false &&
"unreachable");
8137pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8138 if (invalid != NULL) {
8139 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8140 pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
8145pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8146 const uint8_t *invalid = NULL;
8147 size_t length = pm_strspn_binary_number(
string, parser->end -
string, &invalid);
8148 pm_strspn_number_validate(parser,
string, length, invalid);
8153pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8154 const uint8_t *invalid = NULL;
8155 size_t length = pm_strspn_octal_number(
string, parser->end -
string, &invalid);
8156 pm_strspn_number_validate(parser,
string, length, invalid);
8161pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8162 const uint8_t *invalid = NULL;
8163 size_t length = pm_strspn_decimal_number(
string, parser->end -
string, &invalid);
8164 pm_strspn_number_validate(parser,
string, length, invalid);
8169pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8170 const uint8_t *invalid = NULL;
8171 size_t length = pm_strspn_hexadecimal_number(
string, parser->end -
string, &invalid);
8172 pm_strspn_number_validate(parser,
string, length, invalid);
8176static pm_token_type_t
8177lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8178 pm_token_type_t
type = PM_TOKEN_INTEGER;
8182 if (peek(parser) ==
'.') {
8183 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8184 parser->current.end += 2;
8185 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8186 type = PM_TOKEN_FLOAT;
8196 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8197 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8198 parser->current.end += 2;
8200 if (pm_char_is_decimal_digit(peek(parser))) {
8201 parser->current.end++;
8202 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8204 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8206 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8207 parser->current.end++;
8208 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8214 type = PM_TOKEN_FLOAT;
8220static pm_token_type_t
8221lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8222 pm_token_type_t
type = PM_TOKEN_INTEGER;
8225 if (peek_offset(parser, -1) ==
'0') {
8226 switch (*parser->current.end) {
8230 parser->current.end++;
8231 if (pm_char_is_decimal_digit(peek(parser))) {
8232 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8235 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8243 parser->current.end++;
8244 if (pm_char_is_binary_digit(peek(parser))) {
8245 parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
8248 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8251 parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
8257 parser->current.end++;
8258 if (pm_char_is_octal_digit(peek(parser))) {
8259 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8262 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8265 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8278 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8279 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8285 parser->current.end++;
8286 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8287 parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
8290 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8293 parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8298 type = lex_optional_float_suffix(parser, seen_e);
8305 type = lex_optional_float_suffix(parser, seen_e);
8314 const uint8_t *cursor = parser->current.end;
8315 const uint8_t *end = parser->end;
8316 uint64_t value = (uint64_t) (cursor[-1] -
'0');
8318 bool has_underscore =
false;
8319 bool prev_underscore =
false;
8320 const uint8_t *invalid = NULL;
8322 while (cursor < end) {
8323 uint8_t c = *cursor;
8324 if (c >=
'0' && c <=
'9') {
8325 if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c -
'0');
8326 prev_underscore =
false;
8328 }
else if (c ==
'_') {
8329 has_underscore =
true;
8330 if (prev_underscore && invalid == NULL) invalid = cursor;
8331 prev_underscore =
true;
8338 if (has_underscore) {
8339 if (prev_underscore && invalid == NULL) invalid = cursor - 1;
8340 pm_strspn_number_validate(parser, parser->current.end, (
size_t) (cursor - parser->current.end), invalid);
8343 if (value <= UINT32_MAX) {
8344 parser->integer.value = (uint32_t) value;
8345 parser->integer.lexed =
true;
8348 parser->current.end = cursor;
8356 uint8_t next = peek(parser);
8357 if (next ==
'.' || next ==
'e' || next ==
'E') {
8358 type = lex_optional_float_suffix(parser, seen_e);
8362 if (
type != PM_TOKEN_INTEGER) {
8363 parser->integer.lexed =
false;
8372 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8373 const uint8_t *fraction_start = parser->current.end;
8374 const uint8_t *fraction_end = parser->current.end + 2;
8375 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
8376 pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
8382static pm_token_type_t
8384 pm_token_type_t
type = PM_TOKEN_INTEGER;
8385 parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8386 parser->integer.lexed =
false;
8388 if (parser->current.end < parser->end) {
8389 bool seen_e =
false;
8390 type = lex_numeric_prefix(parser, &seen_e);
8392 const uint8_t *end = parser->current.end;
8393 pm_token_type_t suffix_type =
type;
8395 if (
type == PM_TOKEN_INTEGER) {
8396 if (match(parser,
'r')) {
8397 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8399 if (match(parser,
'i')) {
8400 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8402 }
else if (match(parser,
'i')) {
8403 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8406 if (!seen_e && match(parser,
'r')) {
8407 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8409 if (match(parser,
'i')) {
8410 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8412 }
else if (match(parser,
'i')) {
8413 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8417 const uint8_t b = peek(parser);
8418 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8419 parser->current.end = end;
8428static pm_token_type_t
8430 if (parser->current.end >= parser->end) {
8431 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8432 return PM_TOKEN_GLOBAL_VARIABLE;
8437 bool allow_multiple =
true;
8439 switch (*parser->current.end) {
8456 parser->current.end++;
8457 return PM_TOKEN_GLOBAL_VARIABLE;
8463 parser->current.end++;
8464 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8467 parser->current.end++;
8470 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8472 parser->current.end += width;
8473 }
while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8476 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;
8477 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
8480 return PM_TOKEN_GLOBAL_VARIABLE;
8492 parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
8493 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8496 parser->current.end++;
8497 allow_multiple =
false;
8502 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8504 parser->current.end += width;
8505 }
while (allow_multiple && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8506 }
else if (pm_char_is_whitespace(peek(parser))) {
8509 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8513 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;
8514 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8515 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);
8518 return PM_TOKEN_GLOBAL_VARIABLE;
8536lex_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) {
8537 if (memcmp(current_start, value, vlen) == 0) {
8538 pm_lex_state_t last_state = parser->lex_state;
8540 if (parser->lex_state & PM_LEX_STATE_FNAME) {
8541 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8543 lex_state_set(parser, state);
8544 if (state == PM_LEX_STATE_BEG) {
8545 parser->command_start =
true;
8548 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8549 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8550 return modifier_type;
8557 return PM_TOKEN_EOF;
8560static pm_token_type_t
8561lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8564 const uint8_t *end = parser->end;
8565 const uint8_t *current_start = parser->current.start;
8566 const uint8_t *current_end = parser->current.end;
8567 bool encoding_changed = parser->encoding_changed;
8569 if (encoding_changed) {
8570 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8571 current_end += width;
8575 current_end += scan_identifier_ascii(current_end, end);
8578 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8579 current_end += width;
8582 parser->current.end = current_end;
8586 width = (size_t) (current_end - current_start);
8588 if (current_end < end) {
8589 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8595 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8596 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8600 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8601 (void) match(parser,
':');
8605 parser->explicit_encoding = NULL;
8606 return PM_TOKEN_LABEL;
8609 if (parser->lex_state != PM_LEX_STATE_DOT) {
8610 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8611 return PM_TOKEN_KEYWORD_DEFINED;
8615 return PM_TOKEN_METHOD_NAME;
8618 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,
'=')) {
8621 return PM_TOKEN_IDENTIFIER;
8625 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8626 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8630 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8631 (void) match(parser,
':');
8635 parser->explicit_encoding = NULL;
8636 return PM_TOKEN_LABEL;
8640 if (parser->lex_state != PM_LEX_STATE_DOT) {
8641 pm_token_type_t
type;
8645 pm_lex_state_t previous_lex_state = parser->lex_state;
8649 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8657 if (previous_lex_state & PM_LEX_STATE_FNAME) {
8658 return PM_TOKEN_KEYWORD_DO;
8660 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
8674 parser->lambda_enclosure_nesting = -1;
8675 return PM_TOKEN_KEYWORD_DO_LAMBDA;
8677 if (pm_do_loop_stack_p(parser)) {
8678 return PM_TOKEN_KEYWORD_DO_LOOP;
8680 if (!pm_accepts_block_stack_p(parser)) {
8681 return PM_TOKEN_KEYWORD_DO_BLOCK;
8683 return PM_TOKEN_KEYWORD_DO;
8686 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;
8687 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;
8688 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;
8691 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;
8692 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;
8693 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;
8694 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;
8695 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;
8696 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;
8697 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;
8700 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;
8701 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;
8702 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;
8703 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;
8704 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;
8705 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;
8706 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;
8707 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;
8710 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;
8711 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;
8712 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;
8713 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;
8714 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;
8715 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;
8716 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;
8717 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;
8718 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;
8719 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;
8720 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;
8721 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;
8722 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;
8725 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;
8726 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;
8727 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;
8728 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;
8729 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;
8732 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;
8733 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;
8736 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;
8741 if (encoding_changed) {
8742 return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8748 if (*current_start < 0x80) {
8749 return (*current_start >=
'A' && *current_start <=
'Z') ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8751 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8760 return (parser->current.start == parser->start) || (parser->current.start[-1] ==
'\n');
8777static pm_token_type_t
8778lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8781 if (pound + 1 >= parser->end) {
8782 parser->current.end = pound + 1;
8783 return PM_TOKEN_STRING_CONTENT;
8792 if (pound + 2 >= parser->end) {
8793 parser->current.end = pound + 1;
8794 return PM_TOKEN_STRING_CONTENT;
8799 const uint8_t *variable = pound + 2;
8800 if (*variable ==
'@' && pound + 3 < parser->end) variable++;
8802 if (char_is_identifier_start(parser, variable, parser->end - variable)) {
8806 if (pound > parser->current.start) {
8807 parser->current.end = pound;
8808 return PM_TOKEN_STRING_CONTENT;
8813 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8814 parser->current.end = pound + 1;
8815 return PM_TOKEN_EMBVAR;
8821 parser->current.end = pound + 1;
8827 if (pound + 2 >= parser->end) {
8828 parser->current.end = pound + 1;
8829 return PM_TOKEN_STRING_CONTENT;
8835 const uint8_t *check = pound + 2;
8837 if (pound[2] ==
'-') {
8838 if (pound + 3 >= parser->end) {
8839 parser->current.end = pound + 2;
8840 return PM_TOKEN_STRING_CONTENT;
8851 char_is_identifier_start(parser, check, parser->end - check) ||
8852 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8857 if (pound > parser->current.start) {
8858 parser->current.end = pound;
8859 return PM_TOKEN_STRING_CONTENT;
8864 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8865 parser->current.end = pound + 1;
8866 return PM_TOKEN_EMBVAR;
8871 parser->current.end = pound + 1;
8877 if (pound > parser->current.start) {
8878 parser->current.end = pound;
8879 return PM_TOKEN_STRING_CONTENT;
8882 parser->enclosure_nesting++;
8886 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8887 parser->current.end = pound + 2;
8888 parser->command_start =
true;
8889 pm_enclosure_frame_push(parser);
8890 return PM_TOKEN_EMBEXPR_BEGIN;
8895 parser->current.end = pound + 1;
8900static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8901static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8902static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8903static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8904static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8909static const bool ascii_printable_chars[] = {
8910 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8911 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8912 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 1,
8915 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8916 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8917 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8921char_is_ascii_printable(
const uint8_t b) {
8922 return (b < 0x80) && ascii_printable_chars[b];
8930escape_hexadecimal_digit(
const uint8_t value) {
8931 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8940escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const pm_location_t *error_location,
const uint8_t flags) {
8942 for (
size_t index = 0; index < length; index++) {
8943 if (index != 0) value <<= 4;
8944 value |= escape_hexadecimal_digit(
string[index]);
8949 if (value >= 0xD800 && value <= 0xDFFF) {
8950 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8953 }
else if (error_location != NULL) {
8954 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
8956 pm_parser_err(parser, U32(
string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
8968escape_byte(uint8_t value,
const uint8_t flags) {
8969 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8970 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8978escape_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) {
8982 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8983 if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
8984 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8988 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
8992 parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
8995 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8996 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9000 pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
9003 pm_buffer_append_byte(buffer, 0xEF);
9004 pm_buffer_append_byte(buffer, 0xBF);
9005 pm_buffer_append_byte(buffer, 0xBD);
9016 if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
9017 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9021 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
9025 parser->explicit_encoding = parser->encoding;
9028 pm_buffer_append_byte(buffer,
byte);
9048 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9049 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9052 escape_write_byte_encoded(parser, buffer, flags,
byte);
9061 if (parser->encoding_changed) {
9062 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9064 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9068 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);
9069 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
9070 }
else if (width > 1) {
9072 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9073 pm_buffer_append_bytes(b, parser->current.end, width);
9074 parser->current.end += width;
9078 parser->current.end++;
9079 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9089escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9090#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9092 PM_PARSER_WARN_TOKEN_FORMAT(
9095 PM_WARN_INVALID_CHARACTER,
9109 uint8_t peeked = peek(parser);
9112 parser->current.end++;
9113 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9117 parser->current.end++;
9118 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9122 parser->current.end++;
9123 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9127 parser->current.end++;
9128 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9132 parser->current.end++;
9133 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9137 parser->current.end++;
9138 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9142 parser->current.end++;
9143 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9147 parser->current.end++;
9148 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9152 parser->current.end++;
9153 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9157 parser->current.end++;
9158 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9162 parser->current.end++;
9163 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9166 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9167 uint8_t value = (uint8_t) (*parser->current.end -
'0');
9168 parser->current.end++;
9170 if (pm_char_is_octal_digit(peek(parser))) {
9171 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9172 parser->current.end++;
9174 if (pm_char_is_octal_digit(peek(parser))) {
9175 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9176 parser->current.end++;
9180 value = escape_byte(value, flags);
9181 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9185 const uint8_t *start = parser->current.end - 1;
9187 parser->current.end++;
9188 uint8_t
byte = peek(parser);
9190 if (pm_char_is_hexadecimal_digit(
byte)) {
9191 uint8_t value = escape_hexadecimal_digit(
byte);
9192 parser->current.end++;
9194 byte = peek(parser);
9195 if (pm_char_is_hexadecimal_digit(
byte)) {
9196 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9197 parser->current.end++;
9200 value = escape_byte(value, flags);
9201 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9202 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9203 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9205 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9209 escape_write_byte_encoded(parser, buffer, flags, value);
9211 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9217 const uint8_t *start = parser->current.end - 1;
9218 parser->current.end++;
9220 if (parser->current.end == parser->end) {
9221 const uint8_t *start = parser->current.end - 2;
9222 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9223 }
else if (peek(parser) ==
'{') {
9224 const uint8_t *unicode_codepoints_start = parser->current.end - 2;
9225 parser->current.end++;
9229 if ((whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end)) > 0) {
9230 parser->current.end += whitespace;
9231 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9236 parser->current.end += 2;
9242 const uint8_t *extra_codepoints_start = NULL;
9243 int codepoints_count = 0;
9245 while ((parser->current.end < parser->end) && (*parser->current.end !=
'}')) {
9246 const uint8_t *unicode_start = parser->current.end;
9247 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
9249 if (hexadecimal_length > 6) {
9251 pm_parser_err(parser, U32(unicode_start - parser->start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9252 }
else if (hexadecimal_length == 0) {
9255 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9260 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9262 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
9263 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9269 parser->current.end += hexadecimal_length;
9271 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9272 extra_codepoints_start = unicode_start;
9275 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
9276 escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
9278 parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
9283 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9284 pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9287 if (parser->current.end == parser->end) {
9288 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);
9289 }
else if (peek(parser) ==
'}') {
9290 parser->current.end++;
9292 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9297 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9299 pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9303 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9304 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->current.end - unicode_codepoints_start));
9307 size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
9310 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9311 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9313 const uint8_t *start = parser->current.end - 2;
9314 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9316 }
else if (length == 4) {
9317 uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
9319 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9320 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end + 4 - start));
9323 escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
9324 parser->current.end += 4;
9326 parser->current.end += length;
9328 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9332 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9334 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9342 parser->current.end++;
9343 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9344 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9347 if (parser->current.end == parser->end) {
9348 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9352 uint8_t peeked = peek(parser);
9355 parser->current.end++;
9356 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9360 parser->current.end++;
9362 if (match(parser,
'u') || match(parser,
'U')) {
9363 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9367 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9370 parser->current.end++;
9371 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9372 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9375 parser->current.end++;
9376 escape_read_warn(parser, flags, 0,
"\\t");
9377 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9380 if (!char_is_ascii_printable(peeked)) {
9381 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9385 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);
9386 parser->current.end++;
9387 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9393 parser->current.end++;
9394 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9395 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9398 if (peek(parser) !=
'-') {
9399 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9400 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9404 parser->current.end++;
9405 if (parser->current.end == parser->end) {
9406 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9410 uint8_t peeked = peek(parser);
9413 parser->current.end++;
9414 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9418 parser->current.end++;
9420 if (match(parser,
'u') || match(parser,
'U')) {
9421 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9425 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9428 parser->current.end++;
9429 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9430 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9433 parser->current.end++;
9434 escape_read_warn(parser, flags, 0,
"\\t");
9435 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9438 if (!char_is_ascii_printable(peeked)) {
9439 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9440 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9444 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);
9445 parser->current.end++;
9446 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9452 parser->current.end++;
9453 if (flags & PM_ESCAPE_FLAG_META) {
9454 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9457 if (peek(parser) !=
'-') {
9458 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9459 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9463 parser->current.end++;
9464 if (parser->current.end == parser->end) {
9465 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9469 uint8_t peeked = peek(parser);
9472 parser->current.end++;
9474 if (match(parser,
'u') || match(parser,
'U')) {
9475 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9479 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9482 parser->current.end++;
9483 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9484 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9487 parser->current.end++;
9488 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9489 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9492 if (!char_is_ascii_printable(peeked)) {
9493 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9494 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9498 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);
9499 parser->current.end++;
9500 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9505 if (peek_offset(parser, 1) ==
'\n') {
9506 if (parser->heredoc_end == NULL) pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
9507 parser->current.end += 2;
9508 escape_write_byte_encoded(parser, buffer, flags, escape_byte(
'\n', flags));
9514 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9515 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9516 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9519 if (parser->current.end < parser->end) {
9520 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9522 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9554static pm_token_type_t
9556 if (lex_state_end_p(parser)) {
9557 lex_state_set(parser, PM_LEX_STATE_BEG);
9558 return PM_TOKEN_QUESTION_MARK;
9566 parser->explicit_encoding = NULL;
9568 if (parser->current.end >= parser->end) {
9569 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9570 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9571 return PM_TOKEN_CHARACTER_LITERAL;
9574 if (pm_char_is_whitespace(*parser->current.end)) {
9575 lex_state_set(parser, PM_LEX_STATE_BEG);
9576 return PM_TOKEN_QUESTION_MARK;
9579 lex_state_set(parser, PM_LEX_STATE_BEG);
9581 if (match(parser,
'\\')) {
9582 lex_state_set(parser, PM_LEX_STATE_END);
9585 pm_buffer_init(&buffer, 3);
9587 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9590 void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length,
PRISM_ALIGNOF(uint8_t));
9591 pm_string_constant_init(&parser->current_string, (
const char *) arena_data, buffer.length);
9592 pm_buffer_cleanup(&buffer);
9594 return PM_TOKEN_CHARACTER_LITERAL;
9596 size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9601 !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) ==
'_') ||
9603 (parser->current.end + encoding_width >= parser->end) ||
9604 !char_is_identifier(parser, parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
9607 lex_state_set(parser, PM_LEX_STATE_END);
9608 parser->current.end += encoding_width;
9609 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9610 return PM_TOKEN_CHARACTER_LITERAL;
9614 return PM_TOKEN_QUESTION_MARK;
9621static pm_token_type_t
9623 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9624 const uint8_t *end = parser->end;
9627 if ((width = char_is_identifier_start(parser, parser->current.end, end - parser->current.end)) > 0) {
9628 parser->current.end += width;
9630 while ((width = char_is_identifier(parser, parser->current.end, end - parser->current.end)) > 0) {
9631 parser->current.end += width;
9633 }
else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
9634 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9635 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
9636 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9639 size_t width = parser->encoding->char_width(parser->current.end, end - parser->current.end);
9640 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, (
int) ((parser->current.end + width) - parser->current.start), (
const char *) parser->current.start);
9642 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9643 pm_parser_err_token(parser, &parser->current, diag_id);
9648 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
9649 lex_mode_pop(parser);
9660 if (parser->lex_callback.callback) {
9661 parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
9674 .location = TOK2LOC(parser, &parser->current)
9685static pm_token_type_t
9688 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9690 if (newline == NULL) {
9691 parser->current.end = parser->end;
9693 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9694 parser->current.end = newline + 1;
9697 parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
9698 parser_lex_callback(parser);
9701 const uint8_t *comment_start = parser->current.start;
9702 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9706 while (parser->current.end + 4 <= parser->end) {
9707 parser->current.start = parser->current.end;
9712 (memcmp(parser->current.end,
"=end", 4) == 0) &&
9714 (parser->current.end + 4 == parser->end) ||
9715 pm_char_is_whitespace(parser->current.end[4]) ||
9716 (parser->current.end[4] ==
'\0') ||
9717 (parser->current.end[4] ==
'\004') ||
9718 (parser->current.end[4] ==
'\032')
9721 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9723 if (newline == NULL) {
9724 parser->current.end = parser->end;
9726 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9727 parser->current.end = newline + 1;
9730 parser->current.type = PM_TOKEN_EMBDOC_END;
9731 parser_lex_callback(parser);
9733 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9734 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9736 return PM_TOKEN_EMBDOC_END;
9741 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9743 if (newline == NULL) {
9744 parser->current.end = parser->end;
9746 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9747 parser->current.end = newline + 1;
9750 parser->current.type = PM_TOKEN_EMBDOC_LINE;
9751 parser_lex_callback(parser);
9754 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9756 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9757 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9759 return PM_TOKEN_EOF;
9769 parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
9770 parser_lex_callback(parser);
9784 assert(parser->heredoc_end <= parser->end);
9785 parser->next_start = parser->heredoc_end;
9786 parser->heredoc_end = NULL;
9794 const uint8_t *cursor = parser->current.end;
9796 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9797 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9860 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9874 if (parser->encoding_changed) {
9875 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9877 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9882 return (width == 0 ? 1 : width);
9890 size_t width = parser_char_width(parser);
9891 pm_buffer_append_bytes(&token_buffer->
buffer, parser->current.end, width);
9892 parser->current.end += width;
9897 size_t width = parser_char_width(parser);
9898 const uint8_t *start = parser->current.end;
9899 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, width);
9900 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, width);
9901 parser->current.end += width;
9913 size_t len = pm_buffer_length(&token_buffer->
buffer);
9914 void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->
buffer),
len,
PRISM_ALIGNOF(uint8_t));
9915 pm_string_constant_init(&parser->current_string, (
const char *) arena_data,
len);
9916 pm_buffer_cleanup(&token_buffer->
buffer);
9921 pm_token_buffer_copy(parser, &token_buffer->
base);
9936 if (token_buffer->
cursor == NULL) {
9937 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9939 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->current.end - token_buffer->
cursor));
9940 pm_token_buffer_copy(parser, token_buffer);
9947 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9949 const uint8_t *cursor = token_buffer->
base.
cursor;
9950 size_t length = (size_t) (parser->current.end - cursor);
9951 pm_buffer_append_bytes(&token_buffer->
base.
buffer, cursor, length);
9952 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, cursor, length);
9953 pm_regexp_token_buffer_copy(parser, token_buffer);
9957#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9969 const uint8_t *start;
9970 if (token_buffer->
cursor == NULL) {
9971 pm_buffer_init(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9972 start = parser->current.start;
9974 start = token_buffer->
cursor;
9977 const uint8_t *end = parser->current.end - 1;
9978 assert(end >= start);
9979 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9981 token_buffer->
cursor = end;
9986 const uint8_t *start;
9988 pm_buffer_init(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9989 pm_buffer_init(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9990 start = parser->current.start;
9995 const uint8_t *end = parser->current.end - 1;
9996 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9997 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10002#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10009pm_heredoc_strspn_inline_whitespace(
pm_parser_t *parser,
const uint8_t **cursor, pm_heredoc_indent_t indent) {
10010 size_t whitespace = 0;
10013 case PM_HEREDOC_INDENT_NONE:
10018 case PM_HEREDOC_INDENT_DASH:
10020 *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
10022 case PM_HEREDOC_INDENT_TILDE:
10025 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10026 if (**cursor ==
'\t') {
10027 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10046 size_t eol_length = match_eol(parser);
10049 if (parser->heredoc_end) {
10053 parser_flush_heredoc_end(parser);
10056 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
10059 uint8_t delimiter = *parser->current.end;
10063 if (eol_length == 2) {
10064 delimiter = *(parser->current.end + 1);
10067 parser->current.end += eol_length;
10071 return *parser->current.end++;
10078#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10088 assert(parser->current.end <= parser->end);
10089 parser->previous = parser->current;
10092 bool previous_command_start = parser->command_start;
10093 parser->command_start =
false;
10097 bool lexed_comment =
false;
10101 unsigned int semantic_token_seen = parser->semantic_token_seen;
10102 parser->semantic_token_seen =
true;
10110 switch (parser->lex_modes.current->mode) {
10111 case PM_LEX_DEFAULT:
10112 case PM_LEX_EMBEXPR:
10113 case PM_LEX_EMBVAR:
10122 if (parser->next_start != NULL) {
10123 parser->current.end = parser->next_start;
10124 parser->next_start = NULL;
10129 bool space_seen =
false;
10134 bool chomping =
true;
10141 static const uint8_t inline_whitespace[256] = {
10142 [
' '] = 1, [
'\t'] = 1, [
'\f'] = 1, [
'\v'] = 1
10144 const uint8_t *scan = parser->current.end;
10145 while (scan < parser->end && inline_whitespace[*scan]) scan++;
10146 if (scan > parser->current.end) {
10147 parser->current.end = scan;
10150 if (scan >= parser->end)
break;
10153 switch (*parser->current.end) {
10155 if (match_eol_offset(parser, 1)) {
10158 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10159 parser->current.end++;
10164 size_t eol_length = match_eol_offset(parser, 1);
10166 if (parser->heredoc_end) {
10167 parser->current.end = parser->heredoc_end;
10168 parser->heredoc_end = NULL;
10170 parser->current.end += eol_length + 1;
10171 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10174 }
else if (pm_char_is_inline_whitespace(*parser->current.end)) {
10175 parser->current.end += 2;
10189 parser->current.start = parser->current.end;
10193 if (parser->current.end >= parser->end) {
10197 if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
10198 lex_mode_pop(parser);
10199 goto switch_lex_modes;
10207 if (parser->current.start > parser->start && (*(parser->current.start - 1) ==
'\n')) {
10208 parser->current.start -= 1;
10215 switch (*parser->current.end++) {
10219 parser->current.end--;
10223 const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
10224 parser->current.end = ending == NULL ? parser->end : ending;
10229 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10230 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
10232 parser->current.type = PM_TOKEN_COMMENT;
10233 parser_lex_callback(parser);
10237 if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
10238 ptrdiff_t length = parser->current.end - parser->current.start;
10244 if (length >= 10 && !parser->encoding_locked) {
10245 parser_lex_magic_comment_encoding(parser);
10253 if (ending == NULL) {
10254 lexed_comment =
true;
10256 parser->current.start = ending;
10257 parser->current.end = ending + 1;
10263 parser->semantic_token_seen = semantic_token_seen & 0x1;
10264 size_t eol_length = match_eol_at(parser, parser->current.end - 1);
10276 if (!lexed_comment) {
10277 parser->current.end += eol_length - 1;
10280 if (parser->heredoc_end == NULL) {
10281 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10285 if (parser->heredoc_end) {
10286 parser_flush_heredoc_end(parser);
10291 switch (lex_state_ignored_p(parser)) {
10292 case PM_IGNORED_NEWLINE_NONE:
10294 case PM_IGNORED_NEWLINE_PATTERN:
10295 if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
10296 if (!lexed_comment) {
10297 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10298 parser_lex_callback(parser);
10301 lex_state_set(parser, PM_LEX_STATE_BEG);
10302 parser->command_start =
true;
10303 parser->current.type = PM_TOKEN_NEWLINE;
10307 case PM_IGNORED_NEWLINE_ALL:
10308 if (!lexed_comment) parser_lex_ignored_newline(parser);
10309 lexed_comment =
false;
10310 goto lex_next_token;
10317 const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
10318 next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
10320 if (next_content < parser->end) {
10326 if (next_content[0] ==
'#') {
10328 const uint8_t *following = next_newline(next_content, parser->end - next_content);
10330 while (following && (following + 1 < parser->end)) {
10332 following += pm_strspn_inline_whitespace(following, parser->end - following);
10336 if (peek_at(parser, following) !=
'#')
break;
10340 following = next_newline(following, parser->end - following);
10345 if (lex_state_ignored_p(parser)) {
10346 if (!lexed_comment) parser_lex_ignored_newline(parser);
10347 lexed_comment =
false;
10348 goto lex_next_token;
10354 (peek_at(parser, following) ==
'.') ||
10355 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10357 if (!lexed_comment) parser_lex_ignored_newline(parser);
10358 lexed_comment =
false;
10359 goto lex_next_token;
10367 (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
10369 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10370 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10372 peek_at(parser, following) ==
'a' &&
10373 peek_at(parser, following + 1) ==
'n' &&
10374 peek_at(parser, following + 2) ==
'd' &&
10375 peek_at(parser, next_content + 3) !=
'!' &&
10376 peek_at(parser, next_content + 3) !=
'?' &&
10377 !char_is_identifier(parser, following + 3, parser->end - (following + 3))
10380 peek_at(parser, following) ==
'o' &&
10381 peek_at(parser, following + 1) ==
'r' &&
10382 peek_at(parser, next_content + 2) !=
'!' &&
10383 peek_at(parser, next_content + 2) !=
'?' &&
10384 !char_is_identifier(parser, following + 2, parser->end - (following + 2))
10388 if (!lexed_comment) parser_lex_ignored_newline(parser);
10389 lexed_comment =
false;
10390 goto lex_next_token;
10396 if (next_content[0] ==
'.') {
10400 if (peek_at(parser, next_content + 1) ==
'.') {
10401 if (!lexed_comment) {
10402 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10403 parser_lex_callback(parser);
10406 lex_state_set(parser, PM_LEX_STATE_BEG);
10407 parser->command_start =
true;
10408 parser->current.type = PM_TOKEN_NEWLINE;
10412 if (!lexed_comment) parser_lex_ignored_newline(parser);
10413 lex_state_set(parser, PM_LEX_STATE_DOT);
10414 parser->current.start = next_content;
10415 parser->current.end = next_content + 1;
10416 parser->next_start = NULL;
10422 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10423 if (!lexed_comment) parser_lex_ignored_newline(parser);
10424 lex_state_set(parser, PM_LEX_STATE_DOT);
10425 parser->current.start = next_content;
10426 parser->current.end = next_content + 2;
10427 parser->next_start = NULL;
10428 LEX(PM_TOKEN_AMPERSAND_DOT);
10431 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
10434 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10435 if (!lexed_comment) parser_lex_ignored_newline(parser);
10436 lex_state_set(parser, PM_LEX_STATE_BEG);
10437 parser->current.start = next_content;
10438 parser->current.end = next_content + 2;
10439 parser->next_start = NULL;
10440 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10445 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10446 if (!lexed_comment) parser_lex_ignored_newline(parser);
10447 lex_state_set(parser, PM_LEX_STATE_BEG);
10448 parser->current.start = next_content;
10449 parser->current.end = next_content + 2;
10450 parser->next_start = NULL;
10451 LEX(PM_TOKEN_PIPE_PIPE);
10457 peek_at(parser, next_content) ==
'a' &&
10458 peek_at(parser, next_content + 1) ==
'n' &&
10459 peek_at(parser, next_content + 2) ==
'd' &&
10460 peek_at(parser, next_content + 3) !=
'!' &&
10461 peek_at(parser, next_content + 3) !=
'?' &&
10462 !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
10464 if (!lexed_comment) parser_lex_ignored_newline(parser);
10465 lex_state_set(parser, PM_LEX_STATE_BEG);
10466 parser->current.start = next_content;
10467 parser->current.end = next_content + 3;
10468 parser->next_start = NULL;
10469 parser->command_start =
true;
10470 LEX(PM_TOKEN_KEYWORD_AND);
10476 peek_at(parser, next_content) ==
'o' &&
10477 peek_at(parser, next_content + 1) ==
'r' &&
10478 peek_at(parser, next_content + 2) !=
'!' &&
10479 peek_at(parser, next_content + 2) !=
'?' &&
10480 !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
10482 if (!lexed_comment) parser_lex_ignored_newline(parser);
10483 lex_state_set(parser, PM_LEX_STATE_BEG);
10484 parser->current.start = next_content;
10485 parser->current.end = next_content + 2;
10486 parser->next_start = NULL;
10487 parser->command_start =
true;
10488 LEX(PM_TOKEN_KEYWORD_OR);
10495 lex_state_set(parser, PM_LEX_STATE_BEG);
10496 parser->command_start =
true;
10497 parser->current.type = PM_TOKEN_NEWLINE;
10498 if (!lexed_comment) parser_lex_callback(parser);
10504 if ((parser->previous.
type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
10505 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
10508 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10509 LEX(PM_TOKEN_COMMA);
10517 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10519 if (lex_state_beg_p(parser)) {
10520 type = PM_TOKEN_PARENTHESIS_LEFT_GROUPING;
10521 }
else if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10522 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10525 parser->enclosure_nesting++;
10526 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10527 pm_enclosure_frame_push(parser);
10533 parser->enclosure_nesting--;
10534 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10535 pm_enclosure_frame_pop(parser);
10536 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10540 lex_state_set(parser, PM_LEX_STATE_BEG);
10541 parser->command_start =
true;
10542 LEX(PM_TOKEN_SEMICOLON);
10546 parser->enclosure_nesting++;
10547 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10549 if (lex_state_operator_p(parser)) {
10550 if (match(parser,
']')) {
10551 parser->enclosure_nesting--;
10552 lex_state_set(parser, PM_LEX_STATE_ARG);
10553 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10556 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10560 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10561 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10564 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10565 pm_enclosure_frame_push(parser);
10570 parser->enclosure_nesting--;
10571 lex_state_set(parser, PM_LEX_STATE_END);
10572 pm_enclosure_frame_pop(parser);
10573 LEX(PM_TOKEN_BRACKET_RIGHT);
10577 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10579 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
10581 parser->command_start =
true;
10582 lex_state_set(parser, PM_LEX_STATE_BEG);
10583 type = PM_TOKEN_LAMBDA_BEGIN;
10584 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10586 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10587 type = PM_TOKEN_BRACE_LEFT_HASH;
10588 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10590 parser->command_start =
true;
10591 lex_state_set(parser, PM_LEX_STATE_BEG);
10592 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10595 parser->command_start =
true;
10596 lex_state_set(parser, PM_LEX_STATE_BEG);
10597 type = PM_TOKEN_BRACE_LEFT_ARGUMENT;
10600 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10601 type = PM_TOKEN_BRACE_LEFT_HASH;
10604 parser->enclosure_nesting++;
10605 parser->brace_nesting++;
10606 pm_enclosure_frame_push(parser);
10613 parser->enclosure_nesting--;
10614 pm_enclosure_frame_pop(parser);
10616 if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
10617 lex_mode_pop(parser);
10618 LEX(PM_TOKEN_EMBEXPR_END);
10621 parser->brace_nesting--;
10622 lex_state_set(parser, PM_LEX_STATE_END);
10623 LEX(PM_TOKEN_BRACE_RIGHT);
10627 if (match(parser,
'*')) {
10628 if (match(parser,
'=')) {
10629 lex_state_set(parser, PM_LEX_STATE_BEG);
10630 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10633 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10635 if (lex_state_spcarg_p(parser, space_seen)) {
10636 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10637 type = PM_TOKEN_USTAR_STAR;
10638 }
else if (lex_state_beg_p(parser)) {
10639 type = PM_TOKEN_USTAR_STAR;
10640 }
else if (ambiguous_operator_p(parser, space_seen)) {
10641 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10644 if (lex_state_operator_p(parser)) {
10645 lex_state_set(parser, PM_LEX_STATE_ARG);
10647 lex_state_set(parser, PM_LEX_STATE_BEG);
10653 if (match(parser,
'=')) {
10654 lex_state_set(parser, PM_LEX_STATE_BEG);
10655 LEX(PM_TOKEN_STAR_EQUAL);
10658 pm_token_type_t
type = PM_TOKEN_STAR;
10660 if (lex_state_spcarg_p(parser, space_seen)) {
10661 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10662 type = PM_TOKEN_USTAR;
10663 }
else if (lex_state_beg_p(parser)) {
10664 type = PM_TOKEN_USTAR;
10665 }
else if (ambiguous_operator_p(parser, space_seen)) {
10666 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10669 if (lex_state_operator_p(parser)) {
10670 lex_state_set(parser, PM_LEX_STATE_ARG);
10672 lex_state_set(parser, PM_LEX_STATE_BEG);
10680 if (lex_state_operator_p(parser)) {
10681 lex_state_set(parser, PM_LEX_STATE_ARG);
10682 if (match(parser,
'@')) {
10683 LEX(PM_TOKEN_BANG);
10686 lex_state_set(parser, PM_LEX_STATE_BEG);
10689 if (match(parser,
'=')) {
10690 LEX(PM_TOKEN_BANG_EQUAL);
10693 if (match(parser,
'~')) {
10694 LEX(PM_TOKEN_BANG_TILDE);
10697 LEX(PM_TOKEN_BANG);
10702 current_token_starts_line(parser) &&
10703 (parser->current.end + 5 <= parser->end) &&
10704 memcmp(parser->current.end,
"begin", 5) == 0 &&
10705 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10707 pm_token_type_t
type = lex_embdoc(parser);
10708 if (
type == PM_TOKEN_EOF) {
10712 goto lex_next_token;
10715 if (lex_state_operator_p(parser)) {
10716 lex_state_set(parser, PM_LEX_STATE_ARG);
10718 lex_state_set(parser, PM_LEX_STATE_BEG);
10721 if (match(parser,
'>')) {
10722 LEX(PM_TOKEN_EQUAL_GREATER);
10725 if (match(parser,
'~')) {
10726 LEX(PM_TOKEN_EQUAL_TILDE);
10729 if (match(parser,
'=')) {
10730 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10733 LEX(PM_TOKEN_EQUAL);
10737 if (match(parser,
'<')) {
10739 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10740 !lex_state_end_p(parser) &&
10741 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10743 const uint8_t *end = parser->current.end;
10745 pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
10746 pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
10748 if (match(parser,
'-')) {
10749 indent = PM_HEREDOC_INDENT_DASH;
10751 else if (match(parser,
'~')) {
10752 indent = PM_HEREDOC_INDENT_TILDE;
10755 if (match(parser,
'`')) {
10756 quote = PM_HEREDOC_QUOTE_BACKTICK;
10758 else if (match(parser,
'"')) {
10759 quote = PM_HEREDOC_QUOTE_DOUBLE;
10761 else if (match(parser,
'\'')) {
10762 quote = PM_HEREDOC_QUOTE_SINGLE;
10765 const uint8_t *ident_start = parser->current.end;
10768 if (parser->current.end >= parser->end) {
10769 parser->current.end = end;
10770 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) == 0) {
10771 parser->current.end = end;
10773 if (quote == PM_HEREDOC_QUOTE_NONE) {
10774 parser->current.end += width;
10776 while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end))) {
10777 parser->current.end += width;
10782 while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
10783 if (*parser->current.end ==
'\r' || *parser->current.end ==
'\n')
break;
10784 parser->current.end++;
10788 size_t ident_length = (size_t) (parser->current.end - ident_start);
10789 bool ident_error =
false;
10791 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10792 pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10793 ident_error =
true;
10796 parser->explicit_encoding = NULL;
10798 .mode = PM_LEX_HEREDOC,
10801 .ident_start = ident_start,
10802 .ident_length = ident_length,
10806 .next_start = parser->current.end,
10807 .common_whitespace = NULL,
10808 .line_continuation =
false
10812 if (parser->heredoc_end == NULL) {
10813 const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
10815 if (body_start == NULL) {
10820 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10821 body_start = parser->end;
10825 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
10829 parser->next_start = body_start;
10831 parser->next_start = parser->heredoc_end;
10834 LEX(PM_TOKEN_HEREDOC_START);
10838 if (match(parser,
'=')) {
10839 lex_state_set(parser, PM_LEX_STATE_BEG);
10840 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10843 if (ambiguous_operator_p(parser, space_seen)) {
10844 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10847 if (lex_state_operator_p(parser)) {
10848 lex_state_set(parser, PM_LEX_STATE_ARG);
10850 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10851 lex_state_set(parser, PM_LEX_STATE_BEG);
10854 LEX(PM_TOKEN_LESS_LESS);
10857 if (lex_state_operator_p(parser)) {
10858 lex_state_set(parser, PM_LEX_STATE_ARG);
10860 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10861 lex_state_set(parser, PM_LEX_STATE_BEG);
10864 if (match(parser,
'=')) {
10865 if (match(parser,
'>')) {
10866 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10869 LEX(PM_TOKEN_LESS_EQUAL);
10872 LEX(PM_TOKEN_LESS);
10876 if (match(parser,
'>')) {
10877 if (lex_state_operator_p(parser)) {
10878 lex_state_set(parser, PM_LEX_STATE_ARG);
10880 lex_state_set(parser, PM_LEX_STATE_BEG);
10882 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10885 if (lex_state_operator_p(parser)) {
10886 lex_state_set(parser, PM_LEX_STATE_ARG);
10888 lex_state_set(parser, PM_LEX_STATE_BEG);
10891 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10895 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10896 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10897 LEX(PM_TOKEN_STRING_BEGIN);
10902 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10903 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10904 LEX(PM_TOKEN_BACKTICK);
10907 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10908 if (previous_command_start) {
10909 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10911 lex_state_set(parser, PM_LEX_STATE_ARG);
10914 LEX(PM_TOKEN_BACKTICK);
10917 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10918 LEX(PM_TOKEN_XSTRING_BEGIN);
10923 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10924 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10925 LEX(PM_TOKEN_STRING_BEGIN);
10930 LEX(lex_question_mark(parser));
10934 if (match(parser,
'&')) {
10935 lex_state_set(parser, PM_LEX_STATE_BEG);
10937 if (match(parser,
'=')) {
10938 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10941 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10944 if (match(parser,
'=')) {
10945 lex_state_set(parser, PM_LEX_STATE_BEG);
10946 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10949 if (match(parser,
'.')) {
10950 lex_state_set(parser, PM_LEX_STATE_DOT);
10951 LEX(PM_TOKEN_AMPERSAND_DOT);
10954 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10955 if (lex_state_spcarg_p(parser, space_seen)) {
10956 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10957 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10959 const uint8_t delim = peek_offset(parser, 1);
10961 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->current.end + 1, parser->end - (parser->current.end + 1))) {
10962 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10966 type = PM_TOKEN_UAMPERSAND;
10967 }
else if (lex_state_beg_p(parser)) {
10968 type = PM_TOKEN_UAMPERSAND;
10969 }
else if (ambiguous_operator_p(parser, space_seen)) {
10970 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10973 if (lex_state_operator_p(parser)) {
10974 lex_state_set(parser, PM_LEX_STATE_ARG);
10976 lex_state_set(parser, PM_LEX_STATE_BEG);
10984 if (match(parser,
'|')) {
10985 if (match(parser,
'=')) {
10986 lex_state_set(parser, PM_LEX_STATE_BEG);
10987 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10990 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10991 parser->current.end--;
10992 LEX(PM_TOKEN_PIPE);
10995 lex_state_set(parser, PM_LEX_STATE_BEG);
10996 LEX(PM_TOKEN_PIPE_PIPE);
10999 if (match(parser,
'=')) {
11000 lex_state_set(parser, PM_LEX_STATE_BEG);
11001 LEX(PM_TOKEN_PIPE_EQUAL);
11004 if (lex_state_operator_p(parser)) {
11005 lex_state_set(parser, PM_LEX_STATE_ARG);
11007 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11010 LEX(PM_TOKEN_PIPE);
11014 if (lex_state_operator_p(parser)) {
11015 lex_state_set(parser, PM_LEX_STATE_ARG);
11017 if (match(parser,
'@')) {
11018 LEX(PM_TOKEN_UPLUS);
11021 LEX(PM_TOKEN_PLUS);
11024 if (match(parser,
'=')) {
11025 lex_state_set(parser, PM_LEX_STATE_BEG);
11026 LEX(PM_TOKEN_PLUS_EQUAL);
11030 lex_state_beg_p(parser) ||
11031 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11033 lex_state_set(parser, PM_LEX_STATE_BEG);
11035 if (pm_char_is_decimal_digit(peek(parser))) {
11036 parser->current.end++;
11037 pm_token_type_t
type = lex_numeric(parser);
11038 lex_state_set(parser, PM_LEX_STATE_END);
11042 LEX(PM_TOKEN_UPLUS);
11045 if (ambiguous_operator_p(parser, space_seen)) {
11046 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11049 lex_state_set(parser, PM_LEX_STATE_BEG);
11050 LEX(PM_TOKEN_PLUS);
11055 if (lex_state_operator_p(parser)) {
11056 lex_state_set(parser, PM_LEX_STATE_ARG);
11058 if (match(parser,
'@')) {
11059 LEX(PM_TOKEN_UMINUS);
11062 LEX(PM_TOKEN_MINUS);
11065 if (match(parser,
'=')) {
11066 lex_state_set(parser, PM_LEX_STATE_BEG);
11067 LEX(PM_TOKEN_MINUS_EQUAL);
11070 if (match(parser,
'>')) {
11071 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11072 LEX(PM_TOKEN_MINUS_GREATER);
11075 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11076 bool is_beg = lex_state_beg_p(parser);
11077 if (!is_beg && spcarg) {
11078 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11081 if (is_beg || spcarg) {
11082 lex_state_set(parser, PM_LEX_STATE_BEG);
11083 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11086 if (ambiguous_operator_p(parser, space_seen)) {
11087 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11090 lex_state_set(parser, PM_LEX_STATE_BEG);
11091 LEX(PM_TOKEN_MINUS);
11096 bool beg_p = lex_state_beg_p(parser);
11098 if (match(parser,
'.')) {
11099 if (match(parser,
'.')) {
11101 if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) {
11102 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11103 lex_state_set(parser, PM_LEX_STATE_BEG);
11105 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11107 LEX(PM_TOKEN_UDOT_DOT_DOT);
11110 if (parser->enclosure_nesting == 0 && parser_end_of_line_p(parser)) {
11111 pm_parser_warn_token(parser, &parser->current, PM_WARN_DOT_DOT_DOT_EOL);
11114 lex_state_set(parser, PM_LEX_STATE_BEG);
11115 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11118 lex_state_set(parser, PM_LEX_STATE_BEG);
11119 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11122 lex_state_set(parser, PM_LEX_STATE_DOT);
11137 pm_token_type_t
type = lex_numeric(parser);
11138 lex_state_set(parser, PM_LEX_STATE_END);
11144 if (match(parser,
':')) {
11145 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)) {
11146 lex_state_set(parser, PM_LEX_STATE_BEG);
11147 LEX(PM_TOKEN_UCOLON_COLON);
11150 lex_state_set(parser, PM_LEX_STATE_DOT);
11151 LEX(PM_TOKEN_COLON_COLON);
11154 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11155 lex_state_set(parser, PM_LEX_STATE_BEG);
11156 LEX(PM_TOKEN_COLON);
11159 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11160 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->current.end);
11161 parser->current.end++;
11168 parser->explicit_encoding = NULL;
11171 lex_state_set(parser, PM_LEX_STATE_FNAME);
11172 LEX(PM_TOKEN_SYMBOL_BEGIN);
11176 if (lex_state_beg_p(parser)) {
11177 lex_mode_push_regexp(parser,
'\0',
'/');
11178 LEX(PM_TOKEN_REGEXP_BEGIN);
11181 if (match(parser,
'=')) {
11182 lex_state_set(parser, PM_LEX_STATE_BEG);
11183 LEX(PM_TOKEN_SLASH_EQUAL);
11186 if (lex_state_spcarg_p(parser, space_seen)) {
11188 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_4_0) {
11189 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
11191 lex_mode_push_regexp(parser,
'\0',
'/');
11192 LEX(PM_TOKEN_REGEXP_BEGIN);
11195 if (ambiguous_operator_p(parser, space_seen)) {
11196 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11199 if (lex_state_operator_p(parser)) {
11200 lex_state_set(parser, PM_LEX_STATE_ARG);
11202 lex_state_set(parser, PM_LEX_STATE_BEG);
11205 LEX(PM_TOKEN_SLASH);
11209 if (lex_state_operator_p(parser)) {
11210 lex_state_set(parser, PM_LEX_STATE_ARG);
11212 lex_state_set(parser, PM_LEX_STATE_BEG);
11214 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11218 if (lex_state_operator_p(parser)) {
11219 (void) match(parser,
'@');
11220 lex_state_set(parser, PM_LEX_STATE_ARG);
11222 lex_state_set(parser, PM_LEX_STATE_BEG);
11225 LEX(PM_TOKEN_TILDE);
11233 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
11234 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11235 LEX(PM_TOKEN_PERCENT);
11238 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11239 lex_state_set(parser, PM_LEX_STATE_BEG);
11240 LEX(PM_TOKEN_PERCENT_EQUAL);
11242 lex_state_beg_p(parser) ||
11243 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11244 lex_state_spcarg_p(parser, space_seen)
11246 if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) {
11247 if (*parser->current.end >= 0x80) {
11248 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11249 goto lex_next_token;
11252 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11253 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11254 LEX(PM_TOKEN_STRING_BEGIN);
11259 uint8_t delimiter = peek_offset(parser, 1);
11260 if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) {
11261 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11262 goto lex_next_token;
11265 switch (peek(parser)) {
11267 parser->current.end++;
11269 if (parser->current.end < parser->end) {
11270 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11272 lex_mode_push_list_eof(parser);
11275 LEX(PM_TOKEN_PERCENT_LOWER_I);
11278 parser->current.end++;
11280 if (parser->current.end < parser->end) {
11281 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11283 lex_mode_push_list_eof(parser);
11286 LEX(PM_TOKEN_PERCENT_UPPER_I);
11289 parser->current.end++;
11291 if (parser->current.end < parser->end) {
11292 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11293 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11295 lex_mode_push_regexp(parser,
'\0',
'\0');
11298 LEX(PM_TOKEN_REGEXP_BEGIN);
11301 parser->current.end++;
11303 if (parser->current.end < parser->end) {
11304 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11305 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11307 lex_mode_push_string_eof(parser);
11310 LEX(PM_TOKEN_STRING_BEGIN);
11313 parser->current.end++;
11315 if (parser->current.end < parser->end) {
11316 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11317 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11319 lex_mode_push_string_eof(parser);
11322 LEX(PM_TOKEN_STRING_BEGIN);
11325 parser->current.end++;
11327 if (parser->current.end < parser->end) {
11328 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11329 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11330 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11332 lex_mode_push_string_eof(parser);
11335 LEX(PM_TOKEN_SYMBOL_BEGIN);
11338 parser->current.end++;
11340 if (parser->current.end < parser->end) {
11341 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11343 lex_mode_push_list_eof(parser);
11346 LEX(PM_TOKEN_PERCENT_LOWER_W);
11349 parser->current.end++;
11351 if (parser->current.end < parser->end) {
11352 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11354 lex_mode_push_list_eof(parser);
11357 LEX(PM_TOKEN_PERCENT_UPPER_W);
11360 parser->current.end++;
11362 if (parser->current.end < parser->end) {
11363 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11364 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11366 lex_mode_push_string_eof(parser);
11369 LEX(PM_TOKEN_PERCENT_LOWER_X);
11376 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11377 goto lex_next_token;
11381 if (ambiguous_operator_p(parser, space_seen)) {
11382 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11385 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11386 LEX(PM_TOKEN_PERCENT);
11391 pm_token_type_t
type = lex_global_variable(parser);
11395 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
11396 lex_mode_pop(parser);
11399 lex_state_set(parser, PM_LEX_STATE_END);
11405 lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11406 LEX(lex_at_variable(parser));
11409 if (*parser->current.start !=
'_') {
11410 size_t width = char_is_identifier_start(parser, parser->current.start, parser->end - parser->current.start);
11417 if (*parser->current.start >= 0x80) {
11418 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
11419 }
else if (*parser->current.start ==
'\\') {
11420 switch (peek_at(parser, parser->current.start + 1)) {
11422 parser->current.end++;
11423 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11426 parser->current.end++;
11427 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11430 parser->current.end++;
11431 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11434 parser->current.end++;
11435 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11438 if (peek_at(parser, parser->current.start + 2) !=
'\n') {
11439 parser->current.end++;
11440 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11445 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11448 }
else if (char_is_ascii_printable(*parser->current.start)) {
11449 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
11451 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
11454 goto lex_next_token;
11457 parser->current.end = parser->current.start + width;
11460 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11467 ((parser->current.end - parser->current.start) == 7) &&
11468 current_token_starts_line(parser) &&
11469 (memcmp(parser->current.start,
"__END__", 7) == 0) &&
11470 (parser->current.end == parser->end || match_eol(parser))
11475 const uint8_t *cursor = parser->current.end;
11476 while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
11477 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
11480 parser->current.end = parser->end;
11481 parser->current.type = PM_TOKEN___END__;
11482 parser_lex_callback(parser);
11484 parser->data_loc.
start = PM_TOKEN_START(parser, &parser->current);
11485 parser->data_loc.
length = PM_TOKEN_LENGTH(&parser->current);
11490 pm_lex_state_t last_state = parser->lex_state;
11492 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11493 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11494 if (previous_command_start) {
11495 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11497 lex_state_set(parser, PM_LEX_STATE_ARG);
11499 }
else if (parser->lex_state == PM_LEX_STATE_FNAME) {
11500 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11502 lex_state_set(parser, PM_LEX_STATE_END);
11507 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11508 (
type == PM_TOKEN_IDENTIFIER) &&
11509 ((pm_parser_local_depth(parser, &parser->current) != -1) ||
11510 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
11512 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11519 case PM_LEX_LIST: {
11520 if (parser->next_start != NULL) {
11521 parser->current.end = parser->next_start;
11522 parser->next_start = NULL;
11526 parser->current.start = parser->current.end;
11534 if (parser->heredoc_end) {
11535 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11536 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11539 }
else if (lex_mode->as.list.terminator ==
'\n') {
11544 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11546 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));
11549 if (whitespace > 0) {
11550 parser->current.end += whitespace;
11551 if (peek_offset(parser, -1) ==
'\n') {
11553 parser_flush_heredoc_end(parser);
11555 LEX(PM_TOKEN_WORDS_SEP);
11560 if (parser->current.end >= parser->end) {
11566 const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
11567 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11573 while (breakpoint != NULL) {
11578 if (pm_char_is_whitespace(*breakpoint) && *breakpoint != lex_mode->as.list.terminator) {
11579 parser->current.end = breakpoint;
11580 pm_token_buffer_flush(parser, &token_buffer);
11581 LEX(PM_TOKEN_STRING_CONTENT);
11586 if (*breakpoint == lex_mode->as.list.terminator) {
11589 if (lex_mode->as.list.nesting > 0) {
11590 parser->current.end = breakpoint + 1;
11591 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11592 lex_mode->as.list.nesting--;
11598 if (breakpoint > parser->current.start) {
11599 parser->current.end = breakpoint;
11600 pm_token_buffer_flush(parser, &token_buffer);
11601 LEX(PM_TOKEN_STRING_CONTENT);
11606 parser->current.end = breakpoint + 1;
11611 if (*breakpoint ==
'\n') {
11612 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11615 lex_mode_pop(parser);
11616 lex_state_set(parser, PM_LEX_STATE_END);
11617 LEX(PM_TOKEN_STRING_END);
11621 if (*breakpoint ==
'\0') {
11622 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1),
true);
11629 if (*breakpoint ==
'\\') {
11630 parser->current.end = breakpoint + 1;
11634 if (parser->current.end == parser->end) {
11639 pm_token_buffer_escape(parser, &token_buffer);
11640 uint8_t peeked = peek(parser);
11648 pm_token_buffer_push_byte(&token_buffer, peeked);
11649 parser->current.end++;
11652 parser->current.end++;
11653 if (peek(parser) !=
'\n') {
11654 pm_token_buffer_push_byte(&token_buffer,
'\r');
11659 pm_token_buffer_push_byte(&token_buffer,
'\n');
11661 if (parser->heredoc_end) {
11665 parser_flush_heredoc_end(parser);
11666 pm_token_buffer_copy(parser, &token_buffer);
11667 LEX(PM_TOKEN_STRING_CONTENT);
11670 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11673 parser->current.end++;
11676 if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
11677 pm_token_buffer_push_byte(&token_buffer, peeked);
11678 parser->current.end++;
11679 }
else if (lex_mode->as.list.interpolation) {
11680 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11682 pm_token_buffer_push_byte(&token_buffer,
'\\');
11683 pm_token_buffer_push_escaped(&token_buffer, parser);
11689 token_buffer.
cursor = parser->current.end;
11690 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11695 if (*breakpoint ==
'#') {
11696 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11703 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11707 if (
type == PM_TOKEN_STRING_CONTENT) {
11708 pm_token_buffer_flush(parser, &token_buffer);
11716 assert(*breakpoint == lex_mode->as.list.incrementor);
11717 parser->current.end = breakpoint + 1;
11718 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11719 lex_mode->as.list.nesting++;
11723 if (parser->current.end > parser->current.start) {
11724 pm_token_buffer_flush(parser, &token_buffer);
11725 LEX(PM_TOKEN_STRING_CONTENT);
11730 parser->current.end = parser->end;
11731 pm_token_buffer_flush(parser, &token_buffer);
11732 LEX(PM_TOKEN_STRING_CONTENT);
11734 case PM_LEX_REGEXP: {
11736 if (parser->next_start == NULL) {
11737 parser->current.start = parser->current.end;
11739 parser->current.start = parser->next_start;
11740 parser->current.end = parser->next_start;
11741 parser->next_start = NULL;
11746 if (parser->current.end >= parser->end) {
11756 const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
11757 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11760 while (breakpoint != NULL) {
11761 uint8_t term = lex_mode->as.regexp.terminator;
11762 bool is_terminator = (*breakpoint == term);
11767 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11768 if (term ==
'\n') {
11769 is_terminator =
true;
11775 if (term ==
'\r') {
11776 is_terminator =
false;
11782 if (is_terminator) {
11783 if (lex_mode->as.regexp.nesting > 0) {
11784 parser->current.end = breakpoint + 1;
11785 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11786 lex_mode->as.regexp.nesting--;
11793 if (breakpoint > parser->current.start) {
11794 parser->current.end = breakpoint;
11795 pm_regexp_token_buffer_flush(parser, &token_buffer);
11796 LEX(PM_TOKEN_STRING_CONTENT);
11800 size_t eol_length = match_eol_at(parser, breakpoint);
11802 parser->current.end = breakpoint + eol_length;
11807 if (parser->heredoc_end == NULL) {
11808 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11811 parser->current.end = breakpoint + 1;
11816 parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
11818 lex_mode_pop(parser);
11819 lex_state_set(parser, PM_LEX_STATE_END);
11820 LEX(PM_TOKEN_REGEXP_END);
11825 if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
11826 parser->current.end = breakpoint + 1;
11827 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11828 lex_mode->as.regexp.nesting++;
11832 switch (*breakpoint) {
11835 parser->current.end = breakpoint + 1;
11836 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11839 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11840 parser->current.end = breakpoint + 1;
11841 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11846 parser->current.end = breakpoint;
11847 pm_regexp_token_buffer_escape(parser, &token_buffer);
11854 if (parser->heredoc_end == NULL) {
11855 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
11856 parser->current.end = breakpoint + 1;
11857 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11861 parser->current.end = breakpoint + 1;
11862 parser_flush_heredoc_end(parser);
11863 pm_regexp_token_buffer_flush(parser, &token_buffer);
11864 LEX(PM_TOKEN_STRING_CONTENT);
11869 parser->current.end = breakpoint + 1;
11873 if (parser->current.end == parser->end) {
11878 pm_regexp_token_buffer_escape(parser, &token_buffer);
11879 uint8_t peeked = peek(parser);
11883 parser->current.end++;
11884 if (peek(parser) !=
'\n') {
11885 if (lex_mode->as.regexp.terminator !=
'\r') {
11886 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11888 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11889 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11894 if (parser->heredoc_end) {
11898 parser_flush_heredoc_end(parser);
11899 pm_regexp_token_buffer_copy(parser, &token_buffer);
11900 LEX(PM_TOKEN_STRING_CONTENT);
11903 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11906 parser->current.end++;
11916 if (lex_mode->as.regexp.terminator == peeked) {
11921 case '$':
case ')':
case '*':
case '+':
11922 case '.':
case '>':
case '?':
case ']':
11923 case '^':
case '|':
case '}':
11924 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11930 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11931 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11932 parser->current.end++;
11936 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11937 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11941 token_buffer.
base.
cursor = parser->current.end;
11942 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11948 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11955 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11959 if (
type == PM_TOKEN_STRING_CONTENT) {
11960 pm_regexp_token_buffer_flush(parser, &token_buffer);
11966 assert(
false &&
"unreachable");
11971 if (parser->current.end > parser->current.start) {
11972 pm_regexp_token_buffer_flush(parser, &token_buffer);
11973 LEX(PM_TOKEN_STRING_CONTENT);
11978 parser->current.end = parser->end;
11979 pm_regexp_token_buffer_flush(parser, &token_buffer);
11980 LEX(PM_TOKEN_STRING_CONTENT);
11982 case PM_LEX_STRING: {
11984 if (parser->next_start == NULL) {
11985 parser->current.start = parser->current.end;
11987 parser->current.start = parser->next_start;
11988 parser->current.end = parser->next_start;
11989 parser->next_start = NULL;
11994 if (parser->current.end >= parser->end) {
12001 const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
12002 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12008 while (breakpoint != NULL) {
12011 if (lex_mode->as.string.incrementor !=
'\0' && *breakpoint == lex_mode->as.string.incrementor) {
12012 lex_mode->as.string.nesting++;
12013 parser->current.end = breakpoint + 1;
12014 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12018 uint8_t term = lex_mode->as.string.terminator;
12019 bool is_terminator = (*breakpoint == term);
12024 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12025 if (term ==
'\n') {
12026 is_terminator =
true;
12032 if (term ==
'\r') {
12033 is_terminator =
false;
12040 if (is_terminator) {
12043 if (lex_mode->as.string.nesting > 0) {
12044 parser->current.end = breakpoint + 1;
12045 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12046 lex_mode->as.string.nesting--;
12052 if (breakpoint > parser->current.start) {
12053 parser->current.end = breakpoint;
12054 pm_token_buffer_flush(parser, &token_buffer);
12055 LEX(PM_TOKEN_STRING_CONTENT);
12060 size_t eol_length = match_eol_at(parser, breakpoint);
12062 parser->current.end = breakpoint + eol_length;
12067 if (parser->heredoc_end == NULL) {
12068 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
12071 parser->current.end = breakpoint + 1;
12074 if (lex_mode->as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12075 parser->current.end++;
12076 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12077 lex_mode_pop(parser);
12078 LEX(PM_TOKEN_LABEL_END);
12084 if (term ==
'\n' && parser->heredoc_end) {
12085 parser_flush_heredoc_end(parser);
12088 lex_state_set(parser, PM_LEX_STATE_END);
12089 lex_mode_pop(parser);
12090 LEX(PM_TOKEN_STRING_END);
12093 switch (*breakpoint) {
12096 parser->current.end = breakpoint + 1;
12097 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12100 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12101 parser->current.end = breakpoint + 1;
12102 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12109 parser->current.end = breakpoint;
12110 pm_token_buffer_escape(parser, &token_buffer);
12111 token_buffer.
cursor = breakpoint;
12119 if (parser->heredoc_end == NULL) {
12120 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12121 parser->current.end = breakpoint + 1;
12122 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12126 parser->current.end = breakpoint + 1;
12127 parser_flush_heredoc_end(parser);
12128 pm_token_buffer_flush(parser, &token_buffer);
12129 LEX(PM_TOKEN_STRING_CONTENT);
12132 parser->current.end = breakpoint + 1;
12136 if (parser->current.end == parser->end) {
12141 pm_token_buffer_escape(parser, &token_buffer);
12142 uint8_t peeked = peek(parser);
12146 pm_token_buffer_push_byte(&token_buffer,
'\\');
12147 parser->current.end++;
12150 parser->current.end++;
12151 if (peek(parser) !=
'\n') {
12152 if (!lex_mode->as.string.interpolation) {
12153 pm_token_buffer_push_byte(&token_buffer,
'\\');
12155 pm_token_buffer_push_byte(&token_buffer,
'\r');
12160 if (!lex_mode->as.string.interpolation) {
12161 pm_token_buffer_push_byte(&token_buffer,
'\\');
12162 pm_token_buffer_push_byte(&token_buffer,
'\n');
12165 if (parser->heredoc_end) {
12169 parser_flush_heredoc_end(parser);
12170 pm_token_buffer_copy(parser, &token_buffer);
12171 LEX(PM_TOKEN_STRING_CONTENT);
12174 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
12177 parser->current.end++;
12180 if (lex_mode->as.string.incrementor !=
'\0' && peeked == lex_mode->as.string.incrementor) {
12181 pm_token_buffer_push_byte(&token_buffer, peeked);
12182 parser->current.end++;
12183 }
else if (lex_mode->as.string.terminator !=
'\0' && peeked == lex_mode->as.string.terminator) {
12184 pm_token_buffer_push_byte(&token_buffer, peeked);
12185 parser->current.end++;
12186 }
else if (lex_mode->as.string.interpolation) {
12187 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12189 pm_token_buffer_push_byte(&token_buffer,
'\\');
12190 pm_token_buffer_push_escaped(&token_buffer, parser);
12196 token_buffer.
cursor = parser->current.end;
12197 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12201 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12208 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12212 if (
type == PM_TOKEN_STRING_CONTENT) {
12213 pm_token_buffer_flush(parser, &token_buffer);
12219 assert(
false &&
"unreachable");
12223 if (parser->current.end > parser->current.start) {
12224 pm_token_buffer_flush(parser, &token_buffer);
12225 LEX(PM_TOKEN_STRING_CONTENT);
12230 parser->current.end = parser->end;
12231 pm_token_buffer_flush(parser, &token_buffer);
12232 LEX(PM_TOKEN_STRING_CONTENT);
12234 case PM_LEX_HEREDOC: {
12236 if (parser->next_start == NULL) {
12237 parser->current.start = parser->current.end;
12239 parser->current.start = parser->next_start;
12240 parser->current.end = parser->next_start;
12241 parser->heredoc_end = NULL;
12242 parser->next_start = NULL;
12250 bool line_continuation = lex_mode->as.heredoc.line_continuation;
12251 lex_mode->as.heredoc.line_continuation =
false;
12257 if (parser->current.end >= parser->end) {
12258 pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
12259 parser->next_start = lex_mode->as.heredoc.next_start;
12260 parser->heredoc_end = parser->current.end;
12261 lex_state_set(parser, PM_LEX_STATE_END);
12262 lex_mode_pop(parser);
12263 LEX(PM_TOKEN_HEREDOC_END);
12266 const uint8_t *ident_start = heredoc_lex_mode->ident_start;
12267 size_t ident_length = heredoc_lex_mode->ident_length;
12271 if (current_token_starts_line(parser)) {
12272 const uint8_t *start = parser->current.start;
12274 if (!line_continuation && (start + ident_length <= parser->end)) {
12275 const uint8_t *newline = next_newline(start, parser->end - start);
12276 const uint8_t *ident_end = newline;
12277 const uint8_t *terminator_end = newline;
12279 if (newline == NULL) {
12280 terminator_end = parser->end;
12281 ident_end = parser->end;
12284 if (newline[-1] ==
'\r') {
12289 const uint8_t *terminator_start = ident_end - ident_length;
12290 const uint8_t *cursor = start;
12292 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12293 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12299 (cursor == terminator_start) &&
12300 (memcmp(terminator_start, ident_start, ident_length) == 0)
12302 if (newline != NULL) {
12303 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
12306 parser->current.end = terminator_end;
12307 if (*lex_mode->as.heredoc.next_start ==
'\\') {
12308 parser->next_start = NULL;
12310 parser->next_start = lex_mode->as.heredoc.next_start;
12311 parser->heredoc_end = parser->current.end;
12314 lex_state_set(parser, PM_LEX_STATE_END);
12315 lex_mode_pop(parser);
12316 LEX(PM_TOKEN_HEREDOC_END);
12320 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
12322 heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
12323 lex_mode->as.heredoc.common_whitespace != NULL &&
12324 (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
12325 peek_at(parser, start) !=
'\n'
12327 *lex_mode->as.heredoc.common_whitespace = whitespace;
12334 uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] =
"\r\n\\#";
12336 pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
12337 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12338 breakpoints[3] =
'\0';
12341 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12343 bool was_line_continuation =
false;
12345 while (breakpoint != NULL) {
12346 switch (*breakpoint) {
12349 parser->current.end = breakpoint + 1;
12350 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12353 parser->current.end = breakpoint + 1;
12355 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12356 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12363 pm_token_buffer_escape(parser, &token_buffer);
12364 token_buffer.
cursor = breakpoint;
12368 if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
12369 parser_flush_heredoc_end(parser);
12370 parser->current.end = breakpoint + 1;
12371 pm_token_buffer_flush(parser, &token_buffer);
12372 LEX(PM_TOKEN_STRING_CONTENT);
12375 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12379 const uint8_t *start = breakpoint + 1;
12381 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12384 const uint8_t *newline = next_newline(start, parser->end - start);
12386 if (newline == NULL) {
12387 newline = parser->end;
12388 }
else if (newline[-1] ==
'\r') {
12393 const uint8_t *terminator_start = newline - ident_length;
12397 const uint8_t *cursor = start;
12399 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12400 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12406 cursor == terminator_start &&
12407 (memcmp(terminator_start, ident_start, ident_length) == 0)
12409 parser->current.end = breakpoint + 1;
12410 pm_token_buffer_flush(parser, &token_buffer);
12411 LEX(PM_TOKEN_STRING_CONTENT);
12415 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
12422 if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12423 if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12424 *lex_mode->as.heredoc.common_whitespace = whitespace;
12427 parser->current.end = breakpoint + 1;
12428 pm_token_buffer_flush(parser, &token_buffer);
12429 LEX(PM_TOKEN_STRING_CONTENT);
12434 parser->current.end = breakpoint + 1;
12435 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12445 parser->current.end = breakpoint + 1;
12449 if (parser->current.end == parser->end) {
12454 pm_token_buffer_escape(parser, &token_buffer);
12455 uint8_t peeked = peek(parser);
12457 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12460 parser->current.end++;
12461 if (peek(parser) !=
'\n') {
12462 pm_token_buffer_push_byte(&token_buffer,
'\\');
12463 pm_token_buffer_push_byte(&token_buffer,
'\r');
12468 pm_token_buffer_push_byte(&token_buffer,
'\\');
12469 pm_token_buffer_push_byte(&token_buffer,
'\n');
12470 token_buffer.
cursor = parser->current.end + 1;
12471 breakpoint = parser->current.end;
12474 pm_token_buffer_push_byte(&token_buffer,
'\\');
12475 pm_token_buffer_push_escaped(&token_buffer, parser);
12481 parser->current.end++;
12482 if (peek(parser) !=
'\n') {
12483 pm_token_buffer_push_byte(&token_buffer,
'\r');
12491 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12492 const uint8_t *end = parser->current.end;
12494 if (parser->heredoc_end == NULL) {
12495 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
12500 parser->current.end = breakpoint;
12501 pm_token_buffer_flush(parser, &token_buffer);
12505 parser->current.end = end + 1;
12506 lex_mode->as.heredoc.line_continuation =
true;
12507 LEX(PM_TOKEN_STRING_CONTENT);
12510 was_line_continuation =
true;
12511 token_buffer.
cursor = parser->current.end + 1;
12512 breakpoint = parser->current.end;
12515 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12520 token_buffer.
cursor = parser->current.end;
12521 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12525 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12533 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12537 if (
type == PM_TOKEN_STRING_CONTENT) {
12538 pm_token_buffer_flush(parser, &token_buffer);
12544 assert(
false &&
"unreachable");
12547 was_line_continuation =
false;
12550 if (parser->current.end > parser->current.start) {
12551 parser->current.end = parser->end;
12552 pm_token_buffer_flush(parser, &token_buffer);
12553 LEX(PM_TOKEN_STRING_CONTENT);
12558 parser->current.end = parser->end;
12559 pm_token_buffer_flush(parser, &token_buffer);
12560 LEX(PM_TOKEN_STRING_CONTENT);
12564 assert(
false &&
"unreachable");
12582 PM_BINDING_POWER_UNSET = 0,
12583 PM_BINDING_POWER_STATEMENT = 2,
12584 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12585 PM_BINDING_POWER_MODIFIER = 6,
12586 PM_BINDING_POWER_COMPOSITION = 8,
12587 PM_BINDING_POWER_NOT = 10,
12588 PM_BINDING_POWER_MATCH = 12,
12589 PM_BINDING_POWER_DEFINED = 14,
12590 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12591 PM_BINDING_POWER_ASSIGNMENT = 18,
12592 PM_BINDING_POWER_TERNARY = 20,
12593 PM_BINDING_POWER_RANGE = 22,
12594 PM_BINDING_POWER_LOGICAL_OR = 24,
12595 PM_BINDING_POWER_LOGICAL_AND = 26,
12596 PM_BINDING_POWER_EQUALITY = 28,
12597 PM_BINDING_POWER_COMPARISON = 30,
12598 PM_BINDING_POWER_BITWISE_OR = 32,
12599 PM_BINDING_POWER_BITWISE_AND = 34,
12600 PM_BINDING_POWER_SHIFT = 36,
12601 PM_BINDING_POWER_TERM = 38,
12602 PM_BINDING_POWER_FACTOR = 40,
12603 PM_BINDING_POWER_UMINUS = 42,
12604 PM_BINDING_POWER_EXPONENT = 44,
12605 PM_BINDING_POWER_UNARY = 46,
12606 PM_BINDING_POWER_INDEX = 48,
12607 PM_BINDING_POWER_CALL = 50,
12608 PM_BINDING_POWER_MAX = 52
12609} pm_binding_power_t;
12632#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12633#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12634#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12635#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12636#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12640 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12643 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12644 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12645 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12646 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12649 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12650 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12653 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12654 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12657 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12658 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12659 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12660 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12661 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12662 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12663 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12664 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12665 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12666 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12667 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12668 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12669 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12670 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12673 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12676 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12677 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12678 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12679 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12682 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12685 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12688 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12689 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12690 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12691 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12692 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12693 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12696 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12697 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12698 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12699 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12702 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12703 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12706 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12709 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12710 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12713 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12714 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12717 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12718 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12719 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12720 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12723 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12724 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12727 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12728 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12731 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12732 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12733 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12736 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12739 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12740 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12741 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12744#undef BINDING_POWER_ASSIGNMENT
12745#undef LEFT_ASSOCIATIVE
12746#undef RIGHT_ASSOCIATIVE
12747#undef RIGHT_ASSOCIATIVE_UNARY
12754 return parser->current.type ==
type;
12761match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12762 return match1(parser, type1) || match1(parser, type2);
12769match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12770 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12777match4(
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) {
12778 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12785match5(
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) {
12786 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5);
12793match6(
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) {
12794 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
12801match8(
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) {
12802 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);
12813 if (match1(parser,
type)) {
12814 parser_lex(parser);
12825accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12826 if (match2(parser, type1, type2)) {
12827 parser_lex(parser);
12845expect1(
pm_parser_t *parser, pm_token_type_t
type, pm_diagnostic_id_t diag_id) {
12846 if (accept1(parser,
type))
return;
12848 const uint8_t *location = parser->previous.
end;
12849 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12851 parser->previous.
start = location;
12852 parser->previous.
type = 0;
12860expect2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
12861 if (accept2(parser, type1, type2))
return;
12863 const uint8_t *location = parser->previous.
end;
12864 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12866 parser->previous.
start = location;
12867 parser->previous.
type = 0;
12875expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12876 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12877 parser_lex(parser);
12879 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12880 parser->previous.
start = parser->previous.
end;
12881 parser->previous.
type = 0;
12893 if (accept1(parser,
type))
return;
12895 const uint8_t *start = opening->
start;
12896 pm_parser_err(parser, U32(start - parser->start), U32(opening->
end - start), diag_id);
12898 parser->previous.
start = parser->previous.
end;
12899 parser->previous.
type = 0;
12903#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
12904#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
12905#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
12906#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
12917#define PM_PARSE_ACCEPTS_STATEMENT ((uint8_t) 0x10)
12920parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
12927parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
12928 pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
12929 pm_assert_value_expression(parser, node);
12952token_begins_expression_p(pm_token_type_t
type) {
12954 case PM_TOKEN_EQUAL_GREATER:
12955 case PM_TOKEN_KEYWORD_IN:
12959 case PM_TOKEN_BRACE_RIGHT:
12960 case PM_TOKEN_BRACKET_RIGHT:
12961 case PM_TOKEN_COLON:
12962 case PM_TOKEN_COMMA:
12963 case PM_TOKEN_EMBEXPR_END:
12965 case PM_TOKEN_LAMBDA_BEGIN:
12966 case PM_TOKEN_KEYWORD_DO:
12967 case PM_TOKEN_KEYWORD_DO_BLOCK:
12968 case PM_TOKEN_KEYWORD_DO_LAMBDA:
12969 case PM_TOKEN_KEYWORD_DO_LOOP:
12970 case PM_TOKEN_KEYWORD_END:
12971 case PM_TOKEN_KEYWORD_ELSE:
12972 case PM_TOKEN_KEYWORD_ELSIF:
12973 case PM_TOKEN_KEYWORD_ENSURE:
12974 case PM_TOKEN_KEYWORD_THEN:
12975 case PM_TOKEN_KEYWORD_RESCUE:
12976 case PM_TOKEN_KEYWORD_WHEN:
12977 case PM_TOKEN_NEWLINE:
12978 case PM_TOKEN_PARENTHESIS_RIGHT:
12979 case PM_TOKEN_SEMICOLON:
12985 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12987 case PM_TOKEN_UAMPERSAND:
12991 case PM_TOKEN_UCOLON_COLON:
12992 case PM_TOKEN_UMINUS:
12993 case PM_TOKEN_UMINUS_NUM:
12994 case PM_TOKEN_UPLUS:
12995 case PM_TOKEN_BANG:
12996 case PM_TOKEN_TILDE:
12997 case PM_TOKEN_UDOT_DOT:
12998 case PM_TOKEN_UDOT_DOT_DOT:
13005 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13025token_begins_pattern_p(pm_token_type_t
type) {
13027 token_begins_expression_p(
type) ||
13028 type == PM_TOKEN_USTAR ||
13029 type == PM_TOKEN_USTAR_STAR ||
13030 type == PM_TOKEN_CARET
13039parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
13040 if (accept1(parser, PM_TOKEN_USTAR)) {
13042 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));
13043 return UP(pm_splat_node_create(parser, &
operator, expression));
13046 return parse_value_expression(parser, binding_power, flags, diag_id, depth);
13050pm_node_unreference_each(
const pm_node_t *node,
void *data) {
13051 switch (PM_NODE_TYPE(node)) {
13056 case PM_BREAK_NODE:
13058 case PM_REDO_NODE: {
13062 while (index < parser->current_block_exits->size) {
13063 pm_node_t *block_exit = parser->current_block_exits->
nodes[index];
13065 if (block_exit == node) {
13066 if (index + 1 < parser->current_block_exits->
size) {
13068 &parser->current_block_exits->
nodes[index],
13069 &parser->current_block_exits->
nodes[index + 1],
13070 (parser->current_block_exits->
size - index - 1) *
sizeof(
pm_node_t *)
13073 parser->current_block_exits->
size--;
13088 case PM_LOCAL_VARIABLE_READ_NODE:
13089 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13091 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
13093 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13094 if (implicit_parameters->
nodes[index] == node) {
13098 if (index != implicit_parameters->
size - 1) {
13099 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13102 implicit_parameters->
size--;
13121 pm_visit_node(node, pm_node_unreference_each, parser);
13134 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *name_field);
13135 size_t length = constant->length;
13136 uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
13138 memcpy(name, constant->start, length);
13139 name[length] =
'=';
13141 *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
13152 switch (PM_NODE_TYPE(target)) {
13153 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13154 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13155 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13156 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13157 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13158 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13159 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13163 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
13179 switch (PM_NODE_TYPE(target)) {
13180 case PM_ERROR_RECOVERY_NODE:
13182 case PM_SOURCE_ENCODING_NODE:
13183 case PM_FALSE_NODE:
13184 case PM_SOURCE_FILE_NODE:
13185 case PM_SOURCE_LINE_NODE:
13188 case PM_TRUE_NODE: {
13191 return parse_unwriteable_target(parser, target);
13193 case PM_CLASS_VARIABLE_READ_NODE:
13195 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13197 case PM_CONSTANT_PATH_NODE:
13198 if (context_def_p(parser)) {
13199 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13203 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13206 case PM_CONSTANT_READ_NODE:
13207 if (context_def_p(parser)) {
13208 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13212 target->
type = PM_CONSTANT_TARGET_NODE;
13215 case PM_BACK_REFERENCE_READ_NODE:
13216 case PM_NUMBERED_REFERENCE_READ_NODE:
13217 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13218 return UP(pm_error_recovery_node_create_unexpected(parser, target));
13219 case PM_GLOBAL_VARIABLE_READ_NODE:
13221 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13223 case PM_LOCAL_VARIABLE_READ_NODE: {
13224 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13225 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
13226 pm_node_unreference(parser, target);
13230 uint32_t name = cast->
name;
13231 uint32_t depth = cast->
depth;
13232 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13235 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13239 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13241 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
13243 pm_node_unreference(parser, target);
13247 case PM_INSTANCE_VARIABLE_READ_NODE:
13249 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13251 case PM_MULTI_TARGET_NODE:
13252 if (splat_parent) {
13255 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13259 case PM_SPLAT_NODE: {
13268 case PM_CALL_NODE: {
13280 (call->
block == NULL)
13293 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
13295 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
13299 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13300 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13303 parse_write_name(parser, &call->
name);
13304 return UP(pm_call_target_node_create(parser, call));
13311 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13312 return UP(pm_index_target_node_create(parser, call));
13320 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13331 pm_node_t *result = parse_target(parser, target, multiple,
false);
13336 !match1(parser, PM_TOKEN_EQUAL) &&
13337 !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
13338 !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13340 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13352 pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
13354 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13355 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
13366 switch (PM_NODE_TYPE(target)) {
13367 case PM_ERROR_RECOVERY_NODE:
13369 case PM_CLASS_VARIABLE_READ_NODE: {
13373 case PM_CONSTANT_PATH_NODE: {
13376 if (context_def_p(parser)) {
13377 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13380 return parse_shareable_constant_write(parser, node);
13382 case PM_CONSTANT_READ_NODE: {
13385 if (context_def_p(parser)) {
13386 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13389 return parse_shareable_constant_write(parser, node);
13391 case PM_BACK_REFERENCE_READ_NODE:
13392 case PM_NUMBERED_REFERENCE_READ_NODE:
13393 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13395 case PM_GLOBAL_VARIABLE_READ_NODE: {
13399 case PM_LOCAL_VARIABLE_READ_NODE: {
13404 uint32_t depth = local_read->
depth;
13405 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13407 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13408 pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13409 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
13410 pm_node_unreference(parser, target);
13413 pm_locals_unread(&scope->locals, name);
13415 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
13417 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13419 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
13421 pm_node_unreference(parser, target);
13425 case PM_INSTANCE_VARIABLE_READ_NODE: {
13429 case PM_MULTI_TARGET_NODE:
13431 case PM_SPLAT_NODE: {
13439 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
13441 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
13443 case PM_CALL_NODE: {
13455 (call->
block == NULL)
13469 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
13470 pm_parser_local_add_location(parser, &message_loc, 0);
13472 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));
13473 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
13492 pm_arguments_node_arguments_append(parser->arena, arguments, value);
13493 PM_NODE_LENGTH_SET_NODE(call, arguments);
13494 call->
equal_loc = TOK2LOC(parser,
operator);
13496 parse_write_name(parser, &call->
name);
13497 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13506 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13508 call->
arguments = pm_arguments_node_create(parser);
13511 pm_arguments_node_arguments_append(parser->arena, call->
arguments, value);
13512 PM_NODE_LENGTH_SET_NODE(target, value);
13515 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13516 call->
equal_loc = TOK2LOC(parser,
operator);
13520 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13535 pm_node_unreference(parser, value);
13542 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13555 switch (PM_NODE_TYPE(target)) {
13556 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13557 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13558 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13559 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13560 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13561 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13562 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13583parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13584 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13587 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13589 while (accept1(parser, PM_TOKEN_COMMA)) {
13590 if (accept1(parser, PM_TOKEN_USTAR)) {
13595 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13598 pm_token_t star_operator = parser->previous;
13601 if (token_begins_expression_p(parser->current.type)) {
13602 name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13603 name = parse_target(parser, name,
true,
true);
13606 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13607 pm_multi_target_node_targets_append(parser, result, splat);
13609 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
13610 context_push(parser, PM_CONTEXT_MULTI_TARGET);
13611 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13612 target = parse_target(parser, target,
true,
false);
13614 pm_multi_target_node_targets_append(parser, result, target);
13615 context_pop(parser);
13616 }
else if (token_begins_expression_p(parser->current.type)) {
13617 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13618 target = parse_target(parser, target,
true,
false);
13620 pm_multi_target_node_targets_append(parser, result, target);
13621 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13624 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
13625 pm_multi_target_node_targets_append(parser, result, rest);
13638parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13639 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13644 if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
13645 accept1(parser, PM_TOKEN_NEWLINE);
13649 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13650 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13660parse_statements(
pm_parser_t *parser, pm_context_t context, uint16_t depth) {
13663 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13666 if (context_terminator(context, &parser->current))
return NULL;
13672 context_push(parser, context);
13675 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));
13676 pm_statements_node_body_append(parser, statements, node,
true);
13680 if (parser->recovering) {
13683 if (context_terminator(context, &parser->current)) parser->recovering =
false;
13689 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13692 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13693 if (context_terminator(context, &parser->current))
break;
13703 if (context_terminator(context, &parser->current))
break;
13715 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
13716 parser_lex(parser);
13722 if (match1(parser, PM_TOKEN_EOF)) {
13723 parser->recovering =
true;
13727 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13728 if (context_terminator(context, &parser->current))
break;
13729 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13733 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
13734 parser->previous.
start = parser->previous.
end;
13735 parser->previous.
type = 0;
13739 context_pop(parser);
13741 bool last_value =
true;
13743 case PM_CONTEXT_BEGIN_ENSURE:
13744 case PM_CONTEXT_DEF_ENSURE:
13745 last_value =
false;
13750 pm_void_statements_check(parser, statements, last_value);
13761 pm_static_literal_inspect(&buffer, &parser->line_offsets, parser->start, parser->start_line, parser->encoding, duplicated);
13763 pm_diagnostic_list_append_format(
13764 &parser->metadata_arena,
13765 &parser->warning_list,
13768 PM_WARN_DUPLICATED_HASH_KEY,
13769 (
int) pm_buffer_length(&buffer),
13770 pm_buffer_value(&buffer),
13771 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line
13774 pm_buffer_cleanup(&buffer);
13783 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
true);
13785 if (duplicated != NULL) {
13786 pm_hash_key_duplicated_warn(parser, duplicated, node);
13801 for (
size_t index = 0; index < elements->
size; index++) {
13804 switch (PM_NODE_TYPE(element)) {
13805 case PM_ASSOC_NODE: {
13807 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, key,
true);
13809 if (duplicated != NULL && PM_NODE_START(duplicated) < boundary) {
13810 pm_hash_key_duplicated_warn(parser, duplicated, key);
13815 case PM_ASSOC_SPLAT_NODE: {
13818 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13819 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, boundary);
13838 if ((previous = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
false)) != NULL) {
13839 pm_diagnostic_list_append_format(
13840 &parser->metadata_arena,
13841 &parser->warning_list,
13842 PM_NODE_START(node),
13843 PM_NODE_LENGTH(node),
13844 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13845 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line,
13846 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).
line
13856 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13857 bool contains_keyword_splat =
false;
13862 switch (parser->current.type) {
13863 case PM_TOKEN_USTAR_STAR: {
13864 parser_lex(parser);
13868 if (token_begins_expression_p(parser->current.type)) {
13869 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));
13873 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13874 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, PM_NODE_START(value));
13877 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13880 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13881 contains_keyword_splat =
true;
13884 case PM_TOKEN_LABEL: {
13886 parser_lex(parser);
13888 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13889 pm_hash_key_static_literals_add(parser, literals, key);
13893 if (token_begins_expression_p(parser->current.type)) {
13894 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13896 if (parser->encoding->isupper_char(label.
start, (label.
end - 1) - label.
start)) {
13897 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13898 value = UP(pm_constant_read_node_create(parser, &constant));
13903 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13904 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13906 depth = pm_parser_local_depth(parser, &identifier);
13910 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13912 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13917 value = UP(pm_implicit_node_create(parser, value));
13920 element = UP(pm_assoc_node_create(parser, key, NULL, value));
13924 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));
13928 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13929 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13932 pm_hash_key_static_literals_add(parser, literals, key);
13935 if (!pm_symbol_node_label_p(parser, key)) {
13936 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13937 operator = parser->previous;
13940 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));
13941 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
13946 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13947 pm_hash_node_elements_append(parser->arena, (
pm_hash_node_t *) node, element);
13953 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13957 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13961 if (token_begins_expression_p(parser->current.type))
continue;
13967 return contains_keyword_splat;
13972 if (pm_symbol_node_label_p(parser, argument)) {
13976 switch (PM_NODE_TYPE(argument)) {
13977 case PM_CALL_NODE: {
13980 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13983 if (cast->
block != NULL) {
13991 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
14000 arguments->
arguments = pm_arguments_node_create(parser);
14003 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, argument);
14014 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
14033 call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE) &&
14048 switch (PM_NODE_TYPE(node)) {
14049 case PM_CALL_NODE: {
14054 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)) {
14059 if (pm_constant_path_command_call_p(parser, call)) {
14066 return pm_command_call_value_p(parser, call->
receiver);
14071 case PM_SUPER_NODE: {
14078 !(cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE));
14080 case PM_YIELD_NODE: {
14084 case PM_RESCUE_MODIFIER_NODE:
14086 case PM_DEF_NODE: {
14090 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
14093 return pm_command_call_value_p(parser, body);
14109pm_block_call_p(
const pm_node_t *node) {
14110 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
14141 if (PM_NODE_TYPE_P(node, PM_SUPER_NODE)) {
14153parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
14154 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
14159 match2(parser, terminator, PM_TOKEN_EOF) ||
14160 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14161 context_terminator(parser->current_context->context, &parser->current)
14166 bool parsed_first_argument =
false;
14167 bool parsed_bare_hash =
false;
14168 bool parsed_block_argument =
false;
14169 bool parsed_forwarding_arguments =
false;
14171 while (!match1(parser, PM_TOKEN_EOF)) {
14172 if (parsed_forwarding_arguments) {
14173 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14178 switch (parser->current.type) {
14179 case PM_TOKEN_USTAR_STAR:
14180 case PM_TOKEN_LABEL: {
14181 if (parsed_bare_hash) {
14182 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14186 argument = UP(hash);
14189 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
14191 parse_arguments_append(parser, arguments, argument);
14193 pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14194 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14195 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14197 pm_static_literals_free(&hash_keys);
14198 parsed_bare_hash =
true;
14202 case PM_TOKEN_UAMPERSAND: {
14203 parser_lex(parser);
14207 if (token_begins_expression_p(parser->current.type)) {
14208 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14210 pm_parser_scope_forwarding_block_check(parser, &
operator);
14213 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
14214 if (parsed_block_argument) {
14215 parse_arguments_append(parser, arguments, argument);
14217 arguments->
block = argument;
14220 if (match1(parser, PM_TOKEN_COMMA)) {
14221 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14224 parsed_block_argument =
true;
14227 case PM_TOKEN_USTAR: {
14228 parser_lex(parser);
14231 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14232 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14233 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
14234 if (parsed_bare_hash) {
14235 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14238 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));
14240 if (parsed_bare_hash) {
14241 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);
14244 argument = UP(pm_splat_node_create(parser, &
operator, expression));
14247 parse_arguments_append(parser, arguments, argument);
14250 case PM_TOKEN_UDOT_DOT_DOT: {
14251 if (accepts_forwarding) {
14252 parser_lex(parser);
14254 if (token_begins_expression_p(parser->current.type)) {
14259 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));
14264 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14266 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14269 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
14271 pm_parser_scope_forwarding_all_check(parser, &parser->previous);
14272 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14273 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14276 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->previous));
14277 parse_arguments_append(parser, arguments, argument);
14278 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14280 parsed_forwarding_arguments =
true;
14287 if (argument == NULL) {
14288 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));
14291 bool contains_keywords =
false;
14292 bool contains_keyword_splat =
false;
14294 if (argument_allowed_for_bare_hash(parser, argument)) {
14295 if (parsed_bare_hash) {
14296 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14305 if (pm_command_call_value_p(parser, argument) || pm_block_call_p(argument)) {
14306 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->previous.
type));
14310 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
14311 operator = parser->previous;
14315 contains_keywords =
true;
14319 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14322 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));
14323 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
14325 pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
14326 argument = UP(bare_hash);
14329 if (accept1(parser, PM_TOKEN_COMMA) && (
14330 token_begins_expression_p(parser->current.type) ||
14331 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14333 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
14336 pm_static_literals_free(&hash_keys);
14337 parsed_bare_hash =
true;
14340 parse_arguments_append(parser, arguments, argument);
14342 pm_node_flags_t node_flags = 0;
14343 if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14344 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14345 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14351 parsed_first_argument =
true;
14354 if (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_NODE) || parser->recovering)
break;
14359 bool accepted_newline =
false;
14360 if (terminator != PM_TOKEN_EOF) {
14361 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14364 if (parser->previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14368 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14371 if (accepted_newline) {
14372 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14378 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
14381 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14393 if (match1(parser, terminator)) {
14399 if (parsed_forwarding_arguments) {
14400 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14419parse_required_destructured_parameter(
pm_parser_t *parser) {
14420 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14423 pm_multi_target_node_opening_set(parser, node, &parser->previous);
14432 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14433 param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14434 pm_multi_target_node_targets_append(parser, node, param);
14435 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14439 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
14440 param = UP(parse_required_destructured_parameter(parser));
14441 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14445 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14447 value = UP(pm_required_parameter_node_create(parser, &name));
14448 if (pm_parser_parameter_name_check(parser, &name)) {
14449 pm_node_flag_set_repeated_parameter(value);
14451 pm_parser_local_add_token(parser, &name, 1);
14454 param = UP(pm_splat_node_create(parser, &star, value));
14456 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14459 param = UP(pm_required_parameter_node_create(parser, &name));
14460 if (pm_parser_parameter_name_check(parser, &name)) {
14461 pm_node_flag_set_repeated_parameter(param);
14463 pm_parser_local_add_token(parser, &name, 1);
14466 pm_multi_target_node_targets_append(parser, node, param);
14467 }
while (accept1(parser, PM_TOKEN_COMMA));
14469 accept1(parser, PM_TOKEN_NEWLINE);
14470 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14471 pm_multi_target_node_closing_set(parser, node, &parser->previous);
14481 PM_PARAMETERS_NO_CHANGE = 0,
14482 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14483 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14484 PM_PARAMETERS_ORDER_KEYWORDS,
14485 PM_PARAMETERS_ORDER_REST,
14486 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14487 PM_PARAMETERS_ORDER_OPTIONAL,
14488 PM_PARAMETERS_ORDER_NAMED,
14489 PM_PARAMETERS_ORDER_NONE,
14490} pm_parameters_order_t;
14495static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14496 [0] = PM_PARAMETERS_NO_CHANGE,
14497 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14498 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14499 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14500 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14501 [PM_TOKEN_PARENTHESIS_LEFT_GROUPING] = PM_PARAMETERS_ORDER_NAMED,
14502 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14503 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14504 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14505 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14506 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14507 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14519 pm_parameters_order_t state = parameters_ordering[token->type];
14520 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14524 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14525 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14527 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14531 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14532 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14534 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14535 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14537 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14539 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14543 if (state < *current) *current = state;
14548parse_parameters_handle_trailing_comma(
14551 pm_parameters_order_t order,
14553 bool allows_trailing_comma
14555 if (!allows_trailing_comma) {
14556 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14561 if (order >= PM_PARAMETERS_ORDER_NAMED) {
14563 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14565 if (params->
rest == NULL) {
14566 pm_parameters_node_rest_set(params, param);
14568 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14569 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14573 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14578 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
14579 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14590 pm_binding_power_t binding_power,
14591 bool uses_parentheses,
14592 bool allows_trailing_comma,
14593 bool allows_forwarding_parameters,
14594 bool accepts_blocks_in_defaults,
14596 pm_diagnostic_id_t diag_id_forwarding,
14599 pm_do_loop_stack_push(parser,
false);
14602 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14605 bool parsing =
true;
14607 switch (parser->current.type) {
14608 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
14609 update_parameter_state(parser, &parser->current, &order);
14610 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
14612 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14613 pm_parameters_node_requireds_append(parser->arena, params, param);
14615 pm_parameters_node_posts_append(parser->arena, params, param);
14619 case PM_TOKEN_UAMPERSAND:
14620 case PM_TOKEN_AMPERSAND: {
14621 update_parameter_state(parser, &parser->current, &order);
14622 parser_lex(parser);
14627 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14628 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->previous);
14632 bool repeated =
false;
14633 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14634 name = parser->previous;
14635 repeated = pm_parser_parameter_name_check(parser, &name);
14636 pm_parser_local_add_token(parser, &name, 1);
14638 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
14641 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
14643 pm_node_flag_set_repeated_parameter(param);
14647 if (params->
block == NULL) {
14648 pm_parameters_node_block_set(params, param);
14650 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
14651 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14656 case PM_TOKEN_UDOT_DOT_DOT: {
14657 if (!allows_forwarding_parameters) {
14658 pm_parser_err_current(parser, diag_id_forwarding);
14661 bool succeeded = update_parameter_state(parser, &parser->current, &order);
14662 parser_lex(parser);
14664 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
14671 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, keyword_rest)));
14672 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14676 pm_parameters_node_keyword_rest_set(params, UP(param));
14679 case PM_TOKEN_CLASS_VARIABLE:
14680 case PM_TOKEN_IDENTIFIER:
14681 case PM_TOKEN_CONSTANT:
14682 case PM_TOKEN_INSTANCE_VARIABLE:
14683 case PM_TOKEN_GLOBAL_VARIABLE:
14684 case PM_TOKEN_METHOD_NAME: {
14685 parser_lex(parser);
14686 switch (parser->previous.
type) {
14687 case PM_TOKEN_CONSTANT:
14688 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14690 case PM_TOKEN_INSTANCE_VARIABLE:
14691 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14693 case PM_TOKEN_GLOBAL_VARIABLE:
14694 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14696 case PM_TOKEN_CLASS_VARIABLE:
14697 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14699 case PM_TOKEN_METHOD_NAME:
14700 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14705 if (parser->current.type == PM_TOKEN_EQUAL) {
14706 update_parameter_state(parser, &parser->current, &order);
14708 update_parameter_state(parser, &parser->previous, &order);
14712 bool repeated = pm_parser_parameter_name_check(parser, &name);
14713 pm_parser_local_add_token(parser, &name, 1);
14715 if (match1(parser, PM_TOKEN_EQUAL)) {
14717 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14718 parser_lex(parser);
14721 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14723 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14724 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14725 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14730 pm_node_flag_set_repeated_parameter(UP(param));
14732 pm_parameters_node_optionals_append(parser->arena, params, param);
14737 if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14738 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
14741 context_pop(parser);
14746 if (parser->recovering) {
14750 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14753 pm_node_flag_set_repeated_parameter(UP(param));
14755 pm_parameters_node_requireds_append(parser->arena, params, UP(param));
14759 pm_node_flag_set_repeated_parameter(UP(param));
14761 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14766 case PM_TOKEN_LABEL: {
14767 if (!uses_parentheses && !in_block) parser->in_keyword_arg =
true;
14768 update_parameter_state(parser, &parser->current, &order);
14770 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14771 parser_lex(parser);
14777 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)) {
14778 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14779 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14780 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14783 bool repeated = pm_parser_parameter_name_check(parser, &local);
14784 pm_parser_local_add_token(parser, &local, 1);
14786 switch (parser->current.type) {
14787 case PM_TOKEN_COMMA:
14788 case PM_TOKEN_PARENTHESIS_RIGHT:
14789 case PM_TOKEN_PIPE: {
14790 context_pop(parser);
14792 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14794 pm_node_flag_set_repeated_parameter(param);
14797 pm_parameters_node_keywords_append(parser->arena, params, param);
14800 case PM_TOKEN_SEMICOLON:
14801 case PM_TOKEN_NEWLINE: {
14802 context_pop(parser);
14804 if (uses_parentheses) {
14809 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14811 pm_node_flag_set_repeated_parameter(param);
14814 pm_parameters_node_keywords_append(parser->arena, params, param);
14820 if (token_begins_expression_p(parser->current.type)) {
14822 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14824 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14825 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));
14826 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14828 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14829 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
14832 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14835 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14839 pm_node_flag_set_repeated_parameter(param);
14842 context_pop(parser);
14843 pm_parameters_node_keywords_append(parser->arena, params, param);
14848 if (parser->recovering) {
14855 parser->in_keyword_arg =
false;
14858 case PM_TOKEN_USTAR:
14859 case PM_TOKEN_STAR: {
14860 update_parameter_state(parser, &parser->current, &order);
14861 parser_lex(parser);
14865 bool repeated =
false;
14867 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14868 name = parser->previous;
14869 repeated = pm_parser_parameter_name_check(parser, &name);
14870 pm_parser_local_add_token(parser, &name, 1);
14872 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
14875 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14877 pm_node_flag_set_repeated_parameter(param);
14880 if (params->
rest == NULL) {
14881 pm_parameters_node_rest_set(params, param);
14883 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14884 pm_parameters_node_posts_append(parser->arena, params, param);
14889 case PM_TOKEN_STAR_STAR:
14890 case PM_TOKEN_USTAR_STAR: {
14891 pm_parameters_order_t previous_order = order;
14892 update_parameter_state(parser, &parser->current, &order);
14893 parser_lex(parser);
14898 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14899 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14900 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14903 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
14907 bool repeated =
false;
14908 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14909 name = parser->previous;
14910 repeated = pm_parser_parameter_name_check(parser, &name);
14911 pm_parser_local_add_token(parser, &name, 1);
14913 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
14916 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14918 pm_node_flag_set_repeated_parameter(param);
14923 pm_parameters_node_keyword_rest_set(params, param);
14925 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14926 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14932 if (parser->previous.
type == PM_TOKEN_COMMA) {
14933 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
14943 if (!parsing)
break;
14945 bool accepted_newline =
false;
14946 if (uses_parentheses) {
14947 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14950 if (accept1(parser, PM_TOKEN_COMMA)) {
14953 if (accepted_newline) {
14954 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14962 pm_do_loop_stack_pop(parser);
14965 if (PM_NODE_START(params) == PM_NODE_END(params)) {
14978 if (parser->heredoc_end == NULL) {
14982 return parser->line_offsets.
size - 1;
14988 return (
size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
14997token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14998 const uint8_t *cursor = parser->start + parser->line_offsets.
offsets[newline_index];
14999 const uint8_t *end = token->start;
15003 newline_index == 0 &&
15004 parser->start[0] == 0xef &&
15005 parser->start[1] == 0xbb &&
15006 parser->start[2] == 0xbf
15009 int64_t column = 0;
15010 for (; cursor < end; cursor++) {
15013 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15020 if (break_on_non_space)
return -1;
15033parser_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) {
15035 if (!parser->warn_mismatched_indentation)
return;
15038 size_t closing_newline_index = token_newline_index(parser);
15039 if (opening_newline_index == closing_newline_index)
return;
15044 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15045 if (!if_after_else && (opening_column == -1))
return;
15049 pm_token_t *closing_token = &parser->current;
15052 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15053 if ((closing_column == -1) || (opening_column == closing_column))
return;
15057 if (allow_indent && (closing_column > opening_column))
return;
15060 PM_PARSER_WARN_FORMAT(
15062 PM_TOKEN_START(parser, closing_token),
15063 PM_TOKEN_LENGTH(closing_token),
15064 PM_WARN_INDENTATION_MISMATCH,
15065 (
int) (closing_token->
end - closing_token->
start),
15066 (
const char *) closing_token->
start,
15067 (
int) (opening_token->
end - opening_token->
start),
15068 (
const char *) opening_token->
start,
15069 ((int32_t) opening_newline_index) + parser->start_line
15074 PM_RESCUES_BEGIN = 1,
15081} pm_rescues_type_t;
15091 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15092 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15093 parser_lex(parser);
15095 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
15097 switch (parser->current.type) {
15098 case PM_TOKEN_EQUAL_GREATER: {
15102 parser_lex(parser);
15103 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15105 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15106 reference = parse_target(parser, reference,
false,
false);
15108 pm_rescue_node_reference_set(rescue, reference);
15111 case PM_TOKEN_NEWLINE:
15112 case PM_TOKEN_SEMICOLON:
15113 case PM_TOKEN_KEYWORD_THEN:
15118 if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
15123 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15124 pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
15128 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15132 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15133 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15135 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15136 reference = parse_target(parser, reference,
false,
false);
15138 pm_rescue_node_reference_set(rescue, reference);
15141 }
while (accept1(parser, PM_TOKEN_COMMA));
15146 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15147 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15151 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15155 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15156 pm_accepts_block_stack_push(parser,
true);
15157 pm_context_t context;
15160 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_RESCUE;
break;
15161 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_RESCUE;
break;
15162 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_RESCUE;
break;
15163 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_RESCUE;
break;
15164 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE;
break;
15165 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE;
break;
15166 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE;
break;
15167 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15171 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15173 pm_accepts_block_stack_pop(parser);
15174 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15177 if (current == NULL) {
15178 pm_begin_node_rescue_clause_set(parent_node, rescue);
15180 pm_rescue_node_subsequent_set(current, rescue);
15189 if (current != NULL) {
15192 while (clause != NULL) {
15193 PM_NODE_LENGTH_SET_NODE(clause, current);
15199 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15200 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15201 opening_newline_index = token_newline_index(parser);
15203 else_keyword = parser->current;
15204 opening = &else_keyword;
15206 parser_lex(parser);
15207 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15210 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15211 pm_accepts_block_stack_push(parser,
true);
15212 pm_context_t context;
15215 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ELSE;
break;
15216 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ELSE;
break;
15217 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ELSE;
break;
15218 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ELSE;
break;
15219 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE;
break;
15220 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE;
break;
15221 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE;
break;
15222 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_ELSE;
break;
15225 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15226 pm_accepts_block_stack_pop(parser);
15228 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15231 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
15232 pm_begin_node_else_clause_set(parent_node, else_clause);
15236 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
15239 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15240 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15241 pm_token_t ensure_keyword = parser->current;
15243 parser_lex(parser);
15244 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15247 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15248 pm_accepts_block_stack_push(parser,
true);
15249 pm_context_t context;
15252 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ENSURE;
break;
15253 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ENSURE;
break;
15254 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ENSURE;
break;
15255 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ENSURE;
break;
15256 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE;
break;
15257 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE;
break;
15258 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE;
break;
15259 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15262 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15263 pm_accepts_block_stack_pop(parser);
15265 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15268 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
15269 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15272 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15273 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15274 pm_begin_node_end_keyword_set(parser, parent_node, &parser->current);
15277 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
15287 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
15288 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15291 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
15300parse_block_parameters(
15302 bool allows_trailing_comma,
15304 bool is_lambda_literal,
15305 bool accepts_blocks_in_defaults,
15309 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15310 if (!is_lambda_literal) {
15311 context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
15313 parameters = parse_parameters(
15315 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15317 allows_trailing_comma,
15319 accepts_blocks_in_defaults,
15321 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
15322 (uint16_t) (depth + 1)
15324 if (!is_lambda_literal) {
15325 context_pop(parser);
15330 if (opening != NULL) {
15331 accept1(parser, PM_TOKEN_NEWLINE);
15333 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15335 switch (parser->current.type) {
15336 case PM_TOKEN_CONSTANT:
15337 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15338 parser_lex(parser);
15340 case PM_TOKEN_INSTANCE_VARIABLE:
15341 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15342 parser_lex(parser);
15344 case PM_TOKEN_GLOBAL_VARIABLE:
15345 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15346 parser_lex(parser);
15348 case PM_TOKEN_CLASS_VARIABLE:
15349 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15350 parser_lex(parser);
15353 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15357 bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
15358 pm_parser_local_add_token(parser, &parser->previous, 1);
15361 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
15363 pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
15364 }
while (accept1(parser, PM_TOKEN_COMMA));
15368 return block_parameters;
15376outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15377 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15378 if (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15389static const char *
const pm_numbered_parameter_names[] = {
15390 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15400 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
15404 if (parameters != NULL) {
15406 if (implicit_parameters->
size > 0) {
15409 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15410 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15411 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15412 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15414 assert(
false &&
"unreachable");
15423 if (implicit_parameters->
size == 0) {
15430 uint8_t numbered_parameter = 0;
15431 bool it_parameter =
false;
15433 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15436 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15437 if (it_parameter) {
15438 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15439 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15440 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15441 }
else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
15442 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15443 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
15444 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->
location.
start + 1] -
'0'));
15446 assert(
false &&
"unreachable");
15448 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15449 if (numbered_parameter > 0) {
15450 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15452 it_parameter =
true;
15457 if (numbered_parameter > 0) {
15460 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15461 scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15463 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
15466 if (it_parameter) {
15467 return UP(pm_it_parameters_node_create(parser, opening, closing));
15477parse_block(
pm_parser_t *parser, uint16_t depth) {
15479 accept1(parser, PM_TOKEN_NEWLINE);
15485 bool do_block = opening.
type != PM_TOKEN_BRACE_LEFT && opening.
type != PM_TOKEN_BRACE_LEFT_ARGUMENT;
15486 if (do_block) pm_accepts_block_stack_push(parser,
true);
15487 pm_parser_scope_push(parser,
false);
15491 if (accept1(parser, PM_TOKEN_PIPE)) {
15492 pm_token_t block_parameters_opening = parser->previous;
15493 if (match1(parser, PM_TOKEN_PIPE)) {
15494 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15495 parser->command_start =
true;
15496 parser_lex(parser);
15498 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15499 accept1(parser, PM_TOKEN_NEWLINE);
15500 parser->command_start =
true;
15501 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15504 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
15507 accept1(parser, PM_TOKEN_NEWLINE);
15511 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15512 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
15515 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
15517 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15518 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15519 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)));
15522 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15523 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15524 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
15530 pm_accepts_block_stack_pop(parser);
15531 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
15535 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
15536 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
15538 pm_parser_scope_pop(parser);
15539 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
15554parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool full_arguments, uint8_t flags, uint16_t depth) {
15559 !token_begins_expression_p(parser->current.type) &&
15560 !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)
15565 bool found =
false;
15566 bool parsed_command_args =
false;
15568 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15570 arguments->
opening_loc = TOK2LOC(parser, &parser->previous);
15572 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15573 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15575 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
15583 if (!full_arguments && parser->previous.
type == PM_TOKEN_COMMA) {
15584 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15587 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15588 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
15589 parser->previous.
start = parser->previous.
end;
15590 parser->previous.
type = 0;
15593 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15595 }
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)) {
15597 parsed_command_args =
true;
15607 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);
15608 if (lookahead_delimiter) pm_accepts_block_stack_pop(parser);
15609 pm_accepts_block_stack_push(parser,
false);
15610 if (lookahead_delimiter) pm_accepts_block_stack_push(parser,
true);
15615 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
15620 if (parser->previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15621 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15629 bool lookahead_brace = match2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT);
15630 if (lookahead_brace) pm_accepts_block_stack_pop(parser);
15631 pm_accepts_block_stack_pop(parser);
15632 if (lookahead_brace) pm_accepts_block_stack_push(parser,
true);
15638 if (full_arguments) {
15641 if (accept2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT)) {
15643 block = parse_block(parser, (uint16_t) (depth + 1));
15644 pm_arguments_validate_block(parser, arguments, block);
15645 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15647 block = parse_block(parser, (uint16_t) (depth + 1));
15648 }
else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
15650 block = parse_block(parser, (uint16_t) (depth + 1));
15653 if (block != NULL) {
15655 arguments->
block = UP(block);
15657 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
15659 if (arguments->
block != NULL) {
15661 arguments->
arguments = pm_arguments_node_create(parser);
15663 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, arguments->
block);
15665 arguments->
block = UP(block);
15679 bool in_sclass =
false;
15680 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15681 switch (context_node->context) {
15682 case PM_CONTEXT_BEGIN_ELSE:
15683 case PM_CONTEXT_BEGIN_ENSURE:
15684 case PM_CONTEXT_BEGIN_RESCUE:
15685 case PM_CONTEXT_BEGIN:
15686 case PM_CONTEXT_CASE_IN:
15687 case PM_CONTEXT_CASE_WHEN:
15688 case PM_CONTEXT_DEFAULT_PARAMS:
15689 case PM_CONTEXT_DEFINED:
15690 case PM_CONTEXT_ELSE:
15691 case PM_CONTEXT_ELSIF:
15692 case PM_CONTEXT_EMBEXPR:
15693 case PM_CONTEXT_FOR_INDEX:
15694 case PM_CONTEXT_FOR:
15695 case PM_CONTEXT_IF:
15696 case PM_CONTEXT_LOOP_PREDICATE:
15697 case PM_CONTEXT_MAIN:
15698 case PM_CONTEXT_MULTI_TARGET:
15699 case PM_CONTEXT_PARENS:
15700 case PM_CONTEXT_POSTEXE:
15701 case PM_CONTEXT_PREDICATE:
15702 case PM_CONTEXT_PREEXE:
15703 case PM_CONTEXT_RESCUE_MODIFIER:
15704 case PM_CONTEXT_TERNARY:
15705 case PM_CONTEXT_UNLESS:
15706 case PM_CONTEXT_UNTIL:
15707 case PM_CONTEXT_WHILE:
15711 case PM_CONTEXT_SCLASS_ELSE:
15712 case PM_CONTEXT_SCLASS_ENSURE:
15713 case PM_CONTEXT_SCLASS_RESCUE:
15714 case PM_CONTEXT_SCLASS:
15717 case PM_CONTEXT_CLASS_ELSE:
15718 case PM_CONTEXT_CLASS_ENSURE:
15719 case PM_CONTEXT_CLASS_RESCUE:
15720 case PM_CONTEXT_CLASS:
15721 case PM_CONTEXT_MODULE_ELSE:
15722 case PM_CONTEXT_MODULE_ENSURE:
15723 case PM_CONTEXT_MODULE_RESCUE:
15724 case PM_CONTEXT_MODULE:
15726 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15728 case PM_CONTEXT_BLOCK_BRACES:
15729 case PM_CONTEXT_BLOCK_ELSE:
15730 case PM_CONTEXT_BLOCK_ENSURE:
15731 case PM_CONTEXT_BLOCK_KEYWORDS:
15732 case PM_CONTEXT_BLOCK_RESCUE:
15733 case PM_CONTEXT_BLOCK_PARAMETERS:
15734 case PM_CONTEXT_DEF_ELSE:
15735 case PM_CONTEXT_DEF_ENSURE:
15736 case PM_CONTEXT_DEF_PARAMS:
15737 case PM_CONTEXT_DEF_RESCUE:
15738 case PM_CONTEXT_DEF:
15739 case PM_CONTEXT_LAMBDA_BRACES:
15740 case PM_CONTEXT_LAMBDA_DO_END:
15741 case PM_CONTEXT_LAMBDA_ELSE:
15742 case PM_CONTEXT_LAMBDA_ENSURE:
15743 case PM_CONTEXT_LAMBDA_RESCUE:
15747 case PM_CONTEXT_NONE:
15749 assert(
false &&
"unreachable");
15753 if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
15754 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15764 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15765 switch (context_node->context) {
15766 case PM_CONTEXT_BLOCK_BRACES:
15767 case PM_CONTEXT_BLOCK_KEYWORDS:
15768 case PM_CONTEXT_BLOCK_ELSE:
15769 case PM_CONTEXT_BLOCK_ENSURE:
15770 case PM_CONTEXT_BLOCK_PARAMETERS:
15771 case PM_CONTEXT_BLOCK_RESCUE:
15772 case PM_CONTEXT_DEFINED:
15773 case PM_CONTEXT_FOR:
15774 case PM_CONTEXT_LAMBDA_BRACES:
15775 case PM_CONTEXT_LAMBDA_DO_END:
15776 case PM_CONTEXT_LAMBDA_ELSE:
15777 case PM_CONTEXT_LAMBDA_ENSURE:
15778 case PM_CONTEXT_LAMBDA_RESCUE:
15779 case PM_CONTEXT_LOOP_PREDICATE:
15780 case PM_CONTEXT_UNTIL:
15781 case PM_CONTEXT_WHILE:
15785 case PM_CONTEXT_POSTEXE:
15787 if (context_node->context == PM_CONTEXT_POSTEXE) {
15788 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
15793 case PM_CONTEXT_DEF:
15794 case PM_CONTEXT_DEF_PARAMS:
15795 case PM_CONTEXT_DEF_ELSE:
15796 case PM_CONTEXT_DEF_ENSURE:
15797 case PM_CONTEXT_DEF_RESCUE:
15798 case PM_CONTEXT_MAIN:
15799 case PM_CONTEXT_PREEXE:
15800 case PM_CONTEXT_SCLASS:
15801 case PM_CONTEXT_SCLASS_ELSE:
15802 case PM_CONTEXT_SCLASS_ENSURE:
15803 case PM_CONTEXT_SCLASS_RESCUE:
15813 assert(parser->current_block_exits != NULL);
15814 pm_node_list_append(parser->arena, parser->current_block_exits, node);
15816 case PM_CONTEXT_BEGIN_ELSE:
15817 case PM_CONTEXT_BEGIN_ENSURE:
15818 case PM_CONTEXT_BEGIN_RESCUE:
15819 case PM_CONTEXT_BEGIN:
15820 case PM_CONTEXT_CASE_IN:
15821 case PM_CONTEXT_CASE_WHEN:
15822 case PM_CONTEXT_CLASS_ELSE:
15823 case PM_CONTEXT_CLASS_ENSURE:
15824 case PM_CONTEXT_CLASS_RESCUE:
15825 case PM_CONTEXT_CLASS:
15826 case PM_CONTEXT_DEFAULT_PARAMS:
15827 case PM_CONTEXT_ELSE:
15828 case PM_CONTEXT_ELSIF:
15829 case PM_CONTEXT_EMBEXPR:
15830 case PM_CONTEXT_FOR_INDEX:
15831 case PM_CONTEXT_IF:
15832 case PM_CONTEXT_MODULE_ELSE:
15833 case PM_CONTEXT_MODULE_ENSURE:
15834 case PM_CONTEXT_MODULE_RESCUE:
15835 case PM_CONTEXT_MODULE:
15836 case PM_CONTEXT_MULTI_TARGET:
15837 case PM_CONTEXT_PARENS:
15838 case PM_CONTEXT_PREDICATE:
15839 case PM_CONTEXT_RESCUE_MODIFIER:
15840 case PM_CONTEXT_TERNARY:
15841 case PM_CONTEXT_UNLESS:
15845 case PM_CONTEXT_NONE:
15847 assert(
false &&
"unreachable");
15859 pm_node_list_t *previous_block_exits = parser->current_block_exits;
15860 parser->current_block_exits = current_block_exits;
15861 return previous_block_exits;
15875 switch (PM_NODE_TYPE(block_exit)) {
15876 case PM_BREAK_NODE:
type =
"break";
break;
15877 case PM_NEXT_NODE:
type =
"next";
break;
15878 case PM_REDO_NODE:
type =
"redo";
break;
15879 default: assert(
false &&
"unreachable");
type =
"";
break;
15882 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15885 parser->current_block_exits = previous_block_exits;
15894 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15898 parser->current_block_exits = previous_block_exits;
15899 }
else if (previous_block_exits != NULL) {
15905 pm_node_list_concat(parser->arena, previous_block_exits, parser->current_block_exits);
15906 parser->current_block_exits = previous_block_exits;
15911 flush_block_exits(parser, previous_block_exits);
15916parse_predicate(
pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context,
pm_token_t *then_keyword, uint16_t depth) {
15917 context_push(parser, PM_CONTEXT_PREDICATE);
15918 pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
15919 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));
15922 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15924 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15925 predicate_closed =
true;
15926 *then_keyword = parser->previous;
15929 if (!predicate_closed) {
15930 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15933 context_pop(parser);
15938parse_conditional(
pm_parser_t *parser, pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15940 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15945 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, context, &then_keyword, (uint16_t) (depth + 1));
15948 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15949 pm_accepts_block_stack_push(parser,
true);
15950 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15951 pm_accepts_block_stack_pop(parser);
15952 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15958 case PM_CONTEXT_IF:
15959 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15961 case PM_CONTEXT_UNLESS:
15962 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
15965 assert(
false &&
"unreachable");
15973 if (context == PM_CONTEXT_IF) {
15974 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15975 if (parser_end_of_line_p(parser)) {
15976 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
15979 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15981 parser_lex(parser);
15983 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15984 pm_accepts_block_stack_push(parser,
true);
15986 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
15987 pm_accepts_block_stack_pop(parser);
15988 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15990 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15996 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15997 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15998 opening_newline_index = token_newline_index(parser);
16000 parser_lex(parser);
16003 pm_accepts_block_stack_push(parser,
true);
16004 pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
16005 pm_accepts_block_stack_pop(parser);
16007 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16008 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
16009 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
16011 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
16014 case PM_CONTEXT_IF:
16015 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
16017 case PM_CONTEXT_UNLESS:
16021 assert(
false &&
"unreachable");
16025 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
16026 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
16031 case PM_CONTEXT_IF: {
16033 bool recursing =
true;
16035 while (recursing) {
16036 switch (PM_NODE_TYPE(current)) {
16038 pm_if_node_end_keyword_loc_set(parser, (
pm_if_node_t *) current, &parser->previous);
16040 recursing = current != NULL;
16043 pm_else_node_end_keyword_loc_set(parser, (
pm_else_node_t *) current, &parser->previous);
16054 case PM_CONTEXT_UNLESS:
16055 pm_unless_node_end_keyword_loc_set(parser, (
pm_unless_node_t *) parent, &parser->previous);
16058 assert(
false &&
"unreachable");
16062 pop_block_exits(parser, previous_block_exits);
16070#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16071 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16072 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16073 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: \
16074 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16075 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16076 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16077 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16078 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16079 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16080 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16086#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16087 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16088 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16089 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16090 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16091 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16092 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16093 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16100#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16101 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16102 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16103 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_XSTRING_BEGIN: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16104 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16105 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16106 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16107 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16108 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16114#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16115 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16116 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16117 case PM_TOKEN_CLASS_VARIABLE
16123#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16124 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16125 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16126 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16130PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16138 if (explicit_encoding != NULL) {
16139 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
16142 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16143 }
else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
16148 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16159parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16160 switch (parser->current.type) {
16167 case PM_TOKEN_STRING_CONTENT: {
16168 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16169 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
16171 parser_lex(parser);
16180 case PM_TOKEN_EMBEXPR_BEGIN: {
16183 parser->explicit_encoding = NULL;
16185 pm_lex_state_t state = parser->lex_state;
16186 int brace_nesting = parser->brace_nesting;
16188 parser->brace_nesting = 0;
16189 lex_state_set(parser, PM_LEX_STATE_BEG);
16190 parser_lex(parser);
16195 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
16196 statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
16199 parser->brace_nesting = brace_nesting;
16200 lex_state_set(parser, state);
16201 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16206 if (statements != NULL && statements->
body.
size == 1) {
16207 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16210 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
16219 case PM_TOKEN_EMBVAR: {
16222 parser->explicit_encoding = NULL;
16224 lex_state_set(parser, PM_LEX_STATE_BEG);
16225 parser_lex(parser);
16230 switch (parser->current.type) {
16233 case PM_TOKEN_BACK_REFERENCE:
16234 parser_lex(parser);
16235 variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
16239 case PM_TOKEN_NUMBERED_REFERENCE:
16240 parser_lex(parser);
16241 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16245 case PM_TOKEN_GLOBAL_VARIABLE:
16246 parser_lex(parser);
16247 variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
16251 case PM_TOKEN_INSTANCE_VARIABLE:
16252 parser_lex(parser);
16253 variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
16257 case PM_TOKEN_CLASS_VARIABLE:
16258 parser_lex(parser);
16259 variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
16265 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16266 variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16270 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
16273 parser_lex(parser);
16274 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16284static const uint8_t *
16285parse_operator_symbol_name(
const pm_token_t *name) {
16286 switch (name->
type) {
16287 case PM_TOKEN_TILDE:
16288 case PM_TOKEN_BANG:
16289 if (name->
end[-1] ==
'@')
return name->
end - 1;
16298 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
16299 const uint8_t *end = parse_operator_symbol_name(&parser->current);
16301 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16302 parser_lex(parser);
16304 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, end);
16305 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16317 const pm_token_t opening = parser->previous;
16319 if (lex_mode->mode != PM_LEX_STRING) {
16320 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16322 switch (parser->current.type) {
16323 case PM_CASE_OPERATOR:
16324 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16325 case PM_TOKEN_IDENTIFIER:
16326 case PM_TOKEN_CONSTANT:
16327 case PM_TOKEN_INSTANCE_VARIABLE:
16328 case PM_TOKEN_METHOD_NAME:
16329 case PM_TOKEN_CLASS_VARIABLE:
16330 case PM_TOKEN_GLOBAL_VARIABLE:
16331 case PM_TOKEN_NUMBERED_REFERENCE:
16332 case PM_TOKEN_BACK_REFERENCE:
16333 case PM_CASE_KEYWORD:
16334 parser_lex(parser);
16337 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16341 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
16342 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16343 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16348 if (lex_mode->as.string.interpolation) {
16350 if (match1(parser, PM_TOKEN_STRING_END)) {
16351 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16352 parser_lex(parser);
16354 .
type = PM_TOKEN_STRING_CONTENT,
16355 .start = parser->previous.
start,
16356 .end = parser->previous.
start
16359 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
16363 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16367 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16368 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16369 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16371 return UP(pm_string_node_to_symbol_node(parser, (
pm_string_node_t *) part, &opening, &parser->previous));
16375 if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16377 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16378 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16379 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16383 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16384 if (match1(parser, PM_TOKEN_EOF)) {
16385 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16387 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16390 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16397 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16398 content = parser->current;
16399 unescaped = parser->current_string;
16400 parser_lex(parser);
16411 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16413 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16414 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16416 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
16417 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16419 if (next_state != PM_LEX_STATE_NONE) {
16420 lex_state_set(parser, next_state);
16423 parser_lex(parser);
16424 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16426 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16430 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.
end, .end = parser->previous.
end };
16431 pm_string_shared_init(&unescaped, content.
start, content.
end);
16434 if (next_state != PM_LEX_STATE_NONE) {
16435 lex_state_set(parser, next_state);
16438 if (match1(parser, PM_TOKEN_EOF)) {
16439 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16441 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16444 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
false)));
16452parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16453 switch (parser->current.type) {
16454 case PM_CASE_OPERATOR:
16455 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
16456 case PM_CASE_KEYWORD:
16457 case PM_TOKEN_CONSTANT:
16458 case PM_TOKEN_IDENTIFIER:
16459 case PM_TOKEN_METHOD_NAME: {
16460 parser_lex(parser);
16462 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16463 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16464 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16468 case PM_TOKEN_SYMBOL_BEGIN: {
16470 parser_lex(parser);
16472 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16475 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16476 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16487parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16488 switch (parser->current.type) {
16489 case PM_CASE_OPERATOR:
16490 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16491 case PM_CASE_KEYWORD:
16492 case PM_TOKEN_CONSTANT:
16493 case PM_TOKEN_IDENTIFIER:
16494 case PM_TOKEN_METHOD_NAME: {
16495 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16496 parser_lex(parser);
16498 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16499 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16500 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16504 case PM_TOKEN_SYMBOL_BEGIN: {
16506 parser_lex(parser);
16508 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16510 case PM_TOKEN_BACK_REFERENCE:
16511 parser_lex(parser);
16512 return UP(pm_back_reference_read_node_create(parser, &parser->previous));
16513 case PM_TOKEN_NUMBERED_REFERENCE:
16514 parser_lex(parser);
16515 return UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16516 case PM_TOKEN_GLOBAL_VARIABLE:
16517 parser_lex(parser);
16518 return UP(pm_global_variable_read_node_create(parser, &parser->previous));
16520 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16521 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16531 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
16533 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
16535 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16536 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth,
false));
16539 pm_scope_t *current_scope = parser->current_scope;
16540 if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16541 if (is_numbered_param) {
16546 uint8_t maximum = (uint8_t) (parser->previous.
start[1] -
'0');
16547 for (uint8_t number = 1; number <= maximum; number++) {
16548 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16551 if (!match1(parser, PM_TOKEN_EQUAL)) {
16552 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
16555 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0,
false));
16556 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16559 }
else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.
start, parser->previous.
end)) {
16560 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16561 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16575 pm_node_flags_t flags = 0;
16577 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.
end[-1] !=
'!') && (parser->previous.
end[-1] !=
'?')) {
16578 pm_node_t *node = parse_variable(parser);
16579 if (node != NULL)
return node;
16580 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16583 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
16584 pm_node_flag_set(UP(node), flags);
16595parse_method_definition_name(
pm_parser_t *parser) {
16596 switch (parser->current.type) {
16597 case PM_CASE_KEYWORD:
16598 case PM_TOKEN_CONSTANT:
16599 case PM_TOKEN_METHOD_NAME:
16600 parser_lex(parser);
16601 return parser->previous;
16602 case PM_TOKEN_IDENTIFIER:
16603 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
16604 parser_lex(parser);
16605 return parser->previous;
16606 case PM_CASE_OPERATOR:
16607 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16608 parser_lex(parser);
16609 return parser->previous;
16611 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
16612 return (
pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end };
16623 if (string->
type != PM_STRING_OWNED) {
16624 size_t length = pm_string_length(
string);
16625 writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(
string), length,
PRISM_ALIGNOF(uint8_t));
16626 pm_string_constant_init(
string, (
const char *) writable, length);
16628 writable = (uint8_t *) string->
source;
16634 size_t dest_length = pm_string_length(
string);
16635 const uint8_t *source_cursor = writable;
16636 const uint8_t *source_end = source_cursor + dest_length;
16641 size_t trimmed_whitespace = 0;
16647 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16648 if (*source_cursor ==
'\t') {
16649 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16650 if (trimmed_whitespace > common_whitespace)
break;
16652 trimmed_whitespace++;
16659 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
16660 string->length = dest_length;
16670 const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->
content_loc);
16671 return pm_memchr(cursor,
'\\', string_node->
content_loc.
length, parser->encoding_changed, parser->encoding) == NULL;
16683 bool dedent_next =
true;
16687 size_t write_index = 0;
16694 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16695 nodes->
nodes[write_index++] = node;
16696 dedent_next =
false;
16702 parse_heredoc_dedent_string(parser->arena, &string_node->
unescaped, common_whitespace);
16705 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16707 nodes->
nodes[write_index++] = node;
16711 dedent_next =
true;
16714 nodes->
size = write_index;
16721parse_strings_empty_content(
const uint8_t *location) {
16722 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16730 assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
16731 bool concating =
false;
16733 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16739 assert(lex_mode->mode == PM_LEX_STRING);
16740 bool lex_interpolation = lex_mode->as.string.interpolation;
16741 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
16744 parser_lex(parser);
16746 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16747 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16751 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
16752 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->previous);
16756 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16760 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
16761 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
start);
16764 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16765 }
else if (!lex_interpolation) {
16771 if (match1(parser, PM_TOKEN_EOF)) {
16772 unescaped = PM_STRING_EMPTY;
16773 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
16775 unescaped = parser->current_string;
16776 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16777 content = parser->previous;
16791 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16793 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16794 pm_node_list_append(parser->arena, &parts, part);
16797 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16798 pm_node_list_append(parser->arena, &parts, part);
16799 parser_lex(parser);
16800 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16802 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16803 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16804 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16805 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
true)));
16806 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16807 }
else if (match1(parser, PM_TOKEN_EOF)) {
16808 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16809 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16810 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16811 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16813 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.
type));
16814 parser->previous.
start = parser->previous.
end;
16815 parser->previous.
type = 0;
16816 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16818 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16825 const pm_encoding_t *explicit_encoding = parser->explicit_encoding;
16826 parser_lex(parser);
16828 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16829 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16830 pm_node_flag_set(node, parse_unescaped_encoding(parser, explicit_encoding));
16836 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16837 const uint8_t *location = parser->previous.
end;
16838 if (location > parser->start && location[-1] ==
'\n') location--;
16839 pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
16841 parser->previous.
start = parser->previous.
end;
16842 parser->previous.
type = 0;
16844 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16845 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, explicit_encoding, &content, &unescaped,
true)));
16846 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16851 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
16852 pm_node_flag_set(part, parse_unescaped_encoding(parser, explicit_encoding));
16853 pm_node_list_append(parser->arena, &parts, part);
16855 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16856 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16857 pm_node_list_append(parser->arena, &parts, part);
16861 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16862 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16863 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16864 }
else if (match1(parser, PM_TOKEN_EOF)) {
16865 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16866 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16868 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16869 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16879 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16880 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16881 pm_node_list_append(parser->arena, &parts, part);
16885 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16886 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16887 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16888 }
else if (match1(parser, PM_TOKEN_EOF)) {
16889 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16890 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16892 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16893 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16897 if (current == NULL) {
16901 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16912 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16913 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16919 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16920 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16925 pm_interpolated_string_node_append(parser, container, current);
16926 current = UP(container);
16936#define PM_PARSE_PATTERN_SINGLE 0
16937#define PM_PARSE_PATTERN_TOP 1
16938#define PM_PARSE_PATTERN_MULTI 2
16951 if (peek_at(parser, parser->start + location->
start) ==
'_')
return;
16953 if (pm_constant_id_list_includes(captures, capture)) {
16954 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16956 pm_constant_id_list_append(parser->arena, captures, capture);
16967 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16969 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16970 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
16976 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16984 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16985 opening = parser->previous;
16986 accept1(parser, PM_TOKEN_NEWLINE);
16988 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16989 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16990 accept1(parser, PM_TOKEN_NEWLINE);
16991 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16994 closing = parser->previous;
16996 parser_lex(parser);
16997 opening = parser->previous;
16998 accept1(parser, PM_TOKEN_NEWLINE);
17000 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17001 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17002 accept1(parser, PM_TOKEN_NEWLINE);
17003 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17006 closing = parser->previous;
17012 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
17019 switch (PM_NODE_TYPE(inner)) {
17020 case PM_ARRAY_PATTERN_NODE: {
17024 PM_NODE_START_SET_NODE(pattern_node, node);
17025 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17028 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17029 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17031 return UP(pattern_node);
17036 case PM_FIND_PATTERN_NODE: {
17040 PM_NODE_START_SET_NODE(pattern_node, node);
17041 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17044 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17045 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17047 return UP(pattern_node);
17052 case PM_HASH_PATTERN_NODE: {
17056 PM_NODE_START_SET_NODE(pattern_node, node);
17057 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17060 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17061 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17063 return UP(pattern_node);
17075 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17076 pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
17077 return UP(pattern_node);
17085 assert(parser->previous.
type == PM_TOKEN_USTAR);
17092 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17093 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17096 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17097 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17100 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17101 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17102 name = UP(pm_local_variable_target_node_create(
17106 (uint32_t) (depth == -1 ? 0 : depth)
17111 return pm_splat_node_create(parser, &
operator, name);
17119 assert(parser->current.type == PM_TOKEN_USTAR_STAR);
17120 parser_lex(parser);
17125 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17126 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
17129 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17130 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17133 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17134 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17137 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17138 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17139 value = UP(pm_local_variable_target_node_create(
17143 (uint32_t) (depth == -1 ? 0 : depth)
17147 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
17155pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17156 ptrdiff_t length = end - start;
17157 if (length == 0)
return false;
17160 size_t width = char_is_identifier_start(parser, start, end - start);
17161 if (width == 0)
return false;
17164 if (parser->encoding_changed) {
17165 if (parser->encoding->isupper_char(start, length))
return false;
17167 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17172 const uint8_t *cursor = start + width;
17173 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17174 return cursor == end;
17184 const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
17185 const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
17187 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
17190 if (pm_slice_is_valid_local(parser, start, end)) {
17191 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17193 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
17195 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
17196 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
17201 pm_parser_local_add(parser, constant_id, start, end, 0);
17204 parse_pattern_capture(parser, captures, constant_id, value_loc);
17209 (uint32_t) (depth == -1 ? 0 : depth)
17212 return UP(pm_implicit_node_create(parser, UP(target)));
17221 if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, keys, node,
true) != NULL) {
17222 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17235 switch (PM_NODE_TYPE(first_node)) {
17236 case PM_ASSOC_SPLAT_NODE:
17237 case PM_NO_KEYWORDS_PARAMETER_NODE:
17240 case PM_INTERPOLATED_SYMBOL_NODE:
17241 case PM_SYMBOL_NODE: {
17242 if (pm_symbol_node_label_p(parser, first_node)) {
17243 if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
17244 pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17246 parse_pattern_hash_key(parser, &keys, first_node);
17256 if (!token_begins_pattern_p(parser->current.type)) {
17257 if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
17258 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17260 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
17265 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17268 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17269 pm_node_list_append(parser->arena, &assocs, assoc);
17278 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;
17279 pm_parser_err_node(parser, first_node, diag_id);
17281 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
17282 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17284 pm_node_list_append(parser->arena, &assocs, assoc);
17290 while (accept1(parser, PM_TOKEN_COMMA)) {
17296 if (!token_begins_pattern_p(parser->current.type)) {
17298 if (rest != NULL) {
17299 pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17305 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17306 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17308 if (rest == NULL) {
17311 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17312 pm_node_list_append(parser->arena, &assocs, assoc);
17317 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17318 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17320 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17321 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17322 }
else if (!pm_symbol_node_label_p(parser, key)) {
17323 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17325 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
17326 key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17328 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17330 pm_token_t label = { .
type = PM_TOKEN_LABEL, .start = parser->previous.
end, .end = parser->previous.
end };
17331 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
17334 parse_pattern_hash_key(parser, &keys, key);
17342 if (!token_begins_pattern_p(parser->current.type)) {
17343 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
17344 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17346 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
17349 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17352 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
17354 if (rest != NULL) {
17355 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17358 pm_node_list_append(parser->arena, &assocs, assoc);
17365 pm_static_literals_free(&keys);
17374 switch (parser->current.type) {
17375 case PM_TOKEN_IDENTIFIER:
17376 case PM_TOKEN_METHOD_NAME: {
17377 parser_lex(parser);
17378 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17381 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17382 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17385 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17386 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17387 return UP(pm_local_variable_target_node_create(
17391 (uint32_t) (depth == -1 ? 0 : depth)
17394 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17396 parser_lex(parser);
17398 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17401 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
17406 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17408 accept1(parser, PM_TOKEN_NEWLINE);
17409 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17412 switch (PM_NODE_TYPE(inner)) {
17413 case PM_ARRAY_PATTERN_NODE: {
17416 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17417 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17419 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17420 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17422 return UP(pattern_node);
17427 case PM_FIND_PATTERN_NODE: {
17430 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17431 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17433 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17434 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17436 return UP(pattern_node);
17446 pm_array_pattern_node_requireds_append(parser->arena, node, inner);
17449 case PM_TOKEN_BRACE_LEFT_HASH: {
17450 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17451 parser->pattern_matching_newlines =
false;
17455 parser_lex(parser);
17457 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17460 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
17464 switch (parser->current.type) {
17465 case PM_TOKEN_LABEL:
17466 parser_lex(parser);
17467 first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
17469 case PM_TOKEN_USTAR_STAR:
17470 first_node = parse_pattern_keyword_rest(parser, captures);
17472 case PM_TOKEN_STRING_BEGIN:
17473 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));
17476 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
17477 parser_lex(parser);
17479 first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
17484 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17486 accept1(parser, PM_TOKEN_NEWLINE);
17487 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
17490 PM_NODE_START_SET_TOKEN(parser, node, &opening);
17491 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
17497 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17500 case PM_TOKEN_UDOT_DOT:
17501 case PM_TOKEN_UDOT_DOT_DOT: {
17503 parser_lex(parser);
17507 switch (parser->current.type) {
17508 case PM_CASE_PRIMITIVE: {
17509 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));
17510 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17513 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17514 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17515 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17519 case PM_CASE_PRIMITIVE: {
17520 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));
17523 if (pm_symbol_node_label_p(parser, node))
return node;
17526 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17527 pm_parser_err_node(parser, node, diag_id);
17528 return UP(pm_error_recovery_node_create_unexpected(parser, node));
17532 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17538 switch (parser->current.type) {
17539 case PM_CASE_PRIMITIVE: {
17540 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));
17541 return UP(pm_range_node_create(parser, node, &
operator, right));
17544 return UP(pm_range_node_create(parser, node, &
operator, NULL));
17550 case PM_TOKEN_CARET: {
17551 parser_lex(parser);
17556 switch (parser->current.type) {
17557 case PM_TOKEN_IDENTIFIER: {
17558 parser_lex(parser);
17559 pm_node_t *variable = UP(parse_variable(parser));
17561 if (variable == NULL) {
17562 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
17563 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
17566 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17568 case PM_TOKEN_INSTANCE_VARIABLE: {
17569 parser_lex(parser);
17570 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
17572 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17574 case PM_TOKEN_CLASS_VARIABLE: {
17575 parser_lex(parser);
17576 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
17578 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17580 case PM_TOKEN_GLOBAL_VARIABLE: {
17581 parser_lex(parser);
17582 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
17584 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17586 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
17587 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17588 parser->pattern_matching_newlines =
false;
17591 parser_lex(parser);
17593 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));
17594 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17596 accept1(parser, PM_TOKEN_NEWLINE);
17597 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
17598 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->previous));
17603 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17604 pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17605 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17609 case PM_TOKEN_UCOLON_COLON: {
17611 parser_lex(parser);
17613 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17616 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
17618 case PM_TOKEN_CONSTANT: {
17620 parser_lex(parser);
17622 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
17623 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17626 pm_parser_err_current(parser, diag_id);
17627 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17632parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
17633 switch (PM_NODE_TYPE(node)) {
17634 case PM_LOCAL_VARIABLE_TARGET_NODE: {
17636 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17650 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
17660 bool alternation =
false;
17662 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
17663 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
17664 parse_pattern_alternation_error(parser, node);
17667 switch (parser->current.type) {
17668 case PM_TOKEN_IDENTIFIER:
17669 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17670 case PM_TOKEN_BRACE_LEFT_HASH:
17671 case PM_TOKEN_CARET:
17672 case PM_TOKEN_CONSTANT:
17673 case PM_TOKEN_UCOLON_COLON:
17674 case PM_TOKEN_UDOT_DOT:
17675 case PM_TOKEN_UDOT_DOT_DOT:
17676 case PM_CASE_PRIMITIVE: {
17677 if (!alternation) {
17678 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17681 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17683 if (captures->
size) parse_pattern_alternation_error(parser, right);
17684 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17689 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
17690 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17693 parser_lex(parser);
17695 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17696 accept1(parser, PM_TOKEN_NEWLINE);
17697 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17698 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
17700 if (!alternation) {
17703 if (captures->
size) parse_pattern_alternation_error(parser, right);
17704 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17710 pm_parser_err_current(parser, diag_id);
17711 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17713 if (!alternation) {
17716 if (captures->
size) parse_pattern_alternation_error(parser, right);
17717 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
17727 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17729 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17731 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17734 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17735 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17738 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17739 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17744 (uint32_t) (depth == -1 ? 0 : depth)
17747 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17760 bool leading_rest =
false;
17761 bool trailing_rest =
false;
17763 switch (parser->current.type) {
17764 case PM_TOKEN_LABEL: {
17765 parser_lex(parser);
17766 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17767 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17769 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17770 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17775 case PM_TOKEN_USTAR_STAR: {
17776 node = parse_pattern_keyword_rest(parser, captures);
17777 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17779 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17780 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17785 case PM_TOKEN_STRING_BEGIN: {
17788 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17790 if (pm_symbol_node_label_p(parser, node)) {
17791 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17793 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17794 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17800 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17803 case PM_TOKEN_USTAR: {
17804 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17805 parser_lex(parser);
17806 node = UP(parse_pattern_rest(parser, captures));
17807 leading_rest =
true;
17813 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17819 if (pm_symbol_node_label_p(parser, node)) {
17820 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17823 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17828 pm_node_list_append(parser->arena, &nodes, node);
17831 while (accept1(parser, PM_TOKEN_COMMA)) {
17837 if (!token_begins_pattern_p(parser->current.type)) {
17842 if (trailing_rest) {
17843 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17846 node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
17847 pm_node_list_append(parser->arena, &nodes, node);
17848 trailing_rest =
true;
17852 if (accept1(parser, PM_TOKEN_USTAR)) {
17853 node = UP(parse_pattern_rest(parser, captures));
17858 if (trailing_rest) {
17859 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17862 trailing_rest =
true;
17864 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17867 pm_node_list_append(parser->arena, &nodes, node);
17874 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17875 node = UP(pm_find_pattern_node_create(parser, &nodes));
17877 if (nodes.
size == 2) {
17878 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17881 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17883 if (leading_rest && trailing_rest) {
17884 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17889 }
else if (leading_rest) {
17892 node = UP(pm_array_pattern_node_rest_create(parser, node));
17904parse_negative_numeric(
pm_node_t *node) {
17905 switch (PM_NODE_TYPE(node)) {
17906 case PM_INTEGER_NODE: {
17913 case PM_FLOAT_NODE: {
17920 case PM_RATIONAL_NODE: {
17927 case PM_IMAGINARY_NODE:
17933 assert(
false &&
"unreachable");
17944pm_parser_err_prefix(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
17946 case PM_ERR_HASH_KEY: {
17947 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.
type));
17950 case PM_ERR_HASH_VALUE:
17951 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17952 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17955 case PM_ERR_UNARY_RECEIVER: {
17956 const char *human = (parser->current.type == PM_TOKEN_EOF ?
"end-of-input" : pm_token_str(parser->current.type));
17957 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.
start[0]);
17960 case PM_ERR_UNARY_DISALLOWED:
17961 case PM_ERR_EXPECT_ARGUMENT: {
17962 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17966 pm_parser_err_previous(parser, diag_id);
17976#define CONTEXT_NONE 0
17977#define CONTEXT_THROUGH_ENSURE 1
17978#define CONTEXT_THROUGH_ELSE 2
17981 int context = CONTEXT_NONE;
17983 while (context_node != NULL) {
17984 switch (context_node->context) {
17985 case PM_CONTEXT_BEGIN_RESCUE:
17986 case PM_CONTEXT_BLOCK_RESCUE:
17987 case PM_CONTEXT_CLASS_RESCUE:
17988 case PM_CONTEXT_DEF_RESCUE:
17989 case PM_CONTEXT_LAMBDA_RESCUE:
17990 case PM_CONTEXT_MODULE_RESCUE:
17991 case PM_CONTEXT_SCLASS_RESCUE:
17992 case PM_CONTEXT_DEFINED:
17993 case PM_CONTEXT_RESCUE_MODIFIER:
17996 case PM_CONTEXT_CLASS:
17997 case PM_CONTEXT_DEF:
17998 case PM_CONTEXT_DEF_PARAMS:
17999 case PM_CONTEXT_MAIN:
18000 case PM_CONTEXT_MODULE:
18001 case PM_CONTEXT_PREEXE:
18002 case PM_CONTEXT_SCLASS:
18005 if (context == CONTEXT_NONE) {
18006 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
18007 }
else if (context == CONTEXT_THROUGH_ENSURE) {
18008 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
18009 }
else if (context == CONTEXT_THROUGH_ELSE) {
18010 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
18013 case PM_CONTEXT_BEGIN_ELSE:
18014 case PM_CONTEXT_BLOCK_ELSE:
18015 case PM_CONTEXT_CLASS_ELSE:
18016 case PM_CONTEXT_DEF_ELSE:
18017 case PM_CONTEXT_LAMBDA_ELSE:
18018 case PM_CONTEXT_MODULE_ELSE:
18019 case PM_CONTEXT_SCLASS_ELSE:
18022 context = CONTEXT_THROUGH_ELSE;
18024 case PM_CONTEXT_BEGIN_ENSURE:
18025 case PM_CONTEXT_BLOCK_ENSURE:
18026 case PM_CONTEXT_CLASS_ENSURE:
18027 case PM_CONTEXT_DEF_ENSURE:
18028 case PM_CONTEXT_LAMBDA_ENSURE:
18029 case PM_CONTEXT_MODULE_ENSURE:
18030 case PM_CONTEXT_SCLASS_ENSURE:
18033 context = CONTEXT_THROUGH_ENSURE;
18035 case PM_CONTEXT_NONE:
18037 assert(
false &&
"unreachable");
18039 case PM_CONTEXT_BEGIN:
18040 case PM_CONTEXT_BLOCK_BRACES:
18041 case PM_CONTEXT_BLOCK_KEYWORDS:
18042 case PM_CONTEXT_BLOCK_PARAMETERS:
18043 case PM_CONTEXT_CASE_IN:
18044 case PM_CONTEXT_CASE_WHEN:
18045 case PM_CONTEXT_DEFAULT_PARAMS:
18046 case PM_CONTEXT_ELSE:
18047 case PM_CONTEXT_ELSIF:
18048 case PM_CONTEXT_EMBEXPR:
18049 case PM_CONTEXT_FOR_INDEX:
18050 case PM_CONTEXT_FOR:
18051 case PM_CONTEXT_IF:
18052 case PM_CONTEXT_LAMBDA_BRACES:
18053 case PM_CONTEXT_LAMBDA_DO_END:
18054 case PM_CONTEXT_LOOP_PREDICATE:
18055 case PM_CONTEXT_MULTI_TARGET:
18056 case PM_CONTEXT_PARENS:
18057 case PM_CONTEXT_POSTEXE:
18058 case PM_CONTEXT_PREDICATE:
18059 case PM_CONTEXT_TERNARY:
18060 case PM_CONTEXT_UNLESS:
18061 case PM_CONTEXT_UNTIL:
18062 case PM_CONTEXT_WHILE:
18068 context_node = context_node->prev;
18072#undef CONTEXT_ENSURE
18083 while (context_node != NULL) {
18084 switch (context_node->context) {
18085 case PM_CONTEXT_DEF:
18086 case PM_CONTEXT_DEF_PARAMS:
18087 case PM_CONTEXT_DEFINED:
18088 case PM_CONTEXT_DEF_ENSURE:
18089 case PM_CONTEXT_DEF_RESCUE:
18090 case PM_CONTEXT_DEF_ELSE:
18094 case PM_CONTEXT_CLASS:
18095 case PM_CONTEXT_CLASS_ENSURE:
18096 case PM_CONTEXT_CLASS_RESCUE:
18097 case PM_CONTEXT_CLASS_ELSE:
18098 case PM_CONTEXT_MAIN:
18099 case PM_CONTEXT_MODULE:
18100 case PM_CONTEXT_MODULE_ENSURE:
18101 case PM_CONTEXT_MODULE_RESCUE:
18102 case PM_CONTEXT_MODULE_ELSE:
18103 case PM_CONTEXT_SCLASS:
18104 case PM_CONTEXT_SCLASS_RESCUE:
18105 case PM_CONTEXT_SCLASS_ENSURE:
18106 case PM_CONTEXT_SCLASS_ELSE:
18109 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
18111 case PM_CONTEXT_NONE:
18113 assert(
false &&
"unreachable");
18115 case PM_CONTEXT_BEGIN:
18116 case PM_CONTEXT_BEGIN_ELSE:
18117 case PM_CONTEXT_BEGIN_ENSURE:
18118 case PM_CONTEXT_BEGIN_RESCUE:
18119 case PM_CONTEXT_BLOCK_BRACES:
18120 case PM_CONTEXT_BLOCK_KEYWORDS:
18121 case PM_CONTEXT_BLOCK_ELSE:
18122 case PM_CONTEXT_BLOCK_ENSURE:
18123 case PM_CONTEXT_BLOCK_PARAMETERS:
18124 case PM_CONTEXT_BLOCK_RESCUE:
18125 case PM_CONTEXT_CASE_IN:
18126 case PM_CONTEXT_CASE_WHEN:
18127 case PM_CONTEXT_DEFAULT_PARAMS:
18128 case PM_CONTEXT_ELSE:
18129 case PM_CONTEXT_ELSIF:
18130 case PM_CONTEXT_EMBEXPR:
18131 case PM_CONTEXT_FOR_INDEX:
18132 case PM_CONTEXT_FOR:
18133 case PM_CONTEXT_IF:
18134 case PM_CONTEXT_LAMBDA_BRACES:
18135 case PM_CONTEXT_LAMBDA_DO_END:
18136 case PM_CONTEXT_LAMBDA_ELSE:
18137 case PM_CONTEXT_LAMBDA_ENSURE:
18138 case PM_CONTEXT_LAMBDA_RESCUE:
18139 case PM_CONTEXT_LOOP_PREDICATE:
18140 case PM_CONTEXT_MULTI_TARGET:
18141 case PM_CONTEXT_PARENS:
18142 case PM_CONTEXT_POSTEXE:
18143 case PM_CONTEXT_PREDICATE:
18144 case PM_CONTEXT_PREEXE:
18145 case PM_CONTEXT_RESCUE_MODIFIER:
18146 case PM_CONTEXT_TERNARY:
18147 case PM_CONTEXT_UNLESS:
18148 case PM_CONTEXT_UNTIL:
18149 case PM_CONTEXT_WHILE:
18155 context_node = context_node->prev;
18164parse_case(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18165 size_t opening_newline_index = token_newline_index(parser);
18166 parser_lex(parser);
18172 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18174 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18175 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18177 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18179 }
else if (!token_begins_expression_p(parser->current.type)) {
18182 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));
18183 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18186 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18187 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18188 parser_lex(parser);
18189 pop_block_exits(parser, previous_block_exits);
18190 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18191 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->previous));
18198 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18199 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
18205 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18206 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18207 parser_lex(parser);
18210 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18213 if (accept1(parser, PM_TOKEN_USTAR)) {
18215 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));
18217 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18218 pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
18220 if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE))
break;
18222 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));
18223 pm_when_node_conditions_append(parser->arena, when_node, condition);
18227 if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE))
break;
18231 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18232 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18233 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE) && parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
18234 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18237 pm_when_clause_static_literals_add(parser, &literals, condition);
18239 }
while (accept1(parser, PM_TOKEN_COMMA));
18241 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18242 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18243 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18246 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18247 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18250 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18251 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18252 if (statements != NULL) {
18253 pm_when_node_statements_set(when_node, statements);
18257 pm_case_node_condition_append(parser->arena, case_node, UP(when_node));
18263 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18266 pm_static_literals_free(&literals);
18267 node = UP(case_node);
18269 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
18273 if (predicate == NULL) {
18274 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18279 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18280 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18282 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
18283 parser->pattern_matching_newlines =
true;
18285 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18286 parser->command_start =
false;
18287 parser_lex(parser);
18292 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));
18294 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
18299 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18301 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));
18302 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18303 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18305 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));
18306 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18313 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18314 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18315 then_keyword = parser->previous;
18318 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18319 then_keyword = parser->previous;
18325 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18328 statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
18333 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
18334 pm_case_match_node_condition_append(parser->arena, case_node, condition);
18340 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18343 node = UP(case_node);
18346 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18347 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18351 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18352 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
18354 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
18357 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18358 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18364 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18365 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18367 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18368 pm_case_node_end_keyword_loc_set(parser, (
pm_case_node_t *) node, &parser->previous);
18370 pm_case_match_node_end_keyword_loc_set(parser, (
pm_case_match_node_t *) node, &parser->previous);
18373 pop_block_exits(parser, previous_block_exits);
18382parse_class(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18383 size_t opening_newline_index = token_newline_index(parser);
18384 parser_lex(parser);
18386 pm_token_t class_keyword = parser->previous;
18387 pm_do_loop_stack_push(parser,
false);
18390 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18392 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18394 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));
18396 pm_parser_scope_push(parser,
true);
18397 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18398 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
18402 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18403 pm_accepts_block_stack_push(parser,
true);
18404 statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18405 pm_accepts_block_stack_pop(parser);
18408 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18409 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18410 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)));
18412 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18415 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18418 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18420 pm_parser_scope_pop(parser);
18421 pm_do_loop_stack_pop(parser);
18423 flush_block_exits(parser, previous_block_exits);
18424 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->previous));
18427 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));
18429 if (name.
type != PM_TOKEN_CONSTANT) {
18430 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18436 if (match1(parser, PM_TOKEN_LESS)) {
18437 inheritance_operator = parser->current;
18438 lex_state_set(parser, PM_LEX_STATE_BEG);
18440 parser->command_start =
true;
18441 parser_lex(parser);
18443 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));
18448 pm_parser_scope_push(parser,
true);
18450 if (inheritance_operator.
start != NULL) {
18451 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18453 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18457 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18458 pm_accepts_block_stack_push(parser,
true);
18459 statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18460 pm_accepts_block_stack_pop(parser);
18463 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18464 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18465 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)));
18467 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18470 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18472 if (context_def_p(parser)) {
18473 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18477 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18479 pm_parser_scope_pop(parser);
18480 pm_do_loop_stack_pop(parser);
18482 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18483 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18484 if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18485 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18489 pop_block_exits(parser, previous_block_exits);
18490 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
18497parse_def(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
18499 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18502 size_t opening_newline_index = token_newline_index(parser);
18510 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18511 parser_lex(parser);
18515 bool valid_name =
true;
18517 switch (parser->current.type) {
18518 case PM_CASE_OPERATOR:
18519 pm_parser_scope_push(parser,
true);
18520 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18521 parser_lex(parser);
18523 name = parser->previous;
18525 case PM_TOKEN_IDENTIFIER: {
18526 parser_lex(parser);
18528 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18529 receiver = parse_variable_call(parser);
18531 pm_parser_scope_push(parser,
true);
18532 lex_state_set(parser, PM_LEX_STATE_FNAME);
18533 parser_lex(parser);
18535 operator = parser->previous;
18536 name = parse_method_definition_name(parser);
18538 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
18539 pm_parser_scope_push(parser,
true);
18541 name = parser->previous;
18546 case PM_TOKEN_INSTANCE_VARIABLE:
18547 case PM_TOKEN_CLASS_VARIABLE:
18548 case PM_TOKEN_GLOBAL_VARIABLE:
18549 valid_name =
false;
18551 case PM_TOKEN_CONSTANT:
18552 case PM_TOKEN_KEYWORD_NIL:
18553 case PM_TOKEN_KEYWORD_SELF:
18554 case PM_TOKEN_KEYWORD_TRUE:
18555 case PM_TOKEN_KEYWORD_FALSE:
18556 case PM_TOKEN_KEYWORD___FILE__:
18557 case PM_TOKEN_KEYWORD___LINE__:
18558 case PM_TOKEN_KEYWORD___ENCODING__: {
18559 pm_parser_scope_push(parser,
true);
18560 parser_lex(parser);
18564 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18565 lex_state_set(parser, PM_LEX_STATE_FNAME);
18566 parser_lex(parser);
18567 operator = parser->previous;
18569 switch (identifier.
type) {
18570 case PM_TOKEN_CONSTANT:
18571 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18573 case PM_TOKEN_INSTANCE_VARIABLE:
18574 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18576 case PM_TOKEN_CLASS_VARIABLE:
18577 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18579 case PM_TOKEN_GLOBAL_VARIABLE:
18580 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18582 case PM_TOKEN_KEYWORD_NIL:
18583 receiver = UP(pm_nil_node_create(parser, &identifier));
18585 case PM_TOKEN_KEYWORD_SELF:
18586 receiver = UP(pm_self_node_create(parser, &identifier));
18588 case PM_TOKEN_KEYWORD_TRUE:
18589 receiver = UP(pm_true_node_create(parser, &identifier));
18591 case PM_TOKEN_KEYWORD_FALSE:
18592 receiver = UP(pm_false_node_create(parser, &identifier));
18594 case PM_TOKEN_KEYWORD___FILE__:
18595 receiver = UP(pm_source_file_node_create(parser, &identifier));
18597 case PM_TOKEN_KEYWORD___LINE__:
18598 receiver = UP(pm_source_line_node_create(parser, &identifier));
18600 case PM_TOKEN_KEYWORD___ENCODING__:
18601 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18607 name = parse_method_definition_name(parser);
18610 PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.
type));
18617 case PM_TOKEN_PARENTHESIS_LEFT: {
18621 context_pop(parser);
18622 parser_lex(parser);
18625 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));
18627 accept1(parser, PM_TOKEN_NEWLINE);
18628 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18631 lex_state_set(parser, PM_LEX_STATE_FNAME);
18632 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18634 operator = parser->previous;
18635 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18639 pm_parser_scope_push(parser,
true);
18640 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18641 name = parse_method_definition_name(parser);
18645 pm_parser_scope_push(parser,
true);
18646 name = parse_method_definition_name(parser);
18654 bool accept_endless_def =
true;
18655 switch (parser->current.type) {
18656 case PM_TOKEN_PARENTHESIS_LEFT: {
18657 parser_lex(parser);
18658 lparen = parser->previous;
18660 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18664 bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
18665 params = parse_parameters(
18667 PM_BINDING_POWER_DEFINED,
18669 allow_trailing_comma,
18673 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18674 (uint16_t) (depth + 1)
18678 lex_state_set(parser, PM_LEX_STATE_BEG);
18679 parser->command_start =
true;
18681 context_pop(parser);
18682 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18683 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
18684 parser->previous.
start = parser->previous.
end;
18685 parser->previous.
type = 0;
18688 rparen = parser->previous;
18691 case PM_CASE_PARAMETER: {
18694 if (parser->current.type == PM_TOKEN_LABEL) {
18695 lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
18698 params = parse_parameters(
18700 PM_BINDING_POWER_DEFINED,
18706 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18707 (uint16_t) (depth + 1)
18712 accept_endless_def =
false;
18714 context_pop(parser);
18719 context_pop(parser);
18728 if (accept1(parser, PM_TOKEN_EQUAL)) {
18729 if (token_is_setter_name(&name)) {
18730 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18732 if (!accept_endless_def) {
18733 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18736 parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
18737 parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
18739 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");
18741 equal = parser->previous;
18743 context_push(parser, PM_CONTEXT_DEF);
18744 pm_do_loop_stack_push(parser,
false);
18745 statements = UP(pm_statements_node_create(parser));
18747 uint8_t allow_flags;
18748 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
18749 allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
18753 allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18766 pm_accepts_block_stack_push(parser,
true);
18767 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));
18774 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18775 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18776 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18783 while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18784 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18786 pm_token_t rescue_keyword = parser->previous;
18790 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));
18791 context_pop(parser);
18793 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18796 pm_accepts_block_stack_pop(parser);
18801 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(parser, statement)) {
18802 PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18805 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18806 pm_do_loop_stack_pop(parser);
18807 context_pop(parser);
18809 if (lparen.
start == NULL) {
18810 lex_state_set(parser, PM_LEX_STATE_BEG);
18811 parser->command_start =
true;
18812 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18814 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18817 pm_accepts_block_stack_push(parser,
true);
18818 pm_do_loop_stack_push(parser,
false);
18820 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18821 pm_accepts_block_stack_push(parser,
true);
18822 statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18823 pm_accepts_block_stack_pop(parser);
18826 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18827 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18828 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)));
18830 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18833 pm_accepts_block_stack_pop(parser);
18834 pm_do_loop_stack_pop(parser);
18836 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18837 end_keyword = parser->previous;
18841 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18842 pm_parser_scope_pop(parser);
18847 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
18849 flush_block_exits(parser, previous_block_exits);
18851 return UP(pm_def_node_create(
18860 NTOK2PTR(
operator),
18864 NTOK2PTR(end_keyword)
18872parse_module(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18874 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18876 size_t opening_newline_index = token_newline_index(parser);
18877 parser_lex(parser);
18878 pm_token_t module_keyword = parser->previous;
18880 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));
18885 if (PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18886 pop_block_exits(parser, previous_block_exits);
18889 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
18892 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
18895 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18896 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
18902 name = parser->previous;
18903 if (name.
type != PM_TOKEN_CONSTANT) {
18904 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
18907 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)) {
18908 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18911 pm_parser_scope_push(parser,
true);
18912 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
18915 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18916 pm_accepts_block_stack_push(parser,
true);
18917 statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
18918 pm_accepts_block_stack_pop(parser);
18921 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18922 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18923 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)));
18925 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
18929 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18931 pm_parser_scope_pop(parser);
18932 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
18934 if (context_def_p(parser)) {
18935 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
18938 pop_block_exits(parser, previous_block_exits);
18940 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
18947parse_string_array(
pm_parser_t *parser, uint16_t depth) {
18948 parser_lex(parser);
18956 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
18957 switch (parser->current.type) {
18958 case PM_TOKEN_WORDS_SEP: {
18961 parser->explicit_encoding = NULL;
18963 if (current == NULL) {
18970 pm_array_node_elements_append(parser->arena, array, current);
18974 parser_lex(parser);
18977 case PM_TOKEN_STRING_CONTENT: {
18978 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
18979 pm_node_flag_set(
string, parse_unescaped_encoding(parser, parser->explicit_encoding));
18980 parser_lex(parser);
18982 if (current == NULL) {
18988 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
18993 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
18999 pm_interpolated_string_node_append(parser, interpolated, current);
19000 pm_interpolated_string_node_append(parser, interpolated,
string);
19001 current = UP(interpolated);
19003 assert(
false &&
"unreachable");
19008 case PM_TOKEN_EMBVAR: {
19009 if (current == NULL) {
19013 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19014 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19020 pm_interpolated_string_node_append(parser, interpolated, current);
19021 current = UP(interpolated);
19028 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19032 case PM_TOKEN_EMBEXPR_BEGIN: {
19033 if (current == NULL) {
19037 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19038 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19044 pm_interpolated_string_node_append(parser, interpolated, current);
19045 current = UP(interpolated);
19046 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19050 assert(
false &&
"unreachable");
19053 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19058 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19059 parser_lex(parser);
19066 pm_array_node_elements_append(parser->arena, array, current);
19070 if (match1(parser, PM_TOKEN_EOF)) {
19071 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19072 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19074 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19077 pm_array_node_close_set(parser, array, &closing);
19085parse_symbol_array(
pm_parser_t *parser, uint16_t depth) {
19086 parser_lex(parser);
19094 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19095 switch (parser->current.type) {
19096 case PM_TOKEN_WORDS_SEP: {
19099 parser->explicit_encoding = NULL;
19101 if (current == NULL) {
19108 pm_array_node_elements_append(parser->arena, array, current);
19112 parser_lex(parser);
19115 case PM_TOKEN_STRING_CONTENT: {
19116 if (current == NULL) {
19121 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
19122 parser_lex(parser);
19123 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19127 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
19128 parser_lex(parser);
19131 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19138 .
type = PM_TOKEN_STRING_CONTENT,
19143 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
19144 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
19145 parser_lex(parser);
19148 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
19149 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
19151 current = UP(interpolated);
19153 assert(
false &&
"unreachable");
19158 case PM_TOKEN_EMBVAR: {
19159 bool start_location_set =
false;
19160 if (current == NULL) {
19164 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19165 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19172 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19173 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
19174 PM_NODE_START_SET_NODE(interpolated, current);
19175 start_location_set =
true;
19176 current = UP(interpolated);
19183 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19185 if (!start_location_set) {
19186 PM_NODE_START_SET_NODE(current, part);
19190 case PM_TOKEN_EMBEXPR_BEGIN: {
19191 bool start_location_set =
false;
19192 if (current == NULL) {
19196 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19197 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19204 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19205 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
19206 PM_NODE_START_SET_NODE(interpolated, current);
19207 start_location_set =
true;
19208 current = UP(interpolated);
19209 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19213 assert(
false &&
"unreachable");
19216 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19218 if (!start_location_set) {
19219 PM_NODE_START_SET_NODE(current, part);
19224 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19225 parser_lex(parser);
19232 pm_array_node_elements_append(parser->arena, array, current);
19236 if (match1(parser, PM_TOKEN_EOF)) {
19237 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19238 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19240 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19242 pm_array_node_close_set(parser, array, &closing);
19252parse_parentheses(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19254 pm_node_flags_t paren_flags = 0;
19257 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19259 parser_lex(parser);
19261 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19262 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19263 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19270 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
19274 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT) && opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19275 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19278 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19279 pop_block_exits(parser, previous_block_exits);
19280 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
19285 context_push(parser, PM_CONTEXT_PARENS);
19286 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));
19287 context_pop(parser);
19292 bool terminator_found =
false;
19294 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19295 terminator_found =
true;
19296 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19297 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
19298 terminator_found =
true;
19301 if (terminator_found) {
19303 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19304 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19305 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19313 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19314 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19315 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19318 parser_lex(parser);
19319 pop_block_exits(parser, previous_block_exits);
19321 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19327 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
19330 multi_target = pm_multi_target_node_create(parser);
19331 pm_multi_target_node_targets_append(parser, multi_target, statement);
19334 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
19335 multi_target->
rparen_loc = TOK2LOC(parser, &parser->previous);
19336 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
19337 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
19340 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
19341 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19342 accept1(parser, PM_TOKEN_NEWLINE);
19344 result = UP(multi_target);
19347 if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
19349 }
else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match2(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_COMMA)) {
19353 }
else if (flags & PM_PARSE_ACCEPTS_STATEMENT) {
19357 if (pm_binding_powers[parser->current.type].binary && !match1(parser, PM_TOKEN_EQUAL)) {
19358 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19360 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
19363 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19364 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
19367 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19377 pm_statements_node_body_append(parser, statements, statement,
true);
19379 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19385 context_push(parser, PM_CONTEXT_PARENS);
19386 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19389 pm_statements_node_body_append(parser, statements, statement,
true);
19393 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
19394 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19399 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));
19400 pm_statements_node_body_append(parser, statements, node,
true);
19404 if (parser->recovering) {
19407 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering =
false;
19413 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE))
break;
19417 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19418 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
19419 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
19420 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19422 }
else if (!match1(parser, PM_TOKEN_EOF)) {
19425 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19429 context_pop(parser);
19430 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19439 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19441 pm_multi_target_node_targets_append(parser, multi_target, statement);
19443 statement = UP(multi_target);
19447 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
19448 const uint8_t *offset = parser->start + PM_NODE_END(statement);
19449 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
19450 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
19452 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
19455 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
19459 pop_block_exits(parser, previous_block_exits);
19460 pm_void_statements_check(parser, statements,
true);
19461 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19470parse_splat(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19474 if (token_begins_expression_p(parser->current.type)) {
19475 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19478 return UP(pm_splat_node_create(parser, &
operator, name));
19485parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
19486 switch (parser->current.type) {
19487 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
19488 parser_lex(parser);
19490 pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
19491 bool parsed_bare_hash =
false;
19493 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
19494 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
19498 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19504 if (accept1(parser, PM_TOKEN_COMMA)) {
19507 if (accepted_newline) {
19508 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
19513 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
19514 parser->previous.
start = parser->previous.
end;
19515 parser->previous.
type = 0;
19522 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
19526 if (accept1(parser, PM_TOKEN_USTAR)) {
19530 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
19531 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
19533 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));
19536 element = UP(pm_splat_node_create(parser, &
operator, expression));
19537 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
19538 if (parsed_bare_hash) {
19539 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
19542 element = UP(pm_keyword_hash_node_create(parser));
19545 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)) {
19546 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19549 pm_static_literals_free(&hash_keys);
19550 parsed_bare_hash =
true;
19552 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));
19554 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
19555 if (parsed_bare_hash) {
19556 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
19561 pm_hash_key_static_literals_add(parser, &hash_keys, element);
19564 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
19565 operator = parser->previous;
19568 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));
19569 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(
operator), value));
19570 pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
19572 element = UP(hash);
19573 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19574 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19577 pm_static_literals_free(&hash_keys);
19578 parsed_bare_hash =
true;
19582 pm_array_node_elements_append(parser->arena, array, element);
19583 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
19586 accept1(parser, PM_TOKEN_NEWLINE);
19588 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19589 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
19590 parser->previous.
start = parser->previous.
end;
19591 parser->previous.
type = 0;
19594 pm_array_node_close_set(parser, array, &parser->previous);
19598 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
19599 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
19600 return parse_parentheses(parser, binding_power, flags, depth);
19601 case PM_TOKEN_BRACE_LEFT_HASH: {
19602 parser_lex(parser);
19607 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
19609 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
19610 pm_static_literals_free(&hash_keys);
19612 accept1(parser, PM_TOKEN_NEWLINE);
19615 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
19616 pm_hash_node_closing_loc_set(parser, node, &parser->previous);
19620 case PM_TOKEN_CHARACTER_LITERAL: {
19621 pm_node_t *node = UP(pm_string_node_create_current_string(
19624 .type = PM_TOKEN_STRING_BEGIN,
19625 .start = parser->current.start,
19626 .end = parser->current.start + 1
19629 .type = PM_TOKEN_STRING_CONTENT,
19630 .start = parser->current.start + 1,
19631 .end = parser->current.end
19636 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
19640 parser_lex(parser);
19644 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19645 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19650 case PM_TOKEN_CLASS_VARIABLE: {
19651 parser_lex(parser);
19652 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->previous));
19654 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19655 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19660 case PM_TOKEN_CONSTANT: {
19661 parser_lex(parser);
19667 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
19668 ((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))) ||
19669 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19670 match1(parser, PM_TOKEN_BRACE_LEFT)
19673 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19674 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
19677 pm_node_t *node = UP(pm_constant_read_node_create(parser, &parser->previous));
19679 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19682 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19687 case PM_TOKEN_UCOLON_COLON: {
19688 parser_lex(parser);
19691 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19692 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous));
19694 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19695 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19700 case PM_TOKEN_UDOT_DOT:
19701 case PM_TOKEN_UDOT_DOT_DOT: {
19703 parser_lex(parser);
19705 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));
19711 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
19712 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
19715 return UP(pm_range_node_create(parser, NULL, &
operator, right));
19717 case PM_TOKEN_FLOAT:
19718 parser_lex(parser);
19719 return UP(pm_float_node_create(parser, &parser->previous));
19720 case PM_TOKEN_FLOAT_IMAGINARY:
19721 parser_lex(parser);
19722 return UP(pm_float_node_imaginary_create(parser, &parser->previous));
19723 case PM_TOKEN_FLOAT_RATIONAL:
19724 parser_lex(parser);
19725 return UP(pm_float_node_rational_create(parser, &parser->previous));
19726 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
19727 parser_lex(parser);
19728 return UP(pm_float_node_rational_imaginary_create(parser, &parser->previous));
19729 case PM_TOKEN_NUMBERED_REFERENCE: {
19730 parser_lex(parser);
19731 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
19733 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19734 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19739 case PM_TOKEN_GLOBAL_VARIABLE: {
19740 parser_lex(parser);
19741 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->previous));
19743 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19744 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19749 case PM_TOKEN_BACK_REFERENCE: {
19750 parser_lex(parser);
19751 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->previous));
19753 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19754 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19759 case PM_TOKEN_IDENTIFIER:
19760 case PM_TOKEN_METHOD_NAME: {
19761 parser_lex(parser);
19763 pm_node_t *node = parse_variable_call(parser);
19765 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
19773 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
19776 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
19785 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
19787 PM_NODE_LENGTH_SET_LOCATION(call, end);
19795 ((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))) ||
19796 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19797 match1(parser, PM_TOKEN_BRACE_LEFT)
19800 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19801 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
19803 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
19807 pm_node_unreference(parser, node);
19813 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
19815 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
19816 pm_node_unreference(parser, node);
19819 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
19827 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19828 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19833 case PM_TOKEN_HEREDOC_START: {
19836 assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
19839 size_t common_whitespace = (size_t) -1;
19840 parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
19842 parser_lex(parser);
19848 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19851 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19852 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
19854 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19855 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19857 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19860 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
19861 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
19868 node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19869 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19874 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
19878 cast->
closing_loc = TOK2LOC(parser, &parser->current);
19881 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19883 cast->
base.
type = PM_X_STRING_NODE;
19886 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19887 parse_heredoc_dedent_string(parser->arena, &cast->
unescaped, common_whitespace);
19891 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19897 pm_node_list_append(parser->arena, &parts, part);
19899 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19900 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19901 pm_node_list_append(parser->arena, &parts, part);
19907 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19909 cast->
parts = parts;
19911 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19912 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
19919 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19920 pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
19928 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19930 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19936 parse_heredoc_dedent(parser, nodes, common_whitespace);
19944 pm_lex_mode_t *whitespace_mode = parser->lex_modes.current;
19946 if (whitespace_mode->mode == PM_LEX_HEREDOC && whitespace_mode->as.heredoc.common_whitespace == &common_whitespace) {
19947 whitespace_mode->as.heredoc.common_whitespace = NULL;
19949 whitespace_mode = whitespace_mode->prev;
19950 }
while (whitespace_mode != NULL);
19952 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19953 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19958 case PM_TOKEN_INSTANCE_VARIABLE: {
19959 parser_lex(parser);
19960 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
19962 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19963 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19968 case PM_TOKEN_INTEGER: {
19969 pm_node_flags_t base = parser->integer.base;
19970 parser_lex(parser);
19971 return UP(pm_integer_node_create(parser, base, &parser->previous));
19973 case PM_TOKEN_INTEGER_IMAGINARY: {
19974 pm_node_flags_t base = parser->integer.base;
19975 parser_lex(parser);
19976 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
19978 case PM_TOKEN_INTEGER_RATIONAL: {
19979 pm_node_flags_t base = parser->integer.base;
19980 parser_lex(parser);
19981 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
19983 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
19984 pm_node_flags_t base = parser->integer.base;
19985 parser_lex(parser);
19986 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
19988 case PM_TOKEN_KEYWORD___ENCODING__:
19989 parser_lex(parser);
19990 return UP(pm_source_encoding_node_create(parser, &parser->previous));
19991 case PM_TOKEN_KEYWORD___FILE__:
19992 parser_lex(parser);
19993 return UP(pm_source_file_node_create(parser, &parser->previous));
19994 case PM_TOKEN_KEYWORD___LINE__:
19995 parser_lex(parser);
19996 return UP(pm_source_line_node_create(parser, &parser->previous));
19997 case PM_TOKEN_KEYWORD_ALIAS: {
19998 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
19999 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
20002 parser_lex(parser);
20005 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
20006 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
20008 switch (PM_NODE_TYPE(new_name)) {
20009 case PM_BACK_REFERENCE_READ_NODE:
20010 case PM_NUMBERED_REFERENCE_READ_NODE:
20011 case PM_GLOBAL_VARIABLE_READ_NODE: {
20012 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)) {
20013 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
20014 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
20016 }
else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
20017 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
20018 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
20021 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
20023 case PM_SYMBOL_NODE:
20024 case PM_INTERPOLATED_SYMBOL_NODE: {
20025 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)) {
20026 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
20027 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
20032 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
20035 case PM_TOKEN_KEYWORD_CASE:
20036 return parse_case(parser, flags, depth);
20037 case PM_TOKEN_KEYWORD_BEGIN: {
20038 size_t opening_newline_index = token_newline_index(parser);
20039 parser_lex(parser);
20041 pm_token_t begin_keyword = parser->previous;
20042 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20045 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20048 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
20049 pm_accepts_block_stack_push(parser,
true);
20050 begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
20051 pm_accepts_block_stack_pop(parser);
20052 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20055 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
20056 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
20057 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
20059 PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->previous);
20060 pm_begin_node_end_keyword_set(parser, begin_node, &parser->previous);
20061 pop_block_exits(parser, previous_block_exits);
20062 return UP(begin_node);
20064 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
20066 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20068 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20069 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
20072 parser_lex(parser);
20075 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
20077 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
20079 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
20080 pm_context_t context = parser->current_context->context;
20081 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
20082 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
20085 flush_block_exits(parser, previous_block_exits);
20086 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
20088 case PM_TOKEN_KEYWORD_BREAK:
20089 case PM_TOKEN_KEYWORD_NEXT:
20090 case PM_TOKEN_KEYWORD_RETURN: {
20091 parser_lex(parser);
20097 token_begins_expression_p(parser->current.type) ||
20098 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
20100 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
20102 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
20104 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
20107 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
20108 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.
type));
20117 if (parser->previous.
type == PM_TOKEN_COMMA && match1(parser, PM_TOKEN_EOF)) {
20118 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
20125 if (arguments.
block != NULL) {
20126 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20127 pm_node_unreference(parser, arguments.
block);
20128 arguments.
block = NULL;
20132 switch (keyword.
type) {
20133 case PM_TOKEN_KEYWORD_BREAK: {
20135 if (!parser->partial_script) parse_block_exit(parser, node);
20138 case PM_TOKEN_KEYWORD_NEXT: {
20140 if (!parser->partial_script) parse_block_exit(parser, node);
20143 case PM_TOKEN_KEYWORD_RETURN: {
20145 parse_return(parser, node);
20149 assert(
false &&
"unreachable");
20150 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20153 case PM_TOKEN_KEYWORD_SUPER: {
20154 parser_lex(parser);
20158 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20163 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
20165 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
20168 return UP(pm_super_node_create(parser, &keyword, &arguments));
20170 case PM_TOKEN_KEYWORD_YIELD: {
20171 parser_lex(parser);
20175 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
20181 if (arguments.
block != NULL) {
20182 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20183 pm_node_unreference(parser, arguments.
block);
20184 arguments.
block = NULL;
20188 if (!parser->parsing_eval && !parser->partial_script) parse_yield(parser, node);
20192 case PM_TOKEN_KEYWORD_CLASS:
20193 return parse_class(parser, flags, depth);
20194 case PM_TOKEN_KEYWORD_DEF:
20195 return parse_def(parser, binding_power, flags, depth);
20196 case PM_TOKEN_KEYWORD_DEFINED: {
20197 parser_lex(parser);
20204 context_push(parser, PM_CONTEXT_DEFINED);
20205 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
20207 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20208 lparen = parser->previous;
20210 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20211 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20214 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));
20216 if (!parser->recovering) {
20217 accept1(parser, PM_TOKEN_NEWLINE);
20218 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20219 rparen = parser->previous;
20223 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
20226 context_pop(parser);
20227 return UP(pm_defined_node_create(
20235 case PM_TOKEN_KEYWORD_END_UPCASE: {
20236 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20237 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
20240 parser_lex(parser);
20243 if (context_def_p(parser)) {
20244 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
20247 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
20249 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
20251 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
20252 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
20254 case PM_TOKEN_KEYWORD_FALSE:
20255 parser_lex(parser);
20256 return UP(pm_false_node_create(parser, &parser->previous));
20257 case PM_TOKEN_KEYWORD_FOR: {
20258 size_t opening_newline_index = token_newline_index(parser);
20259 parser_lex(parser);
20264 context_push(parser, PM_CONTEXT_FOR_INDEX);
20267 if (accept1(parser, PM_TOKEN_USTAR)) {
20268 index = parse_splat(parser, flags, depth);
20269 }
else if (token_begins_expression_p(parser->current.type)) {
20270 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
20272 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
20273 index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
20277 if (match1(parser, PM_TOKEN_COMMA)) {
20278 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20280 index = parse_target(parser, index,
false,
false);
20283 context_pop(parser);
20284 pm_do_loop_stack_push(parser,
true);
20286 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
20289 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));
20290 pm_do_loop_stack_pop(parser);
20293 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20294 do_keyword = parser->previous;
20296 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
20297 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
20302 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20303 statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
20306 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
20307 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
20309 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous));
20311 case PM_TOKEN_KEYWORD_IF:
20312 if (parser_end_of_line_p(parser)) {
20313 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
20316 size_t opening_newline_index = token_newline_index(parser);
20317 bool if_after_else = parser->previous.
type == PM_TOKEN_KEYWORD_ELSE;
20318 parser_lex(parser);
20320 return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
20321 case PM_TOKEN_KEYWORD_UNDEF: {
20322 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20323 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
20326 parser_lex(parser);
20327 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
20328 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20330 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20332 pm_undef_node_append(parser->arena, undef, name);
20334 while (match1(parser, PM_TOKEN_COMMA)) {
20335 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
20336 parser_lex(parser);
20337 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20339 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20343 pm_undef_node_append(parser->arena, undef, name);
20349 case PM_TOKEN_KEYWORD_NOT: {
20350 parser_lex(parser);
20363 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
20364 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
20365 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
20367 accept1(parser, PM_TOKEN_NEWLINE);
20368 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
20371 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
20374 accept1(parser, PM_TOKEN_NEWLINE);
20376 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20379 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20380 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20382 arguments.
opening_loc = TOK2LOC(parser, &lparen);
20383 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));
20385 if (!parser->recovering) {
20386 accept1(parser, PM_TOKEN_NEWLINE);
20387 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20388 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
20392 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));
20395 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
20397 case PM_TOKEN_KEYWORD_UNLESS: {
20398 size_t opening_newline_index = token_newline_index(parser);
20399 parser_lex(parser);
20401 return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
20403 case PM_TOKEN_KEYWORD_MODULE:
20404 return parse_module(parser, flags, depth);
20405 case PM_TOKEN_KEYWORD_NIL:
20406 parser_lex(parser);
20407 return UP(pm_nil_node_create(parser, &parser->previous));
20408 case PM_TOKEN_KEYWORD_REDO: {
20409 parser_lex(parser);
20411 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
20412 if (!parser->partial_script) parse_block_exit(parser, node);
20416 case PM_TOKEN_KEYWORD_RETRY: {
20417 parser_lex(parser);
20419 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
20420 parse_retry(parser, node);
20424 case PM_TOKEN_KEYWORD_SELF:
20425 parser_lex(parser);
20426 return UP(pm_self_node_create(parser, &parser->previous));
20427 case PM_TOKEN_KEYWORD_TRUE:
20428 parser_lex(parser);
20429 return UP(pm_true_node_create(parser, &parser->previous));
20430 case PM_TOKEN_KEYWORD_UNTIL: {
20431 size_t opening_newline_index = token_newline_index(parser);
20433 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20434 pm_do_loop_stack_push(parser,
true);
20436 parser_lex(parser);
20438 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));
20440 pm_do_loop_stack_pop(parser);
20441 context_pop(parser);
20444 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20445 do_keyword = parser->previous;
20447 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20451 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20452 pm_accepts_block_stack_push(parser,
true);
20453 statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20454 pm_accepts_block_stack_pop(parser);
20455 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20458 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20459 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
20461 return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20463 case PM_TOKEN_KEYWORD_WHILE: {
20464 size_t opening_newline_index = token_newline_index(parser);
20466 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20467 pm_do_loop_stack_push(parser,
true);
20469 parser_lex(parser);
20471 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));
20473 pm_do_loop_stack_pop(parser);
20474 context_pop(parser);
20477 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20478 do_keyword = parser->previous;
20480 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20484 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20485 pm_accepts_block_stack_push(parser,
true);
20486 statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20487 pm_accepts_block_stack_pop(parser);
20488 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20491 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20492 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
20494 return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20496 case PM_TOKEN_PERCENT_LOWER_I: {
20497 parser_lex(parser);
20502 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20503 accept1(parser, PM_TOKEN_WORDS_SEP);
20504 if (match1(parser, PM_TOKEN_STRING_END))
break;
20508 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20510 if (current == NULL) {
20511 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20512 parser_lex(parser);
20513 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20514 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20515 parser_lex(parser);
20517 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20520 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20521 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20522 parser_lex(parser);
20525 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20526 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20529 current = UP(interpolated);
20531 assert(
false &&
"unreachable");
20536 pm_array_node_elements_append(parser->arena, array, current);
20539 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20544 if (match1(parser, PM_TOKEN_EOF)) {
20545 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20546 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20548 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20550 pm_array_node_close_set(parser, array, &closing);
20554 case PM_TOKEN_PERCENT_UPPER_I:
20555 return parse_symbol_array(parser, depth);
20556 case PM_TOKEN_PERCENT_LOWER_W: {
20557 parser_lex(parser);
20562 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20563 accept1(parser, PM_TOKEN_WORDS_SEP);
20564 if (match1(parser, PM_TOKEN_STRING_END))
break;
20568 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20569 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20572 if (current == NULL) {
20574 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20576 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20578 pm_interpolated_string_node_append(parser, interpolated, current);
20579 pm_interpolated_string_node_append(parser, interpolated,
string);
20580 current = UP(interpolated);
20582 assert(
false &&
"unreachable");
20584 parser_lex(parser);
20588 pm_array_node_elements_append(parser->arena, array, current);
20591 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20596 if (match1(parser, PM_TOKEN_EOF)) {
20597 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20598 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20600 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20603 pm_array_node_close_set(parser, array, &closing);
20606 case PM_TOKEN_PERCENT_UPPER_W:
20607 return parse_string_array(parser, depth);
20608 case PM_TOKEN_REGEXP_BEGIN: {
20610 parser_lex(parser);
20612 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20617 .
type = PM_TOKEN_STRING_CONTENT,
20618 .start = parser->previous.
end,
20619 .end = parser->previous.
end
20622 parser_lex(parser);
20625 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20631 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20638 parser_lex(parser);
20643 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20650 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20651 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20659 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20661 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20662 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
20666 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20669 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20674 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20680 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20681 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20682 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20687 if (match1(parser, PM_TOKEN_EOF)) {
20688 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20689 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20691 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20694 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20695 return UP(interpolated);
20697 case PM_TOKEN_XSTRING_BEGIN:
20698 case PM_TOKEN_PERCENT_LOWER_X: {
20699 parser_lex(parser);
20706 if (match1(parser, PM_TOKEN_STRING_END)) {
20711 .
type = PM_TOKEN_STRING_CONTENT,
20712 .start = parser->previous.
end,
20713 .end = parser->previous.
end
20716 parser_lex(parser);
20717 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
20722 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20729 parser_lex(parser);
20731 if (match1(parser, PM_TOKEN_STRING_END)) {
20732 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
20733 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
20734 parser_lex(parser);
20740 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20742 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20743 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
20745 pm_interpolated_xstring_node_append(parser->arena, node, part);
20750 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20754 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20755 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20756 pm_interpolated_xstring_node_append(parser->arena, node, part);
20761 if (match1(parser, PM_TOKEN_EOF)) {
20762 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20763 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20765 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20767 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
20771 case PM_TOKEN_USTAR: {
20772 parser_lex(parser);
20777 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20778 pm_parser_err_prefix(parser, diag_id);
20779 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20782 pm_node_t *splat = parse_splat(parser, flags, depth);
20784 if (match1(parser, PM_TOKEN_COMMA)) {
20785 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20787 return parse_target_validate(parser, splat,
true);
20790 case PM_TOKEN_BANG: {
20791 if (binding_power > PM_BINDING_POWER_UNARY) {
20792 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20795 parser_lex(parser);
20798 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));
20799 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20801 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20804 case PM_TOKEN_TILDE: {
20805 if (binding_power > PM_BINDING_POWER_UNARY) {
20806 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20808 parser_lex(parser);
20811 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));
20812 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20816 case PM_TOKEN_UMINUS: {
20817 if (binding_power > PM_BINDING_POWER_UNARY) {
20818 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20820 parser_lex(parser);
20823 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));
20824 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20828 case PM_TOKEN_UMINUS_NUM: {
20829 parser_lex(parser);
20832 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));
20834 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20835 pm_token_t exponent_operator = parser->previous;
20836 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));
20837 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20838 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20840 switch (PM_NODE_TYPE(node)) {
20841 case PM_INTEGER_NODE:
20842 case PM_FLOAT_NODE:
20843 case PM_RATIONAL_NODE:
20844 case PM_IMAGINARY_NODE:
20845 parse_negative_numeric(node);
20848 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20855 case PM_TOKEN_MINUS_GREATER: {
20856 int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
20857 parser->lambda_enclosure_nesting = parser->enclosure_nesting;
20859 size_t opening_newline_index = token_newline_index(parser);
20860 parser_lex(parser);
20863 pm_parser_scope_push(parser,
false);
20867 switch (parser->current.type) {
20868 case PM_TOKEN_PARENTHESIS_LEFT: {
20870 parser_lex(parser);
20872 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20873 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20875 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20878 accept1(parser, PM_TOKEN_NEWLINE);
20879 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20881 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
20884 case PM_CASE_PARAMETER: {
20885 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
20889 block_parameters = NULL;
20897 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20898 opening = parser->previous;
20900 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20901 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
20904 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20912 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
20913 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20921 pm_accepts_block_stack_push(parser,
true);
20922 expect1(parser, PM_TOKEN_KEYWORD_DO_LAMBDA, PM_ERR_LAMBDA_OPEN);
20923 opening = parser->previous;
20929 parser->lambda_enclosure_nesting = -1;
20931 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20932 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
20935 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20936 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20937 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)));
20939 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20942 pm_accepts_block_stack_pop(parser);
20947 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
20948 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20952 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
20953 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->previous);
20955 pm_parser_scope_pop(parser);
20957 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->previous, parameters, body));
20959 case PM_TOKEN_UPLUS: {
20960 if (binding_power > PM_BINDING_POWER_UNARY) {
20961 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20963 parser_lex(parser);
20966 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));
20967 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20971 case PM_TOKEN_STRING_BEGIN:
20972 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
20973 case PM_TOKEN_SYMBOL_BEGIN: {
20975 parser_lex(parser);
20977 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20980 pm_context_t recoverable = context_recoverable(parser, &parser->current);
20982 if (recoverable != PM_CONTEXT_NONE) {
20983 parser->recovering =
true;
20988 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20989 pm_parser_err_prefix(parser, diag_id);
20995 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
20996 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
21000 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
21002 pm_parser_err_prefix(parser, diag_id);
21005 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
21011parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth);
21021parse_rescue_modifier_terminator(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
21022 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
21023 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21024 parser_lex(parser);
21025 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));
21039parse_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) {
21040 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));
21046 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(parser, value) || pm_block_call_p(value))) {
21047 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21048 parser_lex(parser);
21049 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));
21054 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21055 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21058 parser_lex(parser);
21063 bool statement_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21064 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21066 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21067 context_pop(parser);
21072 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21073 parse_rescue_modifier_terminator(parser, flags, depth);
21076 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21088 switch (PM_NODE_TYPE(node)) {
21089 case PM_BEGIN_NODE: {
21094 case PM_LOCAL_VARIABLE_WRITE_NODE: {
21096 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
21099 case PM_PARENTHESES_NODE: {
21101 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
21104 case PM_STATEMENTS_NODE: {
21109 parse_assignment_value_local(parser, statement);
21131parse_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) {
21132 bool statement_level = (previous_binding_power == PM_BINDING_POWER_STATEMENT) || (flags & PM_PARSE_ACCEPTS_STATEMENT);
21134 bool permitted =
true;
21135 if (!statement_level && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
21140 uint8_t command_call_flag = (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT)
21141 ? (uint8_t) (flags & PM_PARSE_ACCEPTS_COMMAND_CALL)
21142 : ((previous_binding_power < PM_BINDING_POWER_MODIFIER || statement_level) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0);
21144 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));
21145 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
21147 parse_assignment_value_local(parser, value);
21148 bool single_value =
true;
21153 if (statement_level && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
21154 single_value =
false;
21157 pm_array_node_elements_append(parser->arena, array, value);
21160 while (accept1(parser, PM_TOKEN_COMMA)) {
21161 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
21163 pm_array_node_elements_append(parser->arena, array, element);
21164 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
21166 parse_assignment_value_local(parser, element);
21174 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))) {
21175 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21176 parser_lex(parser);
21177 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));
21182 bool multiple_assignment = (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1));
21183 if ((single_value || multiple_assignment) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21184 bool command_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21193 if (multiple_assignment && command_value)
return value;
21195 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21198 parser_lex(parser);
21204 bool statement_value = multiple_assignment || command_value;
21205 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21207 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21208 context_pop(parser);
21213 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21214 parse_rescue_modifier_terminator(parser, flags, depth);
21217 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21236parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth) {
21241 if (match1(parser, PM_TOKEN_USTAR)) {
21243 parser_lex(parser);
21244 value = parse_splat(parser, flags, depth);
21251 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));
21252 multiple = match1(parser, PM_TOKEN_COMMA) || PM_NODE_TYPE_P(value, PM_MULTI_TARGET_NODE);
21256 pm_node_t *target = parse_targets_validate(parser, value, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21263 if (!match1(parser, PM_TOKEN_EQUAL)) {
21264 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
21269 parser_lex(parser);
21271 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));
21272 value = parse_write(parser, target, &
operator, values);
21279 if (!PM_NODE_TYPE_P(value, PM_MATCH_REQUIRED_NODE) && !PM_NODE_TYPE_P(value, PM_MATCH_PREDICATE_NODE)) {
21280 parse_rescue_modifier_terminator(parser, flags, depth);
21288 return parse_expression(parser, PM_BINDING_POWER_DEFINED, flags, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21301 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
21302 pm_node_unreference(parser, UP(call_node->
arguments));
21306 if (call_node->
block != NULL) {
21307 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
21308 pm_node_unreference(parser, UP(call_node->
block));
21309 call_node->
block = NULL;
21314pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21317 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21318 uint8_t value = escape_hexadecimal_digit(*cursor);
21321 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21322 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21326 pm_buffer_append_byte(unescaped, value);
21328 pm_buffer_append_string(unescaped,
"\\x", 2);
21335pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21336 uint8_t value = (uint8_t) (*cursor -
'0');
21339 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21340 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21343 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21344 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21349 pm_buffer_append_byte(unescaped, value);
21355 const uint8_t *start = cursor - 1;
21358 if (cursor >= end) {
21359 pm_buffer_append_string(unescaped,
"\\u", 2);
21363 if (*cursor !=
'{') {
21364 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21365 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21367 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21368 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21371 return cursor + length;
21376 while (cursor < end && *cursor ==
' ') cursor++;
21378 if (cursor >= end)
break;
21379 if (*cursor ==
'}') {
21384 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21388 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21390 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21398pm_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) {
21399 const uint8_t *end = source + length;
21400 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21403 if (++cursor >= end) {
21404 pm_buffer_append_byte(unescaped,
'\\');
21410 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21412 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21413 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21416 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
21419 pm_buffer_append_byte(unescaped,
'\\');
21423 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->encoding_changed, parser->encoding);
21424 if (next_cursor == NULL)
break;
21426 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21427 cursor = next_cursor;
21430 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21442 const uint8_t *source = pm_string_source(capture);
21443 size_t length = pm_string_length(capture);
21454 const uint8_t *cursor = pm_memchr(source,
'\\', length, parser->encoding_changed, parser->encoding);
21455 if (PRISM_UNLIKELY(cursor != NULL)) {
21456 pm_named_capture_escape(parser, &unescaped, source, length, cursor, shared ? NULL : &call->receiver->location);
21457 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21458 length = pm_buffer_length(&unescaped);
21461 const uint8_t *start;
21462 const uint8_t *end;
21467 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21468 pm_buffer_cleanup(&unescaped);
21476 end = source + length;
21477 name = pm_parser_constant_id_raw(parser, start, end);
21481 start = parser->start + PM_NODE_START(call->
receiver);
21482 end = parser->start + PM_NODE_END(call->
receiver);
21484 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
21485 memcpy(memory, source, length);
21486 name = pm_parser_constant_id_owned(parser, memory, length);
21491 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
21492 pm_constant_id_list_append(parser->arena, names, name);
21495 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21498 if (pm_local_is_keyword((
const char *) source, length)) {
21499 pm_buffer_cleanup(&unescaped);
21505 pm_parser_local_add(parser, name, start, end, 0);
21510 if (callback_data->match == NULL) {
21511 callback_data->match = pm_match_write_node_create(parser, call);
21516 pm_token_t token = { .type = 0, .start = start, .end = end };
21518 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &token_loc, name, depth == -1 ? 0 : (uint32_t) depth));
21519 pm_node_list_append(parser->arena, &callback_data->match->
targets, target);
21522 pm_buffer_cleanup(&unescaped);
21538 pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content),
false, extended_mode, parse_regular_expression_named_capture, &callback_data);
21540 if (callback_data.match != NULL) {
21541 return UP(callback_data.match);
21548parse_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) {
21551 switch (token.type) {
21552 case PM_TOKEN_EQUAL: {
21553 switch (PM_NODE_TYPE(node)) {
21554 case PM_CALL_NODE: {
21560 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21561 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
21565 case PM_CASE_WRITABLE: {
21569 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21570 pm_parser_local_add_location(parser, &node->
location, 0);
21573 parser_lex(parser);
21574 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));
21576 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
21577 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21580 return parse_write(parser, node, &token, value);
21582 case PM_SPLAT_NODE: {
21584 pm_multi_target_node_targets_append(parser, multi_target, node);
21586 parser_lex(parser);
21587 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));
21588 return parse_write(parser, UP(multi_target), &token, value);
21590 case PM_SOURCE_ENCODING_NODE:
21591 case PM_FALSE_NODE:
21592 case PM_SOURCE_FILE_NODE:
21593 case PM_SOURCE_LINE_NODE:
21596 case PM_TRUE_NODE: {
21599 parser_lex(parser);
21600 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21601 return parse_unwriteable_write(parser, node, &token, value);
21607 parser_lex(parser);
21608 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21612 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21613 switch (PM_NODE_TYPE(node)) {
21614 case PM_BACK_REFERENCE_READ_NODE:
21615 case PM_NUMBERED_REFERENCE_READ_NODE:
21616 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21618 case PM_GLOBAL_VARIABLE_READ_NODE: {
21619 parser_lex(parser);
21621 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21622 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
21626 case PM_CLASS_VARIABLE_READ_NODE: {
21627 parser_lex(parser);
21629 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21634 case PM_CONSTANT_PATH_NODE: {
21635 parser_lex(parser);
21637 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21640 return parse_shareable_constant_write(parser, write);
21642 case PM_CONSTANT_READ_NODE: {
21643 parser_lex(parser);
21645 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21648 if (context_def_p(parser)) {
21649 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21652 return parse_shareable_constant_write(parser, write);
21654 case PM_INSTANCE_VARIABLE_READ_NODE: {
21655 parser_lex(parser);
21657 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21662 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21664 parser_lex(parser);
21666 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21667 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
21669 pm_node_unreference(parser, node);
21672 case PM_LOCAL_VARIABLE_READ_NODE: {
21673 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21675 pm_node_unreference(parser, node);
21679 parser_lex(parser);
21681 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21682 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21686 case PM_CALL_NODE: {
21692 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21695 parser_lex(parser);
21697 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21698 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21705 parser_lex(parser);
21710 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21711 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21712 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
21716 if (pm_call_node_writable_p(parser, cast)) {
21717 parse_write_name(parser, &cast->
name);
21719 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21722 parse_call_operator_write(parser, cast, &token);
21723 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21724 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
21726 case PM_MULTI_WRITE_NODE: {
21727 parser_lex(parser);
21728 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21732 parser_lex(parser);
21737 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21741 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21742 switch (PM_NODE_TYPE(node)) {
21743 case PM_BACK_REFERENCE_READ_NODE:
21744 case PM_NUMBERED_REFERENCE_READ_NODE:
21745 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21747 case PM_GLOBAL_VARIABLE_READ_NODE: {
21748 parser_lex(parser);
21750 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21751 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
21755 case PM_CLASS_VARIABLE_READ_NODE: {
21756 parser_lex(parser);
21758 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21763 case PM_CONSTANT_PATH_NODE: {
21764 parser_lex(parser);
21766 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21769 return parse_shareable_constant_write(parser, write);
21771 case PM_CONSTANT_READ_NODE: {
21772 parser_lex(parser);
21774 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21777 if (context_def_p(parser)) {
21778 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21781 return parse_shareable_constant_write(parser, write);
21783 case PM_INSTANCE_VARIABLE_READ_NODE: {
21784 parser_lex(parser);
21786 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21791 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21793 parser_lex(parser);
21795 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21796 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
21798 pm_node_unreference(parser, node);
21801 case PM_LOCAL_VARIABLE_READ_NODE: {
21802 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21803 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21804 pm_node_unreference(parser, node);
21808 parser_lex(parser);
21810 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21811 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21815 case PM_CALL_NODE: {
21821 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21824 parser_lex(parser);
21826 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21827 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21834 parser_lex(parser);
21839 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21840 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21841 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
21845 if (pm_call_node_writable_p(parser, cast)) {
21846 parse_write_name(parser, &cast->
name);
21848 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21851 parse_call_operator_write(parser, cast, &token);
21852 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21853 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
21855 case PM_MULTI_WRITE_NODE: {
21856 parser_lex(parser);
21857 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21861 parser_lex(parser);
21866 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21870 case PM_TOKEN_AMPERSAND_EQUAL:
21871 case PM_TOKEN_CARET_EQUAL:
21872 case PM_TOKEN_GREATER_GREATER_EQUAL:
21873 case PM_TOKEN_LESS_LESS_EQUAL:
21874 case PM_TOKEN_MINUS_EQUAL:
21875 case PM_TOKEN_PERCENT_EQUAL:
21876 case PM_TOKEN_PIPE_EQUAL:
21877 case PM_TOKEN_PLUS_EQUAL:
21878 case PM_TOKEN_SLASH_EQUAL:
21879 case PM_TOKEN_STAR_EQUAL:
21880 case PM_TOKEN_STAR_STAR_EQUAL: {
21881 switch (PM_NODE_TYPE(node)) {
21882 case PM_BACK_REFERENCE_READ_NODE:
21883 case PM_NUMBERED_REFERENCE_READ_NODE:
21884 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21886 case PM_GLOBAL_VARIABLE_READ_NODE: {
21887 parser_lex(parser);
21889 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21890 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
21894 case PM_CLASS_VARIABLE_READ_NODE: {
21895 parser_lex(parser);
21897 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21902 case PM_CONSTANT_PATH_NODE: {
21903 parser_lex(parser);
21905 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21908 return parse_shareable_constant_write(parser, write);
21910 case PM_CONSTANT_READ_NODE: {
21911 parser_lex(parser);
21913 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21916 if (context_def_p(parser)) {
21917 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21920 return parse_shareable_constant_write(parser, write);
21922 case PM_INSTANCE_VARIABLE_READ_NODE: {
21923 parser_lex(parser);
21925 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21930 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21932 parser_lex(parser);
21934 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21935 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21937 pm_node_unreference(parser, node);
21940 case PM_LOCAL_VARIABLE_READ_NODE: {
21941 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21942 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21943 pm_node_unreference(parser, node);
21947 parser_lex(parser);
21949 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21950 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21954 case PM_CALL_NODE: {
21955 parser_lex(parser);
21961 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21964 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21965 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21973 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21974 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21975 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21979 if (pm_call_node_writable_p(parser, cast)) {
21980 parse_write_name(parser, &cast->
name);
21982 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21985 parse_call_operator_write(parser, cast, &token);
21986 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21987 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21989 case PM_MULTI_WRITE_NODE: {
21990 parser_lex(parser);
21991 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21995 parser_lex(parser);
22000 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
22004 case PM_TOKEN_AMPERSAND_AMPERSAND:
22005 case PM_TOKEN_KEYWORD_AND: {
22006 parser_lex(parser);
22008 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));
22009 return UP(pm_and_node_create(parser, node, &token, right));
22011 case PM_TOKEN_KEYWORD_OR:
22012 case PM_TOKEN_PIPE_PIPE: {
22013 parser_lex(parser);
22015 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));
22016 return UP(pm_or_node_create(parser, node, &token, right));
22018 case PM_TOKEN_EQUAL_TILDE: {
22026 parser_lex(parser);
22027 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));
22030 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
22036 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
22043 bool interpolated =
false;
22044 size_t total_length = 0;
22048 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
22049 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
22051 interpolated =
true;
22056 if (!interpolated && total_length > 0) {
22057 void *memory =
xmalloc(total_length);
22058 if (!memory) abort();
22060 uint8_t *cursor = memory;
22063 size_t length = pm_string_length(unescaped);
22065 memcpy(cursor, pm_string_source(unescaped), length);
22070 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
22072 result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
22073 pm_string_cleanup(&owned);
22075 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
22086 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
22088 if (name_data.match != NULL) {
22089 result = UP(name_data.match);
22095 case PM_TOKEN_UAMPERSAND:
22096 case PM_TOKEN_USTAR:
22097 case PM_TOKEN_USTAR_STAR:
22100 case PM_TOKEN_BANG_EQUAL:
22101 case PM_TOKEN_BANG_TILDE:
22102 case PM_TOKEN_EQUAL_EQUAL:
22103 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
22104 case PM_TOKEN_LESS_EQUAL_GREATER:
22105 case PM_TOKEN_CARET:
22106 case PM_TOKEN_PIPE:
22107 case PM_TOKEN_AMPERSAND:
22108 case PM_TOKEN_GREATER_GREATER:
22109 case PM_TOKEN_LESS_LESS:
22110 case PM_TOKEN_MINUS:
22111 case PM_TOKEN_PLUS:
22112 case PM_TOKEN_PERCENT:
22113 case PM_TOKEN_SLASH:
22114 case PM_TOKEN_STAR:
22115 case PM_TOKEN_STAR_STAR: {
22116 parser_lex(parser);
22118 switch (PM_NODE_TYPE(node)) {
22119 case PM_RESCUE_MODIFIER_NODE: {
22122 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22126 case PM_AND_NODE: {
22128 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22129 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22135 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22136 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22144 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));
22145 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
22147 case PM_TOKEN_GREATER:
22148 case PM_TOKEN_GREATER_EQUAL:
22149 case PM_TOKEN_LESS:
22150 case PM_TOKEN_LESS_EQUAL: {
22151 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
22152 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
22155 parser_lex(parser);
22156 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));
22157 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
22159 case PM_TOKEN_AMPERSAND_DOT:
22160 case PM_TOKEN_DOT: {
22161 parser_lex(parser);
22166 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
22167 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22168 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
22171 switch (PM_NODE_TYPE(node)) {
22172 case PM_RESCUE_MODIFIER_NODE: {
22175 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22179 case PM_AND_NODE: {
22181 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22182 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22188 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22189 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22199 switch (parser->current.type) {
22200 case PM_CASE_OPERATOR:
22201 case PM_CASE_KEYWORD:
22202 case PM_TOKEN_CONSTANT:
22203 case PM_TOKEN_IDENTIFIER:
22204 case PM_TOKEN_METHOD_NAME: {
22205 parser_lex(parser);
22206 message = parser->previous;
22210 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
22211 message = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
22215 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22216 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
22219 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
22222 match1(parser, PM_TOKEN_COMMA)
22224 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22229 case PM_TOKEN_DOT_DOT:
22230 case PM_TOKEN_DOT_DOT_DOT: {
22231 parser_lex(parser);
22234 if (token_begins_expression_p(parser->current.type)) {
22235 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22238 return UP(pm_range_node_create(parser, node, &token, right));
22240 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
22242 parser_lex(parser);
22244 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));
22245 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
22247 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
22249 parser_lex(parser);
22251 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));
22252 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
22254 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
22255 parser_lex(parser);
22257 pm_statements_node_body_append(parser, statements, node,
true);
22259 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));
22260 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));
22262 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
22263 parser_lex(parser);
22265 pm_statements_node_body_append(parser, statements, node,
true);
22267 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));
22268 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));
22270 case PM_TOKEN_QUESTION_MARK: {
22271 context_push(parser, PM_CONTEXT_TERNARY);
22273 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22276 parser_lex(parser);
22278 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));
22280 if (parser->recovering) {
22288 pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
22290 context_pop(parser);
22291 pop_block_exits(parser, previous_block_exits);
22292 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
22295 accept1(parser, PM_TOKEN_NEWLINE);
22296 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
22299 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));
22301 context_pop(parser);
22302 pop_block_exits(parser, previous_block_exits);
22303 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
22305 case PM_TOKEN_COLON_COLON: {
22306 parser_lex(parser);
22309 switch (parser->current.type) {
22310 case PM_TOKEN_CONSTANT: {
22311 parser_lex(parser);
22315 (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
22316 ((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)))
22327 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22328 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
22331 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
22335 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22336 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22341 case PM_CASE_OPERATOR:
22342 case PM_CASE_KEYWORD:
22343 case PM_TOKEN_IDENTIFIER:
22344 case PM_TOKEN_METHOD_NAME: {
22345 parser_lex(parser);
22351 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22352 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22355 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22356 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22361 case PM_TOKEN_PARENTHESIS_LEFT: {
22365 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22367 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
22370 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
22371 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
22375 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22376 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
22377 parser_lex(parser);
22378 accept1(parser, PM_TOKEN_NEWLINE);
22380 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));
22381 context_pop(parser);
22383 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
22385 case PM_TOKEN_BRACKET_LEFT: {
22386 parser_lex(parser);
22389 arguments.
opening_loc = TOK2LOC(parser, &parser->previous);
22391 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22392 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
22393 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22396 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
22400 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22401 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22402 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22409 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22410 block = parse_block(parser, (uint16_t) (depth + 1));
22411 pm_arguments_validate_block(parser, &arguments, block);
22412 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22413 block = parse_block(parser, (uint16_t) (depth + 1));
22416 if (block != NULL) {
22417 if (arguments.
block != NULL) {
22418 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
22420 arguments.
arguments = pm_arguments_node_create(parser);
22422 pm_arguments_node_arguments_append(parser->arena, arguments.
arguments, arguments.
block);
22425 arguments.
block = UP(block);
22428 return UP(pm_call_node_aref_create(parser, node, &arguments));
22430 case PM_TOKEN_KEYWORD_IN: {
22431 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22432 parser->pattern_matching_newlines =
true;
22435 parser->command_start =
false;
22436 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22437 parser_lex(parser);
22440 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));
22442 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22444 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
22446 case PM_TOKEN_EQUAL_GREATER: {
22447 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22448 parser->pattern_matching_newlines =
true;
22451 parser->command_start =
false;
22452 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22453 parser_lex(parser);
22456 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));
22458 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22460 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
22463 assert(
false &&
"unreachable");
22468#undef PM_PARSE_PATTERN_SINGLE
22469#undef PM_PARSE_PATTERN_TOP
22470#undef PM_PARSE_PATTERN_MULTI
22486 pm_binding_power_t left = pm_binding_powers[parser->current.type].
left;
22488 switch (PM_NODE_TYPE(node)) {
22489 case PM_MULTI_WRITE_NODE:
22490 case PM_RETURN_NODE:
22491 case PM_BREAK_NODE:
22493 return left > PM_BINDING_POWER_MODIFIER;
22494 case PM_CLASS_VARIABLE_WRITE_NODE:
22495 case PM_CONSTANT_PATH_WRITE_NODE:
22496 case PM_CONSTANT_WRITE_NODE:
22497 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22498 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22499 case PM_LOCAL_VARIABLE_WRITE_NODE:
22500 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
22501 case PM_CALL_NODE: {
22504 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
22505 return left > PM_BINDING_POWER_MODIFIER;
22511 if (pm_command_call_value_p(parser, node)) {
22512 return left > PM_BINDING_POWER_COMPOSITION;
22518 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22520 case PM_SUPER_NODE:
22521 case PM_YIELD_NODE:
22524 if (pm_command_call_value_p(parser, node)) {
22525 return left > PM_BINDING_POWER_COMPOSITION;
22530 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22535 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(parser, node);
22536 case PM_RESCUE_MODIFIER_NODE:
22540 if (left > PM_BINDING_POWER_MODIFIER) {
22543 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
22560parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
22561 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
22562 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22563 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
22566 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
22571 switch (PM_NODE_TYPE(node)) {
22572 case PM_ERROR_RECOVERY_NODE:
22574 case PM_PRE_EXECUTION_NODE:
22576 case PM_POST_EXECUTION_NODE:
22577 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22578 case PM_ALIAS_METHOD_NODE:
22579 case PM_UNDEF_NODE:
22580 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
22585 case PM_SUPER_NODE:
22586 case PM_YIELD_NODE:
22588 if (parse_expression_terminator(parser, node)) {
22592 case PM_SYMBOL_NODE:
22593 if (pm_symbol_node_label_p(parser, node)) {
22604 pm_token_type_t current_token_type;
22607 current_token_type = parser->current.type,
22608 current_binding_powers = pm_binding_powers[current_token_type],
22609 binding_power <= current_binding_powers.
left &&
22610 current_binding_powers.
binary
22612 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
22613 if (parse_expression_terminator(parser, node))
return node;
22617 if (current_binding_powers.
nonassoc) {
22625 if (next_binding_powers.
nonassoc && next_binding_powers.
left == current_binding_powers.
left) {
22626 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));
22637 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22638 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22639 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));
22643 if (PM_BINDING_POWER_TERM <= next_binding_powers.
left) {
22646 }
else if (current_binding_powers.
left <= next_binding_powers.
left) {
22651 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
22660 switch (node->
type) {
22661 case PM_CALL_NODE: {
22675 cast->
block == NULL &&
22685 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22688 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22693 case PM_CONSTANT_PATH_NODE:
22696 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22701 if (context_terminator(parser->current_context->context, &parser->current)) {
22704 !next_binding_powers.
binary ||
22705 binding_power > next_binding_powers.
left ||
22706 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
22722 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22723 if (statements == NULL) {
22724 statements = pm_statements_node_create(parser);
22728 pm_arguments_node_arguments_append(
22731 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
22734 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
22737 pm_parser_constant_id_constant(parser,
"print", 5)
22741 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22742 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22743 if (statements == NULL) {
22744 statements = pm_statements_node_create(parser);
22748 pm_arguments_node_arguments_append(
22751 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
22754 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22755 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
22759 pm_parser_constant_id_constant(parser,
"$F", 2),
22763 pm_statements_node_body_prepend(parser->arena, statements, UP(write));
22767 pm_arguments_node_arguments_append(
22770 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
22773 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22775 pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
22777 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
22779 UP(pm_true_node_synthesized_create(parser))
22782 pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
22783 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22787 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
22789 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
22793 statements = wrapped_statements;
22807 if (parser->current_scope == NULL) {
22808 pm_parser_scope_push(parser,
true);
22812 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22814 parser_lex(parser);
22817 if (statements != NULL && !parser->parsing_eval) {
22821 assert(statements->
body.
size > 0);
22822 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22826 pm_locals_order(parser, &parser->current_scope->locals, &locals,
true);
22827 pm_parser_scope_pop(parser);
22832 statements = wrap_statements(parser, statements);
22834 flush_block_exits(parser, previous_block_exits);
22840 if (statements == NULL) {
22841 statements = pm_statements_node_create(parser);
22845 return UP(pm_program_node_create(parser, &locals, statements));
22862pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22863 size_t little_length = strlen(little);
22865 for (
const char *max = big + big_length - little_length; big <= max; big++) {
22866 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22873#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22881pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22882 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22883 pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
22894 const char *switches = pm_strnstr(engine,
" -", length);
22895 if (switches == NULL)
return;
22898 options->shebang_callback(
22900 (
const uint8_t *) (switches + 1),
22901 length - ((
size_t) (switches - engine)) - 1,
22902 options->shebang_callback_data
22905 size_t encoding_length;
22906 if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
22907 const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
22908 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22911 parser->command_line = next_options.command_line;
22912 parser->frozen_string_literal = next_options.frozen_string_literal;
22920 assert(arena != NULL);
22921 assert(source != NULL);
22925 .metadata_arena = { 0 },
22927 .lex_state = PM_LEX_STATE_BEG,
22928 .enclosure_nesting = 0,
22929 .lambda_enclosure_nesting = -1,
22930 .brace_nesting = 0,
22931 .do_loop_stack = 0,
22932 .accepts_block_stack = 0,
22935 .stack = {{ .mode = PM_LEX_DEFAULT }},
22936 .current = &parser->lex_modes.stack[0],
22939 .end = source + size,
22940 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22941 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22942 .next_start = NULL,
22943 .heredoc_end = NULL,
22945 .comment_list = { 0 },
22946 .magic_comment_list = { 0 },
22947 .warning_list = { 0 },
22948 .error_list = { 0 },
22949 .current_scope = NULL,
22950 .current_context = NULL,
22951 .encoding = PM_ENCODING_UTF_8_ENTRY,
22952 .encoding_changed_callback = NULL,
22953 .encoding_comment_start = source,
22954 .lex_callback = { 0 },
22956 .constant_pool = { 0 },
22957 .line_offsets = { 0 },
22959 .current_string = PM_STRING_EMPTY,
22961 .explicit_encoding = NULL,
22963 .parsing_eval =
false,
22964 .partial_script =
false,
22965 .command_start =
true,
22966 .recovering =
false,
22967 .continuable =
true,
22968 .encoding_locked =
false,
22969 .encoding_changed =
false,
22970 .pattern_matching_newlines =
false,
22971 .in_keyword_arg =
false,
22972 .current_block_exits = NULL,
22973 .semantic_token_seen =
false,
22975 .warn_mismatched_indentation =
true
22983 if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
22984 if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
22991 uint32_t constant_size = ((uint32_t) size) / 120;
22992 pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
22997 size_t newline_size = size / 22;
22998 pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
23001 if (options != NULL) {
23003 parser->filepath = options->filepath;
23006 parser->start_line = options->line;
23009 size_t encoding_length = pm_string_length(&options->encoding);
23010 if (encoding_length > 0) {
23011 const uint8_t *encoding_source = pm_string_source(&options->encoding);
23012 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23016 parser->encoding_locked = options->encoding_locked;
23019 parser->frozen_string_literal = options->frozen_string_literal;
23022 parser->command_line = options->command_line;
23025 parser->version = options->version;
23028 parser->partial_script = options->partial_script;
23031 parser->parsing_eval = options->scopes_count > 0;
23032 if (parser->parsing_eval) parser->warn_mismatched_indentation =
false;
23034 for (
size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
23036 pm_parser_scope_push(parser, scope_index == 0);
23040 parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
23042 for (
size_t local_index = 0; local_index < scope->locals_count; local_index++) {
23043 const pm_string_t *local = pm_options_scope_local(scope, local_index);
23045 const uint8_t *source = pm_string_source(local);
23046 size_t length = pm_string_length(local);
23048 uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
23049 memcpy(allocated, source, length);
23050 pm_parser_local_add_owned(parser, allocated, length);
23057 if (parser->version == PM_OPTIONS_VERSION_UNSET) {
23058 parser->version = PM_OPTIONS_VERSION_LATEST;
23061 pm_accepts_block_stack_push(parser,
true);
23064 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
23065 parser->current.end += 3;
23066 parser->encoding_comment_start += 3;
23068 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
23069 parser->encoding = PM_ENCODING_UTF_8_ENTRY;
23070 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
23077 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
23094 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
23095 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
23097 if (length > 2 && parser->current.end[0] ==
'#' && parser->current.end[1] ==
'!') {
23098 const char *engine;
23100 if ((engine = pm_strnstr((
const char *) parser->start,
"ruby", length)) != NULL) {
23101 if (newline != NULL) {
23102 parser->encoding_comment_start = newline + 1;
23104 if (options == NULL || options->main_script) {
23105 pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
23109 if (options != NULL && options->main_script && options->shebang_callback != NULL) {
23110 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->start)));
23113 search_shebang =
false;
23114 }
else if (options != NULL && options->main_script && !parser->parsing_eval) {
23115 search_shebang =
true;
23121 if (search_shebang) {
23124 bool found_shebang =
false;
23128 const uint8_t *cursor = parser->start;
23132 const uint8_t *newline = next_newline(cursor, parser->end - cursor);
23134 while (newline != NULL) {
23135 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
23137 cursor = newline + 1;
23138 newline = next_newline(cursor, parser->end - cursor);
23140 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
23141 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
23142 const char *engine;
23143 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
23144 found_shebang =
true;
23146 if (newline != NULL) {
23147 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
23148 parser->encoding_comment_start = newline + 1;
23151 if (options != NULL && options->shebang_callback != NULL) {
23152 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
23160 if (found_shebang) {
23161 parser->previous = (
pm_token_t) { .
type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23162 parser->current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23164 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
23165 pm_line_offset_list_clear(&parser->line_offsets);
23172 parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
23185 if (parser == NULL) abort();
23187 pm_parser_init(arena, parser, source, size, options);
23196 pm_string_cleanup(&parser->filepath);
23197 pm_arena_cleanup(&parser->metadata_arena);
23199 while (parser->current_scope != NULL) {
23204 pm_parser_scope_pop(parser);
23207 while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
23208 lex_mode_pop(parser);
23217 pm_parser_cleanup(parser);
23227pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
23229 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
23230 case PM_ERR_BEGIN_UPCASE_BRACE:
23231 case PM_ERR_CLASS_VARIABLE_BARE:
23232 case PM_ERR_END_UPCASE_BRACE:
23233 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
23234 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
23235 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
23236 case PM_ERR_EXPRESSION_NOT_WRITABLE:
23237 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
23238 case PM_ERR_FLOAT_PARSE:
23239 case PM_ERR_GLOBAL_VARIABLE_BARE:
23240 case PM_ERR_HASH_KEY:
23241 case PM_ERR_HEREDOC_IDENTIFIER:
23242 case PM_ERR_INSTANCE_VARIABLE_BARE:
23243 case PM_ERR_INVALID_BLOCK_EXIT:
23244 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
23245 case PM_ERR_INVALID_FLOAT_EXPONENT:
23246 case PM_ERR_INVALID_NUMBER_BINARY:
23247 case PM_ERR_INVALID_NUMBER_DECIMAL:
23248 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
23249 case PM_ERR_INVALID_NUMBER_OCTAL:
23250 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
23251 case PM_ERR_NO_LOCAL_VARIABLE:
23252 case PM_ERR_PARAMETER_ORDER:
23253 case PM_ERR_STATEMENT_UNDEF:
23254 case PM_ERR_VOID_EXPRESSION:
23297 if (parser->error_list.size == 0) {
23298 parser->continuable =
false;
23302 if (!parser->continuable)
return;
23304 size_t source_length = (size_t) (parser->end - parser->start);
23307 bool has_non_stray_error =
false;
23309 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)) {
23310 has_non_stray_error =
true;
23318 size_t non_stray_min_start = SIZE_MAX;
23321 size_t error_start = (size_t) error->location.start;
23322 size_t error_end = error_start + (size_t) error->location.length;
23323 bool at_eof = error_end >= source_length;
23326 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
23327 parser->continuable =
false;
23332 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
23333 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
23334 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
23343 if (non_stray_min_start < error_start)
continue;
23350 if (at_eof && error_start > 0) {
23352 if (error->location.length == 1) {
23353 const uint8_t *
byte = parser->start + error_start;
23354 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
23355 parser->continuable =
false;
23365 if (has_non_stray_error)
continue;
23372 if (error->location.length == 1) {
23373 const uint8_t *
byte = parser->start + error_start;
23374 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
23378 parser->continuable =
false;
23388 pm_node_t *node = parse_program(parser);
23389 pm_parse_continuable(parser);
23401 bool eof = pm_source_stream_read(source);
23406 while (!eof && tmp->error_list.size > 0) {
23407 eof = pm_source_stream_read(source);
23410 pm_arena_cleanup(arena);
23412 tmp =
pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
23420#undef PM_CASE_KEYWORD
23421#undef PM_CASE_OPERATOR
23422#undef PM_CASE_WRITABLE
23423#undef PM_STRING_EMPTY
23428#ifndef PRISM_EXCLUDE_SERIALIZATION
23432 pm_buffer_append_string(buffer,
"PRISM", 5);
23436 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23444 pm_serialize_header(buffer);
23445 pm_serialize_content(parser, node, buffer);
23446 pm_buffer_append_byte(buffer,
'\0');
23454pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23456 pm_options_read(&options, data);
23460 pm_parser_init(&arena, &parser, source, size, &options);
23464 pm_serialize_header(buffer);
23465 pm_serialize_content(&parser, node, buffer);
23466 pm_buffer_append_byte(buffer,
'\0');
23468 pm_parser_cleanup(&parser);
23469 pm_arena_cleanup(&arena);
23470 pm_options_cleanup(&options);
23482 pm_options_read(&options, data);
23484 pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
23485 pm_serialize_header(buffer);
23486 pm_serialize_content(parser, node, buffer);
23487 pm_buffer_append_byte(buffer,
'\0');
23490 pm_arena_cleanup(&arena);
23491 pm_options_cleanup(&options);
23505 pm_options_read(&options, data);
23509 pm_parser_init(&arena, &parser, source, size, &options);
23513 int8_t result = -1;
23514 if (parser.error_list.size > 0) {
23515 const char *encoding_name = parser.encoding->name;
23516 pm_buffer_append_string(buffer, encoding_name, strlen(encoding_name));
23517 pm_buffer_append_byte(buffer,
'\0');
23519 result = (int8_t) pm_errors_format(&parser, buffer, format_type);
23522 pm_parser_cleanup(&parser);
23523 pm_arena_cleanup(&arena);
23524 pm_options_cleanup(&options);
23533pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23535 pm_options_read(&options, data);
23539 pm_parser_init(&arena, &parser, source, size, &options);
23542 pm_serialize_header(buffer);
23543 pm_serialize_encoding(parser.encoding, buffer);
23544 pm_buffer_append_varsint(buffer, parser.start_line);
23545 pm_serialize_line_offset_list(&parser.line_offsets, buffer);
23546 pm_serialize_comment_list(&parser.comment_list, buffer);
23548 pm_parser_cleanup(&parser);
23549 pm_arena_cleanup(&arena);
23550 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.