5#include "prism/internal/allocator.h"
6#include "prism/internal/arena.h"
7#include "prism/internal/bit.h"
8#include "prism/internal/buffer.h"
9#include "prism/internal/char.h"
10#include "prism/internal/comments.h"
11#include "prism/internal/constant_pool.h"
12#include "prism/internal/diagnostic.h"
13#include "prism/internal/encoding.h"
14#include "prism/internal/integer.h"
15#include "prism/internal/isinf.h"
16#include "prism/internal/line_offset_list.h"
17#include "prism/internal/list.h"
18#include "prism/internal/magic_comments.h"
19#include "prism/internal/memchr.h"
20#include "prism/internal/node.h"
21#include "prism/internal/options.h"
22#include "prism/internal/parser.h"
23#include "prism/internal/regexp.h"
24#include "prism/internal/serialize.h"
25#include "prism/internal/source.h"
26#include "prism/internal/static_literals.h"
27#include "prism/internal/stringy.h"
28#include "prism/internal/strncasecmp.h"
29#include "prism/internal/strpbrk.h"
30#include "prism/internal/tokens.h"
50#ifndef PRISM_DEPTH_MAXIMUM
51 #define PRISM_DEPTH_MAXIMUM 10000
58#define PM_CONCATENATE(left, right) left ## right
65#if defined(_Static_assert)
66# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message)
68# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
75#if defined(__GNUC__) || defined(__clang__)
77 #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
80 #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
83 #define PRISM_LIKELY(x) (x)
86 #define PRISM_UNLIKELY(x) (x)
101#define PM_TAB_WHITESPACE_SIZE 8
104#define MIN(a,b) (((a)<(b))?(a):(b))
105#define MAX(a,b) (((a)>(b))?(a):(b))
111#define U32(value_) ((uint32_t) (value_))
113#define FL PM_NODE_FLAGS
114#define UP PM_NODE_UPCAST
116#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
117#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
118#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
119#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
121#define PM_NODE_START(node_) (UP(node_)->location.start)
122#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
123#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
124#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
126#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
127#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
129#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
130#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
131#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
132#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
133#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
143pm_location_init(uint32_t start, uint32_t length) {
148#define PM_LOCATION_INIT(start_, length_) pm_location_init((start_), (length_))
149#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
150#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
151#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
153#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
154#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
155#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
156#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
158#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
159#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
160#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
171lex_mode_incrementor(
const uint8_t start) {
188lex_mode_terminator(
const uint8_t start) {
210 lex_mode.prev = parser->lex_modes.current;
211 parser->lex_modes.index++;
213 if (parser->lex_modes.index > PM_LEX_STACK_SIZE - 1) {
215 if (PRISM_UNLIKELY(parser->lex_modes.current == NULL)) {
216 fprintf(stderr,
"prism: out of memory; aborting\n");
220 *parser->lex_modes.current = lex_mode;
222 parser->lex_modes.stack[parser->lex_modes.index] = lex_mode;
223 parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
231lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
232 uint8_t incrementor = lex_mode_incrementor(delimiter);
233 uint8_t terminator = lex_mode_terminator(delimiter);
239 .interpolation = interpolation,
242 .incrementor = incrementor,
243 .terminator = terminator
249 uint8_t *breakpoints = lex_mode.as.list.breakpoints;
250 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
251 memcpy(breakpoints,
"\\ \t\f\r\v\n",
sizeof(
"\\ \t\f\r\v\n") - 1);
256 if (terminator !=
'\0') {
257 breakpoints[index++] = terminator;
263 breakpoints[index++] =
'#';
267 if (incrementor !=
'\0') {
268 breakpoints[index++] = incrementor;
271 parser->explicit_encoding = NULL;
272 lex_mode_push(parser, lex_mode);
282 lex_mode_push_list(parser,
false,
'\0');
289lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
291 .mode = PM_LEX_REGEXP,
294 .incrementor = incrementor,
295 .terminator = terminator
302 uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
303 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
304 memcpy(breakpoints,
"\r\n\\#",
sizeof(
"\r\n\\#") - 1);
308 if (terminator !=
'\0') {
309 breakpoints[index++] = terminator;
313 if (incrementor !=
'\0') {
314 breakpoints[index++] = incrementor;
317 parser->explicit_encoding = NULL;
318 lex_mode_push(parser, lex_mode);
325lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
327 .mode = PM_LEX_STRING,
330 .interpolation = interpolation,
331 .label_allowed = label_allowed,
332 .incrementor = incrementor,
333 .terminator = terminator
339 uint8_t *breakpoints = lex_mode.as.string.breakpoints;
340 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
341 memcpy(breakpoints,
"\r\n\\",
sizeof(
"\r\n\\") - 1);
346 if (terminator !=
'\0') {
347 breakpoints[index++] = terminator;
353 breakpoints[index++] =
'#';
358 if (incrementor !=
'\0') {
359 breakpoints[index++] = incrementor;
362 parser->explicit_encoding = NULL;
363 lex_mode_push(parser, lex_mode);
373 lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
383 if (parser->lex_modes.index == 0) {
384 parser->lex_modes.current->mode = PM_LEX_DEFAULT;
385 }
else if (parser->lex_modes.index < PM_LEX_STACK_SIZE) {
386 parser->lex_modes.index--;
387 parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
389 parser->lex_modes.index--;
391 xfree_sized(parser->lex_modes.current,
sizeof(
pm_lex_mode_t));
392 parser->lex_modes.current = prev;
400lex_state_p(
const pm_parser_t *parser, pm_lex_state_t state) {
401 return parser->lex_state & state;
405 PM_IGNORED_NEWLINE_NONE = 0,
406 PM_IGNORED_NEWLINE_ALL,
407 PM_IGNORED_NEWLINE_PATTERN
408} pm_ignored_newline_type_t;
412 bool ignored = lex_state_p(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_CLASS | PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT) && !lex_state_p(parser, PM_LEX_STATE_LABELED);
415 return PM_IGNORED_NEWLINE_ALL;
416 }
else if ((parser->lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
417 return PM_IGNORED_NEWLINE_PATTERN;
419 return PM_IGNORED_NEWLINE_NONE;
425 return lex_state_p(parser, PM_LEX_STATE_BEG_ANY) || ((parser->lex_state & (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED));
430 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
434lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
435 if (parser->current.end >= parser->end) {
438 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
443 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
451 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
459lex_state_set(
pm_parser_t *parser, pm_lex_state_t state) {
460 parser->lex_state = state;
463#ifndef PM_DEBUG_LOGGING
468#define PM_DEBUG_LOGGING 0
474 fprintf(stderr,
"STATE: ");
477 if (parser->lex_state == PM_LEX_STATE_NONE) {
478 fprintf(stderr,
"NONE\n");
482#define CHECK_STATE(state) \
483 if (parser->lex_state & state) { \
484 if (!first) fprintf(stderr, "|"); \
485 fprintf(stderr, "%s", #state); \
489 CHECK_STATE(PM_LEX_STATE_BEG)
490 CHECK_STATE(PM_LEX_STATE_END)
491 CHECK_STATE(PM_LEX_STATE_ENDARG)
492 CHECK_STATE(PM_LEX_STATE_ENDFN)
493 CHECK_STATE(PM_LEX_STATE_ARG)
494 CHECK_STATE(PM_LEX_STATE_CMDARG)
495 CHECK_STATE(PM_LEX_STATE_MID)
496 CHECK_STATE(PM_LEX_STATE_FNAME)
497 CHECK_STATE(PM_LEX_STATE_DOT)
498 CHECK_STATE(PM_LEX_STATE_CLASS)
499 CHECK_STATE(PM_LEX_STATE_LABEL)
500 CHECK_STATE(PM_LEX_STATE_LABELED)
501 CHECK_STATE(PM_LEX_STATE_FITEM)
505 fprintf(stderr,
"\n");
509debug_lex_state_set(
pm_parser_t *parser, pm_lex_state_t state,
char const * caller_name,
int line_number) {
510 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
512 lex_state_set(parser, state);
513 fprintf(stderr,
"Now: ");
515 fprintf(stderr,
"\n");
518#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
526#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
529#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
532#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
535#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
538#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
541#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
544#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
554pm_parser_err(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
555 pm_diagnostic_list_append(&parser->metadata_arena, &parser->error_list, start, length, diag_id);
564 pm_parser_err(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
572pm_parser_err_current(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
573 pm_parser_err_token(parser, &parser->current, diag_id);
581pm_parser_err_previous(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
582 pm_parser_err_token(parser, &parser->previous, diag_id);
591 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
597#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
598 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
604#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
605 PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
611#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
612 PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
618#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
619 PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id, __VA_ARGS__)
625#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
626 PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
632pm_parser_warn(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
633 pm_diagnostic_list_append(&parser->metadata_arena, &parser->warning_list, start, length, diag_id);
642 pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
651 pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
658#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
659 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->warning_list, start_, length_, diag_id_, __VA_ARGS__)
665#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
666 PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id_, __VA_ARGS__)
672#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
673 PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
679#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
680 PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
688pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
689 PM_PARSER_ERR_FORMAT(
691 U32(ident_start - parser->start),
695 (
const char *) ident_start
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 uint32_t next_capacity = locals->capacity == 0 ? 4 : (locals->capacity * 2);
893 assert(next_capacity > locals->capacity);
896 if (next_locals == NULL) abort();
898 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
899 if (locals->size > 0) {
900 memcpy(next_locals, locals->locals, locals->size *
sizeof(
pm_local_t));
905 bool hash_needed = (locals->capacity <= PM_LOCALS_HASH_THRESHOLD);
906 uint32_t mask = next_capacity - 1;
908 for (uint32_t index = 0; index < locals->capacity; index++) {
911 if (local->name != PM_CONSTANT_ID_UNSET) {
912 if (hash_needed) local->hash = pm_constant_id_hash(local->name);
914 uint32_t hash = local->hash;
915 while (next_locals[hash & mask].name != PM_CONSTANT_ID_UNSET) hash++;
916 next_locals[hash & mask] = *local;
921 pm_locals_free(locals);
922 locals->locals = next_locals;
923 locals->capacity = next_capacity;
943 if (locals->size >= (locals->capacity / 4 * 3)) {
944 pm_locals_resize(locals);
947 locals->bloom |= (1u << (name & 31));
949 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
950 for (uint32_t index = 0; index < locals->capacity; index++) {
953 if (local->name == PM_CONSTANT_ID_UNSET) {
956 .location = { .start = start, .length = length },
957 .index = locals->size++,
962 }
else if (local->name == name) {
967 uint32_t mask = locals->capacity - 1;
968 uint32_t hash = pm_constant_id_hash(name);
969 uint32_t initial_hash = hash;
972 pm_local_t *local = &locals->locals[hash & mask];
974 if (local->name == PM_CONSTANT_ID_UNSET) {
977 .location = { .start = start, .length = length },
978 .index = locals->size++,
983 }
else if (local->name == name) {
988 }
while ((hash & mask) != initial_hash);
991 assert(
false &&
"unreachable");
1001 if (!(locals->bloom & (1u << (name & 31))))
return UINT32_MAX;
1003 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
1004 for (uint32_t index = 0; index < locals->size; index++) {
1006 if (local->name == name)
return index;
1009 uint32_t mask = locals->capacity - 1;
1010 uint32_t hash = pm_constant_id_hash(name);
1011 uint32_t initial_hash = hash & mask;
1014 pm_local_t *local = &locals->locals[hash & mask];
1016 if (local->name == PM_CONSTANT_ID_UNSET) {
1018 }
else if (local->name == name) {
1023 }
while ((hash & mask) != initial_hash);
1035 uint32_t index = pm_locals_find(locals, name);
1036 assert(index != UINT32_MAX);
1039 assert(local->reads < UINT32_MAX);
1050 uint32_t index = pm_locals_find(locals, name);
1051 assert(index != UINT32_MAX);
1054 assert(local->reads > 0);
1064 uint32_t index = pm_locals_find(locals, name);
1065 assert(index != UINT32_MAX);
1067 return locals->locals[index].reads;
1080 pm_constant_id_list_init_capacity(parser->arena, list, locals->size);
1085 uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
1089 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
1091 for (uint32_t index = 0; index < capacity; index++) {
1094 if (local->name != PM_CONSTANT_ID_UNSET) {
1095 pm_constant_id_list_insert(list, (
size_t) local->index, local->name);
1097 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))) {
1098 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->name);
1100 if (constant->length >= 1 && *constant->start !=
'_') {
1101 PM_PARSER_WARN_FORMAT(
1103 local->location.
start,
1105 PM_WARN_UNUSED_LOCAL_VARIABLE,
1106 (
int) constant->length,
1107 (
const char *) constant->start
1123pm_parser_constant_id_raw(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1126 if (start == parser->constant_cache.start && end == parser->constant_cache.end) {
1127 return parser->constant_cache.id;
1130 pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (
size_t) (end - start));
1132 parser->constant_cache.start = start;
1133 parser->constant_cache.end = end;
1134 parser->constant_cache.id = id;
1143pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1144 return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length);
1151pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1152 return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (
const uint8_t *) start, length);
1160 return pm_parser_constant_id_raw(parser, token->start, token->end);
1167#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1168 case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1179 while (node != NULL) {
1180 switch (PM_NODE_TYPE(node)) {
1181 case PM_CASE_VOID_VALUE:
1182 return void_node != NULL ? void_node : node;
1183 case PM_MATCH_PREDICATE_NODE:
1185 case PM_BEGIN_NODE: {
1191 if (vn != NULL)
return vn;
1196 if (vn != NULL)
return vn;
1202 if (cast->
else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1206 if (vn == NULL)
return NULL;
1207 if (void_node == NULL) void_node = vn;
1211 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1215 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1227 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1228 pm_node_t *vn = pm_check_value_expression(parser, node);
1229 if (vn != NULL)
return vn;
1240 case PM_CASE_NODE: {
1242 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1251 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1255 if (vn == NULL)
return NULL;
1256 if (void_node == NULL) void_node = vn;
1259 node = UP(cast->else_clause);
1262 case PM_CASE_MATCH_NODE: {
1264 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1273 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1277 if (vn == NULL)
return NULL;
1278 if (void_node == NULL) void_node = vn;
1281 node = UP(cast->else_clause);
1284 case PM_ENSURE_NODE: {
1289 case PM_PARENTHESES_NODE: {
1291 node = UP(cast->
body);
1294 case PM_STATEMENTS_NODE: {
1298 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1301 switch (PM_NODE_TYPE(body_part)) {
1302 case PM_CASE_VOID_VALUE:
1303 if (void_node == NULL) {
1304 void_node = body_part;
1324 if (void_node == NULL) {
1330 case PM_UNLESS_NODE: {
1339 if (void_node == NULL) {
1345 case PM_ELSE_NODE: {
1358 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1362 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->previous;
1364 pm_locals_read(&scope->locals, cast->
name);
1377 pm_node_t *void_node = pm_check_value_expression(parser, node);
1378 if (void_node != NULL) {
1379 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1388 const char *
type = NULL;
1391 switch (PM_NODE_TYPE(node)) {
1392 case PM_BACK_REFERENCE_READ_NODE:
1393 case PM_CLASS_VARIABLE_READ_NODE:
1394 case PM_GLOBAL_VARIABLE_READ_NODE:
1395 case PM_INSTANCE_VARIABLE_READ_NODE:
1396 case PM_LOCAL_VARIABLE_READ_NODE:
1397 case PM_NUMBERED_REFERENCE_READ_NODE:
1398 type =
"a variable";
1401 case PM_CALL_NODE: {
1405 const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->
name);
1406 switch (message->length) {
1408 switch (message->start[0]) {
1419 type = (
const char *) message->start;
1425 switch (message->start[1]) {
1427 if (message->start[0] ==
'<' || message->start[0] ==
'>' || message->start[0] ==
'!' || message->start[0] ==
'=') {
1428 type = (
const char *) message->start;
1433 if (message->start[0] ==
'+' || message->start[0] ==
'-') {
1434 type = (
const char *) message->start;
1439 if (message->start[0] ==
'*') {
1440 type = (
const char *) message->start;
1447 if (memcmp(message->start,
"<=>", 3) == 0) {
1456 case PM_CONSTANT_PATH_NODE:
1460 case PM_CONSTANT_READ_NODE:
1461 type =
"a constant";
1464 case PM_DEFINED_NODE:
1473 case PM_IMAGINARY_NODE:
1474 case PM_INTEGER_NODE:
1475 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1476 case PM_INTERPOLATED_STRING_NODE:
1477 case PM_RATIONAL_NODE:
1478 case PM_REGULAR_EXPRESSION_NODE:
1479 case PM_SOURCE_ENCODING_NODE:
1480 case PM_SOURCE_FILE_NODE:
1481 case PM_SOURCE_LINE_NODE:
1482 case PM_STRING_NODE:
1483 case PM_SYMBOL_NODE:
1491 case PM_RANGE_NODE: {
1494 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1517 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1528 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1529 for (
size_t index = 0; index < size; index++) {
1530 pm_void_statement_check(parser, node->
body.
nodes[index]);
1540 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1541 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1542 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1543} pm_conditional_predicate_type_t;
1549pm_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) {
1551 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1552 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1554 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1555 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1557 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1567pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1568 switch (PM_NODE_TYPE(node)) {
1569 case PM_ARRAY_NODE: {
1570 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1573 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1574 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1579 case PM_HASH_NODE: {
1580 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1583 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1585 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1588 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1595 case PM_IMAGINARY_NODE:
1596 case PM_INTEGER_NODE:
1598 case PM_RATIONAL_NODE:
1599 case PM_REGULAR_EXPRESSION_NODE:
1600 case PM_SOURCE_ENCODING_NODE:
1601 case PM_SOURCE_FILE_NODE:
1602 case PM_SOURCE_LINE_NODE:
1603 case PM_STRING_NODE:
1604 case PM_SYMBOL_NODE:
1618 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1619 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);
1637 switch (PM_NODE_TYPE(node)) {
1640 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1641 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1646 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1647 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1650 case PM_PARENTHESES_NODE: {
1653 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1655 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1660 case PM_BEGIN_NODE: {
1668 case PM_RANGE_NODE: {
1671 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1672 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1680 node->
type = PM_FLIP_FLOP_NODE;
1684 case PM_REGULAR_EXPRESSION_NODE:
1689 node->
type = PM_MATCH_LAST_LINE_NODE;
1691 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1692 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1696 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1701 node->
type = PM_INTERPOLATED_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_VERBOSE,
"regex ");
1708 case PM_INTEGER_NODE:
1709 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1710 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1711 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1714 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1717 case PM_STRING_NODE:
1718 case PM_SOURCE_FILE_NODE:
1719 case PM_INTERPOLATED_STRING_NODE:
1720 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1722 case PM_SYMBOL_NODE:
1723 case PM_INTERPOLATED_SYMBOL_NODE:
1724 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1726 case PM_SOURCE_LINE_NODE:
1727 case PM_SOURCE_ENCODING_NODE:
1729 case PM_RATIONAL_NODE:
1730 case PM_IMAGINARY_NODE:
1731 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1733 case PM_CLASS_VARIABLE_WRITE_NODE:
1736 case PM_CONSTANT_WRITE_NODE:
1739 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1742 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1745 case PM_LOCAL_VARIABLE_WRITE_NODE:
1748 case PM_MULTI_WRITE_NODE:
1784 if (arguments->
block != NULL) {
1785 uint32_t end = PM_NODE_END(arguments->
block);
1788 uint32_t arguments_end = PM_LOCATION_END(&arguments->
closing_loc);
1789 if (arguments_end > end) {
1832 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1846char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1847 if (n <= 0)
return 0;
1849 if (parser->encoding_changed) {
1852 if ((width = parser->encoding->alpha_char(b, n)) != 0) {
1854 }
else if (*b ==
'_') {
1856 }
else if (*b >= 0x80) {
1857 return parser->encoding->char_width(b, n);
1861 }
else if (*b < 0x80) {
1862 return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b ==
'_');
1864 return pm_encoding_utf_8_char_width(b, n);
1873char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1876 }
else if (*b < 0x80) {
1877 return (*b ==
'_') || (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0);
1879 return pm_encoding_utf_8_char_width(b, n);
1896#if defined(PRISM_HAS_NEON)
1897#include <arm_neon.h>
1900scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1901 const uint8_t *cursor = start;
1908 static const uint8_t low_lut_data[16] = {
1909 0x15, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
1910 0x1F, 0x1F, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0E
1912 static const uint8_t high_lut_data[16] = {
1913 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
1914 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1916 const uint8x16_t low_lut = vld1q_u8(low_lut_data);
1917 const uint8x16_t high_lut = vld1q_u8(high_lut_data);
1918 const uint8x16_t mask_0f = vdupq_n_u8(0x0F);
1920 while (cursor + 16 <= end) {
1921 uint8x16_t v = vld1q_u8(cursor);
1923 uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
1924 uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
1925 uint8x16_t ident = vandq_u8(lo_class, hi_class);
1928 if (vminvq_u8(ident) != 0) {
1934 uint8x16_t is_zero = vceqq_u8(ident, vdupq_n_u8(0));
1935 uint64_t lo = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 0);
1938 cursor += pm_ctzll(lo) / 8;
1940 uint64_t hi = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 1);
1941 cursor += 8 + pm_ctzll(hi) / 8;
1944 return (
size_t) (cursor - start);
1947 return (
size_t) (cursor - start);
1950#elif defined(PRISM_HAS_SSE2)
1951#include <emmintrin.h>
1954scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1955 const uint8_t *cursor = start;
1957 while (cursor + 16 <= end) {
1958 __m128i v = _mm_loadu_si128((
const __m128i *) cursor);
1959 __m128i zero = _mm_setzero_si128();
1966 __m128i lowered = _mm_or_si128(v, _mm_set1_epi8(0x20));
1967 __m128i letter = _mm_and_si128(
1968 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x61), lowered), zero),
1969 _mm_cmpeq_epi8(_mm_subs_epu8(lowered, _mm_set1_epi8(0x7A)), zero));
1971 __m128i digit = _mm_and_si128(
1972 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x30), v), zero),
1973 _mm_cmpeq_epi8(_mm_subs_epu8(v, _mm_set1_epi8(0x39)), zero));
1975 __m128i underscore = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5F));
1977 __m128i ident = _mm_or_si128(_mm_or_si128(letter, digit), underscore);
1978 int mask = _mm_movemask_epi8(ident);
1980 if (mask == 0xFFFF) {
1985 cursor += pm_ctzll((uint64_t) (~mask & 0xFFFF));
1986 return (
size_t) (cursor - start);
1989 return (
size_t) (cursor - start);
1996#elif defined(PRISM_HAS_SWAR)
2008scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
2009 static const uint64_t ones = 0x0101010101010101ULL;
2010 static const uint64_t highs = 0x8080808080808080ULL;
2011 const uint8_t *cursor = start;
2013 while (cursor + 8 <= end) {
2015 memcpy(&word, cursor, 8);
2018 if (word & highs)
break;
2020 uint64_t digit = ((word | highs) - ones * 0x30) & ((ones * 0x39 | highs) - word) & highs;
2027 uint64_t lowered = word | (ones * 0x20);
2028 uint64_t letter = ((lowered | highs) - ones * 0x61) & ((ones * 0x7A | highs) - lowered) & highs;
2033 uint64_t xor_us = word ^ (ones * 0x5F);
2034 uint64_t underscore = (xor_us - ones) & ~xor_us & highs;
2036 uint64_t ident = digit | letter | underscore;
2038 if (ident == highs) {
2045 uint64_t not_ident = ~ident & highs;
2046 cursor += pm_ctzll(not_ident) / 8;
2047 return (
size_t) (cursor - start);
2050 return (
size_t) (cursor - start);
2057#define scan_identifier_ascii(start, end) ((size_t) 0)
2067char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
2070 }
else if (parser->encoding_changed) {
2073 if ((width = parser->encoding->alnum_char(b, n)) != 0) {
2075 }
else if (*b ==
'_') {
2077 }
else if (*b >= 0x80) {
2078 return parser->encoding->char_width(b, n);
2083 return char_is_identifier_utf8(b, n);
2090#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
2091#define PUNCT(idx) ( \
2092 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
2093 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
2094 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
2095 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
2096 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
2099const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
2104static PRISM_INLINE bool
2105char_is_global_name_punctuation(const uint8_t b) {
2106 const unsigned int i = (const unsigned int) b;
2107 if (i <= 0x20 || 0x7e < i) return false;
2109 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
2112static PRISM_INLINE bool
2113token_is_setter_name(pm_token_t *token) {
2115 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
2116 ((token->type == PM_TOKEN_IDENTIFIER) &&
2117 (token->end - token->start >= 2) &&
2118 (token->end[-1] == '='))
2126pm_local_is_keyword(const char *source, size_t length) {
2127#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
2131 switch (source[0]) {
2132 case 'd': KEYWORD("do"); return false;
2133 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
2134 case 'o': KEYWORD("or"); return false;
2135 default: return false;
2138 switch (source[0]) {
2139 case 'a': KEYWORD("and"); return false;
2140 case 'd': KEYWORD("def"); return false;
2141 case 'e': KEYWORD("end"); return false;
2142 case 'f': KEYWORD("for"); return false;
2143 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
2144 default: return false;
2147 switch (source[0]) {
2148 case 'c': KEYWORD("case"); return false;
2149 case 'e': KEYWORD("else"); return false;
2150 case 'n': KEYWORD("next"); return false;
2151 case 'r': KEYWORD("redo"); return false;
2152 case 's': KEYWORD("self"); return false;
2153 case 't': KEYWORD("then"); KEYWORD("true"); return false;
2154 case 'w': KEYWORD("when"); return false;
2155 default: return false;
2158 switch (source[0]) {
2159 case 'a': KEYWORD("alias"); return false;
2160 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
2161 case 'c': KEYWORD("class"); return false;
2162 case 'e': KEYWORD("elsif"); return false;
2163 case 'f': KEYWORD("false"); return false;
2164 case 'r': KEYWORD("retry"); return false;
2165 case 's': KEYWORD("super"); return false;
2166 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
2167 case 'w': KEYWORD("while"); return false;
2168 case 'y': KEYWORD("yield"); return false;
2169 default: return false;
2172 switch (source[0]) {
2173 case 'e': KEYWORD("ensure"); return false;
2174 case 'm': KEYWORD("module"); return false;
2175 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
2176 case 'u': KEYWORD("unless"); return false;
2177 default: return false;
2180 KEYWORD("__LINE__");
2181 KEYWORD("__FILE__");
2184 KEYWORD("__ENCODING__");
2193/******************************************************************************/
2194/* Node flag handling functions */
2195/******************************************************************************/
2200static PRISM_INLINE void
2201pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
2202 node->flags |= flag;
2208static PRISM_INLINE void
2209pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
2210 node->flags &= (pm_node_flags_t) ~flag;
2216static PRISM_INLINE void
2217pm_node_flag_set_repeated_parameter(pm_node_t *node) {
2218 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
2219 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
2220 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
2221 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
2222 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
2223 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
2224 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
2225 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
2227 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
2230/******************************************************************************/
2231/* Node creation functions */
2232/******************************************************************************/
2239#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)
2244static PRISM_INLINE pm_node_flags_t
2245pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
2246 pm_node_flags_t flags = 0;
2248 if (closing->type == PM_TOKEN_REGEXP_END) {
2249 pm_buffer_t unknown_flags = { 0 };
2251 // The closing delimiter is normally a single byte, so the options
2252 // follow it. A `\r\n` newline delimiter is two bytes, however, so we
2253 // skip past it to avoid misreading the trailing `\n` as an option.
2254 const uint8_t *flag = closing->start + 1;
2255 if ((closing->end - closing->start) >= 2 && closing->start[0] == '\r' && closing->start[1] == '\n') {
2259 for (; flag < closing->end; flag++) {
2261 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
2262 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
2263 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
2264 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
2266 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
2267 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
2268 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
2269 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
2271 default: pm_buffer_append_byte(&unknown_flags, *flag);
2275 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
2276 if (unknown_flags_length != 0) {
2277 const char *word = unknown_flags_length >= 2 ? "options" : "option";
2278 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
2280 pm_buffer_cleanup(&unknown_flags);
2286#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
2288static pm_statements_node_t *
2289pm_statements_node_create(pm_parser_t *parser);
2292pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
2295pm_statements_node_body_length(pm_statements_node_t *node);
2301static PRISM_INLINE void
2302pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
2303 if (integer->values != NULL) {
2304 size_t byte_size = integer->length * sizeof(uint32_t);
2305 uint32_t *old_values = integer->values;
2306 integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
2314static pm_error_recovery_node_t *
2315pm_error_recovery_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
2316 return pm_error_recovery_node_new(
2320 ((pm_location_t) { .start = start, .length = length }),
2328static pm_error_recovery_node_t *
2329pm_error_recovery_node_create_unexpected(pm_parser_t *parser, pm_node_t *unexpected) {
2330 return pm_error_recovery_node_new(
2334 unexpected->location,
2342static pm_alias_global_variable_node_t *
2343pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2344 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2346 return pm_alias_global_variable_node_new(
2350 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2353 TOK2LOC(parser, keyword)
2360static pm_alias_method_node_t *
2361pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2362 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2364 return pm_alias_method_node_new(
2368 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2371 TOK2LOC(parser, keyword)
2378static pm_alternation_pattern_node_t *
2379pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2380 return pm_alternation_pattern_node_new(
2384 PM_LOCATION_INIT_NODES(left, right),
2387 TOK2LOC(parser, operator)
2394static pm_and_node_t *
2395pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2396 pm_assert_value_expression(parser, left);
2398 return pm_and_node_new(
2402 PM_LOCATION_INIT_NODES(left, right),
2405 TOK2LOC(parser, operator)
2412static pm_arguments_node_t *
2413pm_arguments_node_create(pm_parser_t *parser) {
2414 return pm_arguments_node_new(
2418 PM_LOCATION_INIT_UNSET,
2419 ((pm_node_list_t) { 0 })
2427pm_arguments_node_size(pm_arguments_node_t *node) {
2428 return node->arguments.size;
2435pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
2436 if (pm_arguments_node_size(node) == 0) {
2437 PM_NODE_START_SET_NODE(node, argument);
2440 if (PM_NODE_END(node) < PM_NODE_END(argument)) {
2441 PM_NODE_LENGTH_SET_NODE(node, argument);
2444 pm_node_list_append(arena, &node->arguments, argument);
2446 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2447 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2448 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2450 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2458static pm_array_node_t *
2459pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2460 if (opening == NULL) {
2461 return pm_array_node_new(
2464 PM_NODE_FLAG_STATIC_LITERAL,
2465 PM_LOCATION_INIT_UNSET,
2466 ((pm_node_list_t) { 0 }),
2467 ((pm_location_t) { 0 }),
2468 ((pm_location_t) { 0 })
2471 return pm_array_node_new(
2474 PM_NODE_FLAG_STATIC_LITERAL,
2475 PM_LOCATION_INIT_TOKEN(parser, opening),
2476 ((pm_node_list_t) { 0 }),
2477 TOK2LOC(parser, opening),
2478 TOK2LOC(parser, opening)
2486static PRISM_INLINE void
2487pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
2488 if (!node->elements.size && !node->opening_loc.length) {
2489 PM_NODE_START_SET_NODE(node, element);
2492 pm_node_list_append(arena, &node->elements, element);
2493 PM_NODE_LENGTH_SET_NODE(node, element);
2495 // If the element is not a static literal, then the array is not a static
2496 // literal. Turn that flag off.
2497 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)) {
2498 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2501 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2502 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2510pm_array_node_close_set(const pm_parser_t *parser, pm_array_node_t *node, const pm_token_t *closing) {
2511 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == 0);
2512 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2513 node->closing_loc = TOK2LOC(parser, closing);
2520static pm_array_pattern_node_t *
2521pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2522 pm_array_pattern_node_t *node = pm_array_pattern_node_new(
2526 PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2528 ((pm_node_list_t) { 0 }),
2530 ((pm_node_list_t) { 0 }),
2531 ((pm_location_t) { 0 }),
2532 ((pm_location_t) { 0 })
2535 // For now we're going to just copy over each pointer manually. This could be
2536 // much more efficient, as we could instead resize the node list.
2537 bool found_rest = false;
2540 PM_NODE_LIST_FOREACH(nodes, index, child) {
2541 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2544 } else if (found_rest) {
2545 pm_node_list_append(parser->arena, &node->posts, child);
2547 pm_node_list_append(parser->arena, &node->requireds, child);
2557static pm_array_pattern_node_t *
2558pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2559 return pm_array_pattern_node_new(
2563 PM_LOCATION_INIT_NODE(rest),
2565 ((pm_node_list_t) { 0 }),
2567 ((pm_node_list_t) { 0 }),
2568 ((pm_location_t) { 0 }),
2569 ((pm_location_t) { 0 })
2577static pm_array_pattern_node_t *
2578pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2579 return pm_array_pattern_node_new(
2583 PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
2585 ((pm_node_list_t) { 0 }),
2587 ((pm_node_list_t) { 0 }),
2588 TOK2LOC(parser, opening),
2589 TOK2LOC(parser, closing)
2597static pm_array_pattern_node_t *
2598pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2599 return pm_array_pattern_node_new(
2603 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2605 ((pm_node_list_t) { 0 }),
2607 ((pm_node_list_t) { 0 }),
2608 TOK2LOC(parser, opening),
2609 TOK2LOC(parser, closing)
2613static PRISM_INLINE void
2614pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
2615 pm_node_list_append(arena, &node->requireds, inner);
2621static pm_assoc_node_t *
2622pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2625 if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
2626 end = PM_NODE_END(value);
2627 } else if (operator != NULL) {
2628 end = PM_TOKEN_END(parser, operator);
2630 end = PM_NODE_END(key);
2633 // Hash string keys will be frozen, so we can mark them as frozen here so
2634 // that the compiler picks them up and also when we check for static literal
2635 // on the keys it gets factored in.
2636 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2637 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2640 // If the key and value of this assoc node are both static literals, then
2641 // we can mark this node as a static literal.
2642 pm_node_flags_t flags = 0;
2644 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2645 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)
2647 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2650 return pm_assoc_node_new(
2654 ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
2657 NTOK2LOC(parser, operator)
2664static pm_assoc_splat_node_t *
2665pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2666 assert(operator->type == PM_TOKEN_USTAR_STAR);
2668 return pm_assoc_splat_node_new(
2672 (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
2674 TOK2LOC(parser, operator)
2681static pm_back_reference_read_node_t *
2682pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2683 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2685 return pm_back_reference_read_node_new(
2689 PM_LOCATION_INIT_TOKEN(parser, name),
2690 pm_parser_constant_id_token(parser, name)
2697static pm_begin_node_t *
2698pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2699 uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
2700 uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
2702 return pm_begin_node_new(
2706 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2707 NTOK2LOC(parser, begin_keyword),
2712 ((pm_location_t) { 0 })
2720pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2721 if (node->begin_keyword_loc.length == 0) {
2722 PM_NODE_START_SET_NODE(node, rescue_clause);
2724 PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
2725 node->rescue_clause = rescue_clause;
2732pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2733 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2734 PM_NODE_START_SET_NODE(node, else_clause);
2736 PM_NODE_LENGTH_SET_NODE(node, else_clause);
2737 node->else_clause = else_clause;
2744pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2745 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2746 PM_NODE_START_SET_NODE(node, ensure_clause);
2748 PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
2749 node->ensure_clause = ensure_clause;
2756pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
2757 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
2758 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
2759 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
2765static pm_block_argument_node_t *
2766pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2767 assert(operator->type == PM_TOKEN_UAMPERSAND);
2769 return pm_block_argument_node_new(
2773 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
2775 TOK2LOC(parser, operator)
2782static pm_block_node_t *
2783pm_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) {
2784 return pm_block_node_new(
2788 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2792 TOK2LOC(parser, opening),
2793 TOK2LOC(parser, closing)
2800static pm_block_parameter_node_t *
2801pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2802 assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2804 return pm_block_parameter_node_new(
2808 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
2809 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
2810 NTOK2LOC(parser, name),
2811 TOK2LOC(parser, operator)
2818static pm_block_parameters_node_t *
2819pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2821 if (opening != NULL) {
2822 start = PM_TOKEN_START(parser, opening);
2823 } else if (parameters != NULL) {
2824 start = PM_NODE_START(parameters);
2830 if (parameters != NULL) {
2831 end = PM_NODE_END(parameters);
2832 } else if (opening != NULL) {
2833 end = PM_TOKEN_END(parser, opening);
2838 return pm_block_parameters_node_new(
2842 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2844 ((pm_node_list_t) { 0 }),
2845 NTOK2LOC(parser, opening),
2846 ((pm_location_t) { 0 })
2854pm_block_parameters_node_closing_set(const pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_token_t *closing) {
2855 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == 0);
2856 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2857 node->closing_loc = TOK2LOC(parser, closing);
2863static pm_block_local_variable_node_t *
2864pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2865 return pm_block_local_variable_node_new(
2869 PM_LOCATION_INIT_TOKEN(parser, name),
2870 pm_parser_constant_id_token(parser, name)
2878pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2879 pm_node_list_append(arena, &node->locals, UP(local));
2881 if (PM_NODE_LENGTH(node) == 0) {
2882 PM_NODE_START_SET_NODE(node, local);
2885 PM_NODE_LENGTH_SET_NODE(node, local);
2891static pm_break_node_t *
2892pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2893 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2895 return pm_break_node_new(
2899 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
2901 TOK2LOC(parser, keyword)
2905// There are certain flags that we want to use internally but don't want to
2906// expose because they are not relevant beyond parsing. Therefore we'll define
2907// them here and not define them in config.yml/a header file.
2908static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2910static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2911static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2912static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2919static pm_call_node_t *
2920pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2921 return pm_call_node_new(
2925 PM_LOCATION_INIT_UNSET,
2927 ((pm_location_t) { 0 }),
2929 ((pm_location_t) { 0 }),
2930 ((pm_location_t) { 0 }),
2932 ((pm_location_t) { 0 }),
2933 ((pm_location_t) { 0 }),
2942static PRISM_INLINE pm_node_flags_t
2943pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2944 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2951static pm_call_node_t *
2952pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2953 pm_assert_value_expression(parser, receiver);
2955 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2956 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2957 flags |= PM_CALL_NODE_FLAGS_INDEX;
2960 pm_call_node_t *node = pm_call_node_create(parser, flags);
2962 PM_NODE_START_SET_NODE(node, receiver);
2964 const pm_location_t *end = pm_arguments_end(arguments);
2965 assert(end != NULL && "unreachable");
2966 PM_NODE_LENGTH_SET_LOCATION(node, end);
2968 node->receiver = receiver;
2969 node->message_loc.start = arguments->opening_loc.start;
2970 node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
2972 node->opening_loc = arguments->opening_loc;
2973 node->arguments = arguments->arguments;
2974 node->closing_loc = arguments->closing_loc;
2975 node->block = arguments->block;
2977 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2984static pm_call_node_t *
2985pm_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) {
2986 pm_assert_value_expression(parser, receiver);
2987 pm_assert_value_expression(parser, argument);
2989 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2991 PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
2992 PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
2994 node->receiver = receiver;
2995 node->message_loc = TOK2LOC(parser, operator);
2997 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2998 pm_arguments_node_arguments_append(parser->arena, arguments, argument);
2999 node->arguments = arguments;
3001 node->name = pm_parser_constant_id_token(parser, operator);
3005static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
3010static pm_call_node_t *
3011pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
3012 pm_assert_value_expression(parser, receiver);
3014 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3016 PM_NODE_START_SET_NODE(node, receiver);
3017 const pm_location_t *end = pm_arguments_end(arguments);
3019 PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
3021 PM_NODE_LENGTH_SET_LOCATION(node, end);
3024 node->receiver = receiver;
3025 node->call_operator_loc = TOK2LOC(parser, operator);
3026 node->message_loc = TOK2LOC(parser, message);
3027 node->opening_loc = arguments->opening_loc;
3028 node->arguments = arguments->arguments;
3029 node->closing_loc = arguments->closing_loc;
3030 node->block = arguments->block;
3032 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3033 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3040 node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
3047static pm_call_node_t *
3048pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
3049 pm_call_node_t *node = pm_call_node_create(parser, 0);
3050 node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
3052 node->receiver = receiver;
3053 node->arguments = arguments;
3055 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
3063static pm_call_node_t *
3064pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
3065 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3067 PM_NODE_START_SET_TOKEN(parser, node, message);
3068 const pm_location_t *end = pm_arguments_end(arguments);
3069 assert(end != NULL && "unreachable");
3070 PM_NODE_LENGTH_SET_LOCATION(node, end);
3072 node->message_loc = TOK2LOC(parser, message);
3073 node->opening_loc = arguments->opening_loc;
3074 node->arguments = arguments->arguments;
3075 node->closing_loc = arguments->closing_loc;
3076 node->block = arguments->block;
3078 node->name = pm_parser_constant_id_token(parser, message);
3086static pm_call_node_t *
3087pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
3088 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3090 node->base.location = (pm_location_t) { 0 };
3091 node->arguments = arguments;
3100static pm_call_node_t *
3101pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
3102 pm_assert_value_expression(parser, receiver);
3103 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
3105 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
3107 PM_NODE_START_SET_TOKEN(parser, node, message);
3108 if (arguments->closing_loc.length > 0) {
3109 PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
3111 assert(receiver != NULL);
3112 PM_NODE_LENGTH_SET_NODE(node, receiver);
3115 node->receiver = receiver;
3116 node->message_loc = TOK2LOC(parser, message);
3117 node->opening_loc = arguments->opening_loc;
3118 node->arguments = arguments->arguments;
3119 node->closing_loc = arguments->closing_loc;
3121 node->name = pm_parser_constant_id_constant(parser, "!", 1);
3128static pm_call_node_t *
3129pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
3130 pm_assert_value_expression(parser, receiver);
3132 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3134 PM_NODE_START_SET_NODE(node, receiver);
3135 const pm_location_t *end = pm_arguments_end(arguments);
3136 assert(end != NULL && "unreachable");
3137 PM_NODE_LENGTH_SET_LOCATION(node, end);
3139 node->receiver = receiver;
3140 node->call_operator_loc = TOK2LOC(parser, operator);
3141 node->opening_loc = arguments->opening_loc;
3142 node->arguments = arguments->arguments;
3143 node->closing_loc = arguments->closing_loc;
3144 node->block = arguments->block;
3146 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3147 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3150 node->name = pm_parser_constant_id_constant(parser, "call", 4);
3157static pm_call_node_t *
3158pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
3159 pm_assert_value_expression(parser, receiver);
3161 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3163 PM_NODE_START_SET_TOKEN(parser, node, operator);
3164 PM_NODE_LENGTH_SET_NODE(node, receiver);
3166 node->receiver = receiver;
3167 node->message_loc = TOK2LOC(parser, operator);
3169 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
3177static pm_call_node_t *
3178pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
3179 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3181 node->base.location = TOK2LOC(parser, message);
3182 node->message_loc = TOK2LOC(parser, message);
3184 node->name = pm_parser_constant_id_token(parser, message);
3192static PRISM_INLINE bool
3193pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
3195 (node->message_loc.length > 0) &&
3196 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
3197 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
3198 char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
3199 (node->opening_loc.length == 0) &&
3200 (node->arguments == NULL) &&
3201 (node->block == NULL)
3209pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
3210 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
3212 if (write_constant->length > 0) {
3213 size_t length = write_constant->length - 1;
3215 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
3216 memcpy(memory, write_constant->start, length);
3218 *read_name = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, memory, length);
3220 // We can get here if the message was missing because of a syntax error.
3221 *read_name = pm_parser_constant_id_constant(parser, "", 0);
3228static pm_call_and_write_node_t *
3229pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3230 assert(target->block == NULL);
3231 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3233 pm_call_and_write_node_t *node = pm_call_and_write_node_new(
3237 PM_LOCATION_INIT_NODES(target, value),
3239 target->call_operator_loc,
3240 target->message_loc,
3243 TOK2LOC(parser, operator),
3247 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3249 // The target is no longer necessary because we've reused its children.
3250 // It is arena-allocated so no explicit free is needed.
3260pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
3261 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
3262 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
3264 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
3265 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
3266 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
3272 if (block != NULL) {
3273 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
3281static pm_index_and_write_node_t *
3282pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3283 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3285 pm_index_arguments_check(parser, target->arguments, target->block);
3287 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3289 pm_index_and_write_node_t *node = pm_index_and_write_node_new(
3293 PM_LOCATION_INIT_NODES(target, value),
3295 target->call_operator_loc,
3296 target->opening_loc,
3298 target->closing_loc,
3299 (pm_block_argument_node_t *) target->block,
3300 TOK2LOC(parser, operator),
3304 // The target is no longer necessary because we've reused its children.
3305 // It is arena-allocated so no explicit free is needed.
3313static pm_call_operator_write_node_t *
3314pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3315 assert(target->block == NULL);
3317 pm_call_operator_write_node_t *node = pm_call_operator_write_node_new(
3321 PM_LOCATION_INIT_NODES(target, value),
3323 target->call_operator_loc,
3324 target->message_loc,
3327 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3328 TOK2LOC(parser, operator),
3332 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3334 // The target is no longer necessary because we've reused its children.
3335 // It is arena-allocated so no explicit free is needed.
3343static pm_index_operator_write_node_t *
3344pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3345 pm_index_arguments_check(parser, target->arguments, target->block);
3347 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3349 pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
3353 PM_LOCATION_INIT_NODES(target, value),
3355 target->call_operator_loc,
3356 target->opening_loc,
3358 target->closing_loc,
3359 (pm_block_argument_node_t *) target->block,
3360 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3361 TOK2LOC(parser, operator),
3365 // The target is no longer necessary because we've reused its children.
3366 // It is arena-allocated so no explicit free is needed.
3374static pm_call_or_write_node_t *
3375pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3376 assert(target->block == NULL);
3377 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3379 pm_call_or_write_node_t *node = pm_call_or_write_node_new(
3383 PM_LOCATION_INIT_NODES(target, value),
3385 target->call_operator_loc,
3386 target->message_loc,
3389 TOK2LOC(parser, operator),
3393 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3395 // The target is no longer necessary because we've reused its children.
3396 // It is arena-allocated so no explicit free is needed.
3404static pm_index_or_write_node_t *
3405pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3406 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3408 pm_index_arguments_check(parser, target->arguments, target->block);
3410 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3412 pm_index_or_write_node_t *node = pm_index_or_write_node_new(
3416 PM_LOCATION_INIT_NODES(target, value),
3418 target->call_operator_loc,
3419 target->opening_loc,
3421 target->closing_loc,
3422 (pm_block_argument_node_t *) target->block,
3423 TOK2LOC(parser, operator),
3427 // The target is no longer necessary because we've reused its children.
3428 // It is arena-allocated so no explicit free is needed.
3437static pm_call_target_node_t *
3438pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3439 pm_call_target_node_t *node = pm_call_target_node_new(
3443 PM_LOCATION_INIT_NODE(target),
3445 target->call_operator_loc,
3450 /* It is possible to get here where we have parsed an invalid syntax tree
3451 * where the call operator was not present. In that case we will have a
3452 * problem because it is a required location. In this case we need to fill
3453 * it in with a fake location so that the syntax tree remains valid. */
3454 if (node->call_operator_loc.length == 0) {
3455 node->call_operator_loc = target->base.location;
3458 // The target is no longer necessary because we've reused its children.
3459 // It is arena-allocated so no explicit free is needed.
3468static pm_index_target_node_t *
3469pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3470 pm_index_arguments_check(parser, target->arguments, target->block);
3471 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3473 pm_index_target_node_t *node = pm_index_target_node_new(
3476 FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3477 PM_LOCATION_INIT_NODE(target),
3479 target->opening_loc,
3481 target->closing_loc,
3482 (pm_block_argument_node_t *) target->block
3485 // The target is no longer necessary because we've reused its children.
3486 // It is arena-allocated so no explicit free is needed.
3494static pm_capture_pattern_node_t *
3495pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3496 return pm_capture_pattern_node_new(
3500 PM_LOCATION_INIT_NODES(value, target),
3503 TOK2LOC(parser, operator)
3510static pm_case_node_t *
3511pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3512 return pm_case_node_new(
3516 PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
3518 ((pm_node_list_t) { 0 }),
3520 TOK2LOC(parser, case_keyword),
3521 NTOK2LOC(parser, end_keyword)
3529pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
3530 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3532 pm_node_list_append(arena, &node->conditions, condition);
3533 PM_NODE_LENGTH_SET_NODE(node, condition);
3540pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3541 node->else_clause = else_clause;
3542 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3549pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
3550 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3551 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3557static pm_case_match_node_t *
3558pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
3559 return pm_case_match_node_new(
3563 PM_LOCATION_INIT_TOKEN(parser, case_keyword),
3565 ((pm_node_list_t) { 0 }),
3567 TOK2LOC(parser, case_keyword),
3568 ((pm_location_t) { 0 })
3576pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
3577 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3579 pm_node_list_append(arena, &node->conditions, condition);
3580 PM_NODE_LENGTH_SET_NODE(node, condition);
3587pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3588 node->else_clause = else_clause;
3589 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3596pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3597 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3598 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3604static pm_class_node_t *
3605pm_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) {
3606 return pm_class_node_new(
3610 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
3612 TOK2LOC(parser, class_keyword),
3614 NTOK2LOC(parser, inheritance_operator),
3617 TOK2LOC(parser, end_keyword),
3618 pm_parser_constant_id_token(parser, name)
3625static pm_class_variable_and_write_node_t *
3626pm_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) {
3627 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3629 return pm_class_variable_and_write_node_new(
3633 PM_LOCATION_INIT_NODES(target, value),
3635 target->base.location,
3636 TOK2LOC(parser, operator),
3644static pm_class_variable_operator_write_node_t *
3645pm_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) {
3646 return pm_class_variable_operator_write_node_new(
3650 PM_LOCATION_INIT_NODES(target, value),
3652 target->base.location,
3653 TOK2LOC(parser, operator),
3655 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3662static pm_class_variable_or_write_node_t *
3663pm_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) {
3664 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3666 return pm_class_variable_or_write_node_new(
3670 PM_LOCATION_INIT_NODES(target, value),
3672 target->base.location,
3673 TOK2LOC(parser, operator),
3681static pm_class_variable_read_node_t *
3682pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3683 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3685 return pm_class_variable_read_node_new(
3689 PM_LOCATION_INIT_TOKEN(parser, token),
3690 pm_parser_constant_id_token(parser, token)
3700static PRISM_INLINE pm_node_flags_t
3701pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3702 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
3711static pm_class_variable_write_node_t *
3712pm_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) {
3713 return pm_class_variable_write_node_new(
3716 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3717 PM_LOCATION_INIT_NODES(read_node, value),
3719 read_node->base.location,
3721 TOK2LOC(parser, operator)
3728static pm_constant_path_and_write_node_t *
3729pm_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) {
3730 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3732 return pm_constant_path_and_write_node_new(
3736 PM_LOCATION_INIT_NODES(target, value),
3738 TOK2LOC(parser, operator),
3746static pm_constant_path_operator_write_node_t *
3747pm_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) {
3748 return pm_constant_path_operator_write_node_new(
3752 PM_LOCATION_INIT_NODES(target, value),
3754 TOK2LOC(parser, operator),
3756 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3763static pm_constant_path_or_write_node_t *
3764pm_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) {
3765 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3767 return pm_constant_path_or_write_node_new(
3771 PM_LOCATION_INIT_NODES(target, value),
3773 TOK2LOC(parser, operator),
3781static pm_constant_path_node_t *
3782pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3783 pm_assert_value_expression(parser, parent);
3785 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3786 if (name_token->type == PM_TOKEN_CONSTANT) {
3787 name = pm_parser_constant_id_token(parser, name_token);
3790 return pm_constant_path_node_new(
3794 (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
3797 TOK2LOC(parser, delimiter),
3798 TOK2LOC(parser, name_token)
3805static pm_constant_path_write_node_t *
3806pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3807 return pm_constant_path_write_node_new(
3810 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3811 PM_LOCATION_INIT_NODES(target, value),
3813 TOK2LOC(parser, operator),
3821static pm_constant_and_write_node_t *
3822pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3823 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3825 return pm_constant_and_write_node_new(
3829 PM_LOCATION_INIT_NODES(target, value),
3831 target->base.location,
3832 TOK2LOC(parser, operator),
3840static pm_constant_operator_write_node_t *
3841pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3842 return pm_constant_operator_write_node_new(
3846 PM_LOCATION_INIT_NODES(target, value),
3848 target->base.location,
3849 TOK2LOC(parser, operator),
3851 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3858static pm_constant_or_write_node_t *
3859pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3860 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3862 return pm_constant_or_write_node_new(
3866 PM_LOCATION_INIT_NODES(target, value),
3868 target->base.location,
3869 TOK2LOC(parser, operator),
3877static pm_constant_read_node_t *
3878pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3879 assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
3881 return pm_constant_read_node_new(
3885 PM_LOCATION_INIT_TOKEN(parser, name),
3886 pm_parser_constant_id_token(parser, name)
3893static pm_constant_write_node_t *
3894pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3895 return pm_constant_write_node_new(
3898 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3899 PM_LOCATION_INIT_NODES(target, value),
3901 target->base.location,
3903 TOK2LOC(parser, operator)
3911pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3912 switch (PM_NODE_TYPE(node)) {
3913 case PM_BEGIN_NODE: {
3914 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3915 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3918 case PM_PARENTHESES_NODE: {
3919 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3920 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3923 case PM_STATEMENTS_NODE: {
3924 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3925 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3930 case PM_IMAGINARY_NODE:
3931 case PM_INTEGER_NODE:
3932 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3933 case PM_INTERPOLATED_STRING_NODE:
3934 case PM_INTERPOLATED_SYMBOL_NODE:
3935 case PM_INTERPOLATED_X_STRING_NODE:
3936 case PM_RATIONAL_NODE:
3937 case PM_REGULAR_EXPRESSION_NODE:
3938 case PM_SOURCE_ENCODING_NODE:
3939 case PM_SOURCE_FILE_NODE:
3940 case PM_SOURCE_LINE_NODE:
3941 case PM_STRING_NODE:
3942 case PM_SYMBOL_NODE:
3943 case PM_X_STRING_NODE:
3944 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3954static pm_def_node_t *
3956 pm_parser_t *parser,
3957 pm_constant_id_t name,
3958 const pm_token_t *name_loc,
3959 pm_node_t *receiver,
3960 pm_parameters_node_t *parameters,
3962 pm_constant_id_list_t *locals,
3963 const pm_token_t *def_keyword,
3964 const pm_token_t *operator,
3965 const pm_token_t *lparen,
3966 const pm_token_t *rparen,
3967 const pm_token_t *equal,
3968 const pm_token_t *end_keyword
3970 if (receiver != NULL) {
3971 pm_def_node_receiver_check(parser, receiver);
3974 return pm_def_node_new(
3978 (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
3980 TOK2LOC(parser, name_loc),
3985 TOK2LOC(parser, def_keyword),
3986 NTOK2LOC(parser, operator),
3987 NTOK2LOC(parser, lparen),
3988 NTOK2LOC(parser, rparen),
3989 NTOK2LOC(parser, equal),
3990 NTOK2LOC(parser, end_keyword)
3997static pm_defined_node_t *
3998pm_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) {
3999 return pm_defined_node_new(
4003 (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
4004 NTOK2LOC(parser, lparen),
4006 NTOK2LOC(parser, rparen),
4007 TOK2LOC(parser, keyword)
4014static pm_else_node_t *
4015pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4016 return pm_else_node_new(
4020 ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
4021 TOK2LOC(parser, else_keyword),
4023 NTOK2LOC(parser, end_keyword)
4030static pm_embedded_statements_node_t *
4031pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
4032 return pm_embedded_statements_node_new(
4036 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4037 TOK2LOC(parser, opening),
4039 TOK2LOC(parser, closing)
4046static pm_embedded_variable_node_t *
4047pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
4048 return pm_embedded_variable_node_new(
4052 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
4053 TOK2LOC(parser, operator),
4061static pm_ensure_node_t *
4062pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4063 return pm_ensure_node_new(
4067 PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
4068 TOK2LOC(parser, ensure_keyword),
4070 TOK2LOC(parser, end_keyword)
4077static pm_false_node_t *
4078pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4079 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4081 return pm_false_node_new(
4084 PM_NODE_FLAG_STATIC_LITERAL,
4085 PM_LOCATION_INIT_TOKEN(parser, token)
4093static pm_find_pattern_node_t *
4094pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4095 assert(nodes->size >= 2);
4096 pm_node_t *left = nodes->nodes[0];
4097 pm_node_t *right = nodes->nodes[nodes->size - 1];
4099 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4100 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4102 pm_find_pattern_node_t *node = pm_find_pattern_node_new(
4106 PM_LOCATION_INIT_NODES(left, right),
4108 (pm_splat_node_t *) left,
4109 ((pm_node_list_t) { 0 }),
4110 (pm_splat_node_t *) right,
4111 ((pm_location_t) { 0 }),
4112 ((pm_location_t) { 0 })
4115 // For now we're going to just copy over each pointer manually. This could be
4116 // much more efficient, as we could instead resize the node list to only point
4118 for (size_t index = 1; index < nodes->size - 1; index++) {
4119 pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
4130pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4131 ptrdiff_t diff = token->end - token->start;
4132 if (diff <= 0) return 0.0;
4134 // First, get a buffer of the content.
4135 size_t length = (size_t) diff;
4136 const size_t buffer_size = sizeof(char) * (length + 1);
4137 char *buffer = xmalloc(buffer_size);
4138 memcpy((void *) buffer, token->start, length);
4140 // Next, determine if we need to replace the decimal point because of
4141 // locale-specific options, and then normalize them if we have to.
4142 char decimal_point = *localeconv()->decimal_point;
4143 if (decimal_point != '.') {
4144 for (size_t index = 0; index < length; index++) {
4145 if (buffer[index] == '.') buffer[index] = decimal_point;
4150 * Next, handle underscores by removing them from the buffer in a single
4151 * pass to avoid quadratic-time copies.
4155 for (size_t read = 0; read < length; read++) {
4156 if (buffer[read] != '_') buffer[write++] = buffer[read];
4161 // Null-terminate the buffer so that strtod cannot read off the end.
4162 buffer[length] = '\0';
4164 // Now, call strtod to parse the value. Note that CRuby has their own
4165 // version of strtod which avoids locales. We're okay using the locale-aware
4166 // version because we've already validated through the parser that the token
4167 // is in a valid format.
4170 double value = strtod(buffer, &eptr);
4172 // This should never happen, because we've already checked that the token
4173 // is in a valid format. However it's good to be safe.
4174 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4175 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
4176 xfree_sized(buffer, buffer_size);
4180 // If errno is set, then it should only be ERANGE. At this point we need to
4181 // check if it's infinity (it should be).
4182 if (errno == ERANGE && PRISM_ISINF(value)) {
4184 const char *ellipsis;
4190 warn_width = (int) length;
4194 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);
4195 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4198 // Finally we can free the buffer and return the value.
4199 xfree_sized(buffer, buffer_size);
4206static pm_float_node_t *
4207pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4208 assert(token->type == PM_TOKEN_FLOAT);
4210 return pm_float_node_new(
4213 PM_NODE_FLAG_STATIC_LITERAL,
4214 PM_LOCATION_INIT_TOKEN(parser, token),
4215 pm_double_parse(parser, token)
4222static pm_imaginary_node_t *
4223pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4224 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4226 return pm_imaginary_node_new(
4229 PM_NODE_FLAG_STATIC_LITERAL,
4230 PM_LOCATION_INIT_TOKEN(parser, token),
4231 UP(pm_float_node_create(parser, &((pm_token_t) {
4232 .type = PM_TOKEN_FLOAT,
4233 .start = token->start,
4234 .end = token->end - 1
4242static pm_rational_node_t *
4243pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4244 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4246 pm_rational_node_t *node = pm_rational_node_new(
4249 PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4250 PM_LOCATION_INIT_TOKEN(parser, token),
4251 ((pm_integer_t) { 0 }),
4252 ((pm_integer_t) { 0 })
4255 const uint8_t *start = token->start;
4256 const uint8_t *end = token->end - 1; // r
4258 while (start < end && *start == '0') start++; // 0.1 -> .1
4259 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4261 size_t length = (size_t) (end - start);
4263 node->denominator.value = 1;
4267 const uint8_t *point = memchr(start, '.', length);
4268 assert(point && "should have a decimal point");
4270 uint8_t *digits = xmalloc(length);
4271 if (digits == NULL) {
4272 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4276 memcpy(digits, start, (unsigned long) (point - start));
4277 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4278 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4280 size_t fract_length = 0;
4281 for (const uint8_t *fract = point; fract < end; ++fract) {
4282 if (*fract != '_') ++fract_length;
4285 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
4286 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
4287 xfree_sized(digits, length);
4289 pm_integers_reduce(&node->numerator, &node->denominator);
4290 pm_integer_arena_move(parser->arena, &node->numerator);
4291 pm_integer_arena_move(parser->arena, &node->denominator);
4299static pm_imaginary_node_t *
4300pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4301 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4303 return pm_imaginary_node_new(
4306 PM_NODE_FLAG_STATIC_LITERAL,
4307 PM_LOCATION_INIT_TOKEN(parser, token),
4308 UP(pm_float_node_rational_create(parser, &((pm_token_t) {
4309 .type = PM_TOKEN_FLOAT_RATIONAL,
4310 .start = token->start,
4311 .end = token->end - 1
4319static pm_for_node_t *
4321 pm_parser_t *parser,
4323 pm_node_t *collection,
4324 pm_statements_node_t *statements,
4325 const pm_token_t *for_keyword,
4326 const pm_token_t *in_keyword,
4327 const pm_token_t *do_keyword,
4328 const pm_token_t *end_keyword
4330 return pm_for_node_new(
4334 PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
4338 TOK2LOC(parser, for_keyword),
4339 TOK2LOC(parser, in_keyword),
4340 NTOK2LOC(parser, do_keyword),
4341 TOK2LOC(parser, end_keyword)
4348static pm_forwarding_arguments_node_t *
4349pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4350 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4352 return pm_forwarding_arguments_node_new(
4356 PM_LOCATION_INIT_TOKEN(parser, token)
4363static pm_forwarding_parameter_node_t *
4364pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4365 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4367 return pm_forwarding_parameter_node_new(
4371 PM_LOCATION_INIT_TOKEN(parser, token)
4378static pm_forwarding_super_node_t *
4379pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4380 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4381 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4383 pm_block_node_t *block = NULL;
4384 if (arguments->block != NULL) {
4385 block = (pm_block_node_t *) arguments->block;
4388 return pm_forwarding_super_node_new(
4392 (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
4393 PM_LOCATION_INIT_TOKEN(parser, token),
4402static pm_hash_pattern_node_t *
4403pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4404 return pm_hash_pattern_node_new(
4408 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4410 ((pm_node_list_t) { 0 }),
4412 TOK2LOC(parser, opening),
4413 TOK2LOC(parser, closing)
4420static pm_hash_pattern_node_t *
4421pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4425 if (elements->size > 0) {
4427 start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
4428 end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
4430 start = PM_NODE_START(elements->nodes[0]);
4431 end = PM_NODE_END(elements->nodes[elements->size - 1]);
4434 assert(rest != NULL);
4435 start = PM_NODE_START(rest);
4436 end = PM_NODE_END(rest);
4439 pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
4443 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4445 ((pm_node_list_t) { 0 }),
4447 ((pm_location_t) { 0 }),
4448 ((pm_location_t) { 0 })
4451 pm_node_list_concat(parser->arena, &node->elements, elements);
4458static pm_constant_id_t
4459pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4460 switch (PM_NODE_TYPE(target)) {
4461 case PM_GLOBAL_VARIABLE_READ_NODE:
4462 return ((pm_global_variable_read_node_t *) target)->name;
4463 case PM_BACK_REFERENCE_READ_NODE:
4464 return ((pm_back_reference_read_node_t *) target)->name;
4465 case PM_NUMBERED_REFERENCE_READ_NODE:
4466 // This will only ever happen in the event of a syntax error, but we
4467 // still need to provide something for the node.
4468 return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
4470 assert(false && "unreachable");
4471 return (pm_constant_id_t) -1;
4478static pm_global_variable_and_write_node_t *
4479pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4480 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4482 return pm_global_variable_and_write_node_new(
4486 PM_LOCATION_INIT_NODES(target, value),
4487 pm_global_variable_write_name(parser, target),
4489 TOK2LOC(parser, operator),
4497static pm_global_variable_operator_write_node_t *
4498pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4499 return pm_global_variable_operator_write_node_new(
4503 PM_LOCATION_INIT_NODES(target, value),
4504 pm_global_variable_write_name(parser, target),
4506 TOK2LOC(parser, operator),
4508 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4515static pm_global_variable_or_write_node_t *
4516pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4517 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4519 return pm_global_variable_or_write_node_new(
4523 PM_LOCATION_INIT_NODES(target, value),
4524 pm_global_variable_write_name(parser, target),
4526 TOK2LOC(parser, operator),
4534static pm_global_variable_read_node_t *
4535pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4536 return pm_global_variable_read_node_new(
4540 PM_LOCATION_INIT_TOKEN(parser, name),
4541 pm_parser_constant_id_token(parser, name)
4548static pm_global_variable_read_node_t *
4549pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4550 return pm_global_variable_read_node_new(
4554 PM_LOCATION_INIT_UNSET,
4562static pm_global_variable_write_node_t *
4563pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4564 return pm_global_variable_write_node_new(
4567 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4568 PM_LOCATION_INIT_NODES(target, value),
4569 pm_global_variable_write_name(parser, target),
4572 TOK2LOC(parser, operator)
4579static pm_global_variable_write_node_t *
4580pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4581 return pm_global_variable_write_node_new(
4585 PM_LOCATION_INIT_UNSET,
4587 ((pm_location_t) { 0 }),
4589 ((pm_location_t) { 0 })
4596static pm_hash_node_t *
4597pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4598 assert(opening != NULL);
4600 return pm_hash_node_new(
4603 PM_NODE_FLAG_STATIC_LITERAL,
4604 PM_LOCATION_INIT_TOKEN(parser, opening),
4605 TOK2LOC(parser, opening),
4606 ((pm_node_list_t) { 0 }),
4607 ((pm_location_t) { 0 })
4614static PRISM_INLINE void
4615pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
4616 pm_node_list_append(arena, &hash->elements, element);
4618 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4619 if (static_literal) {
4620 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4621 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);
4622 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4623 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4626 if (!static_literal) {
4627 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4631static PRISM_INLINE void
4632pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
4633 PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
4634 hash->closing_loc = TOK2LOC(parser, token);
4640static pm_if_node_t *
4641pm_if_node_create(pm_parser_t *parser,
4642 const pm_token_t *if_keyword,
4643 pm_node_t *predicate,
4644 const pm_token_t *then_keyword,
4645 pm_statements_node_t *statements,
4646 pm_node_t *subsequent,
4647 const pm_token_t *end_keyword
4649 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4651 uint32_t start = PM_TOKEN_START(parser, if_keyword);
4654 if (end_keyword != NULL) {
4655 end = PM_TOKEN_END(parser, end_keyword);
4656 } else if (subsequent != NULL) {
4657 end = PM_NODE_END(subsequent);
4658 } else if (pm_statements_node_body_length(statements) != 0) {
4659 end = PM_NODE_END(statements);
4661 end = PM_NODE_END(predicate);
4664 return pm_if_node_new(
4667 PM_NODE_FLAG_NEWLINE,
4668 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4669 TOK2LOC(parser, if_keyword),
4671 NTOK2LOC(parser, then_keyword),
4674 NTOK2LOC(parser, end_keyword)
4681static pm_if_node_t *
4682pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4683 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4685 pm_statements_node_t *statements = pm_statements_node_create(parser);
4686 pm_statements_node_body_append(parser, statements, statement, true);
4688 return pm_if_node_new(
4691 PM_NODE_FLAG_NEWLINE,
4692 PM_LOCATION_INIT_NODES(statement, predicate),
4693 TOK2LOC(parser, if_keyword),
4695 ((pm_location_t) { 0 }),
4698 ((pm_location_t) { 0 })
4705static pm_if_node_t *
4706pm_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) {
4707 pm_assert_value_expression(parser, predicate);
4708 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4710 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4711 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4713 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4714 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4716 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
4717 return pm_if_node_new(
4720 PM_NODE_FLAG_NEWLINE,
4721 PM_LOCATION_INIT_NODES(predicate, false_expression),
4722 ((pm_location_t) { 0 }),
4724 TOK2LOC(parser, qmark),
4727 ((pm_location_t) { 0 })
4731static PRISM_INLINE void
4732pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
4733 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4734 node->end_keyword_loc = TOK2LOC(parser, keyword);
4737static PRISM_INLINE void
4738pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
4739 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4740 node->end_keyword_loc = TOK2LOC(parser, keyword);
4746static pm_implicit_node_t *
4747pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4748 return pm_implicit_node_new(
4752 PM_LOCATION_INIT_NODE(value),
4760static pm_implicit_rest_node_t *
4761pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4762 assert(token->type == PM_TOKEN_COMMA);
4764 return pm_implicit_rest_node_new(
4768 PM_LOCATION_INIT_TOKEN(parser, token)
4775static pm_integer_node_t *
4776pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4777 assert(token->type == PM_TOKEN_INTEGER);
4779 pm_integer_node_t *node = pm_integer_node_new(
4782 base | PM_NODE_FLAG_STATIC_LITERAL,
4783 PM_LOCATION_INIT_TOKEN(parser, token),
4784 ((pm_integer_t) { 0 })
4787 if (parser->integer.lexed) {
4788 // The value was already computed during lexing.
4789 node->value.value = parser->integer.value;
4790 parser->integer.lexed = false;
4792 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4794 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4795 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4796 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4797 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4798 default: assert(false && "unreachable"); break;
4801 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4802 pm_integer_arena_move(parser->arena, &node->value);
4812static pm_imaginary_node_t *
4813pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4814 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4816 return pm_imaginary_node_new(
4819 PM_NODE_FLAG_STATIC_LITERAL,
4820 PM_LOCATION_INIT_TOKEN(parser, token),
4821 UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4822 .type = PM_TOKEN_INTEGER,
4823 .start = token->start,
4824 .end = token->end - 1
4833static pm_rational_node_t *
4834pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4835 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4837 pm_rational_node_t *node = pm_rational_node_new(
4840 base | PM_NODE_FLAG_STATIC_LITERAL,
4841 PM_LOCATION_INIT_TOKEN(parser, token),
4842 ((pm_integer_t) { 0 }),
4843 ((pm_integer_t) { .value = 1 })
4846 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4848 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4849 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4850 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4851 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4852 default: assert(false && "unreachable"); break;
4855 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4856 pm_integer_arena_move(parser->arena, &node->numerator);
4865static pm_imaginary_node_t *
4866pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4867 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4869 return pm_imaginary_node_new(
4872 PM_NODE_FLAG_STATIC_LITERAL,
4873 PM_LOCATION_INIT_TOKEN(parser, token),
4874 UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4875 .type = PM_TOKEN_INTEGER_RATIONAL,
4876 .start = token->start,
4877 .end = token->end - 1
4885static pm_in_node_t *
4886pm_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) {
4887 uint32_t start = PM_TOKEN_START(parser, in_keyword);
4890 if (statements != NULL) {
4891 end = PM_NODE_END(statements);
4892 } else if (then_keyword != NULL) {
4893 end = PM_TOKEN_END(parser, then_keyword);
4895 end = PM_NODE_END(pattern);
4898 return pm_in_node_new(
4902 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4905 TOK2LOC(parser, in_keyword),
4906 NTOK2LOC(parser, then_keyword)
4913static pm_instance_variable_and_write_node_t *
4914pm_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) {
4915 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4917 return pm_instance_variable_and_write_node_new(
4921 PM_LOCATION_INIT_NODES(target, value),
4923 target->base.location,
4924 TOK2LOC(parser, operator),
4932static pm_instance_variable_operator_write_node_t *
4933pm_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) {
4934 return pm_instance_variable_operator_write_node_new(
4938 PM_LOCATION_INIT_NODES(target, value),
4940 target->base.location,
4941 TOK2LOC(parser, operator),
4943 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4950static pm_instance_variable_or_write_node_t *
4951pm_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) {
4952 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4954 return pm_instance_variable_or_write_node_new(
4958 PM_LOCATION_INIT_NODES(target, value),
4960 target->base.location,
4961 TOK2LOC(parser, operator),
4969static pm_instance_variable_read_node_t *
4970pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4971 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4973 return pm_instance_variable_read_node_new(
4977 PM_LOCATION_INIT_TOKEN(parser, token),
4978 pm_parser_constant_id_token(parser, token)
4986static pm_instance_variable_write_node_t *
4987pm_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) {
4988 return pm_instance_variable_write_node_new(
4991 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4992 PM_LOCATION_INIT_NODES(read_node, value),
4994 read_node->base.location,
4996 TOK2LOC(parser, operator)
5006pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5007 switch (PM_NODE_TYPE(part)) {
5008 case PM_STRING_NODE:
5009 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5011 case PM_EMBEDDED_STATEMENTS_NODE: {
5012 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5013 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5015 if (embedded == NULL) {
5016 // If there are no statements or more than one statement, then
5017 // we lose the static literal flag.
5018 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5019 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5020 // If the embedded statement is a string, then we can keep the
5021 // static literal flag and mark the string as frozen.
5022 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5023 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5024 // If the embedded statement is an interpolated string and it's
5025 // a static literal, then we can keep the static literal flag.
5027 // Otherwise we lose the static literal flag.
5028 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5033 case PM_EMBEDDED_VARIABLE_NODE:
5034 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5037 assert(false && "unexpected node type");
5041 pm_node_list_append(arena, parts, part);
5047static pm_interpolated_regular_expression_node_t *
5048pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5049 return pm_interpolated_regular_expression_node_new(
5052 PM_NODE_FLAG_STATIC_LITERAL,
5053 PM_LOCATION_INIT_TOKEN(parser, opening),
5054 TOK2LOC(parser, opening),
5055 ((pm_node_list_t) { 0 }),
5056 TOK2LOC(parser, opening)
5060static PRISM_INLINE void
5061pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5062 if (PM_NODE_START(node) > PM_NODE_START(part)) {
5063 PM_NODE_START_SET_NODE(node, part);
5065 if (PM_NODE_END(node) < PM_NODE_END(part)) {
5066 PM_NODE_LENGTH_SET_NODE(node, part);
5069 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5072static PRISM_INLINE void
5073pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5074 node->closing_loc = TOK2LOC(parser, closing);
5075 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5076 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
5102static PRISM_INLINE void
5103pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
5104 pm_arena_t *arena = parser->arena;
5105#define CLEAR_FLAGS(node) \
5106 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))
5108#define MUTABLE_FLAGS(node) \
5109 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5111 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5112 PM_NODE_START_SET_NODE(node, part);
5115 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5116 PM_NODE_LENGTH_SET_NODE(node, part);
5119 switch (PM_NODE_TYPE(part)) {
5120 case PM_STRING_NODE:
5121 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5122 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5123 // as long as this interpolation only consists of other string literals.
5124 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5125 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5127 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5129 case PM_INTERPOLATED_STRING_NODE:
5130 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5131 // If the string that we're concatenating is a static literal,
5132 // then we can keep the static literal flag for this string.
5134 // Otherwise, we lose the static literal flag here and we should
5135 // also clear the mutability flags.
5139 case PM_EMBEDDED_STATEMENTS_NODE: {
5140 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5141 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5143 if (embedded == NULL) {
5144 // If we're embedding multiple statements or no statements, then
5145 // the string is not longer a static literal.
5147 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5148 // If the embedded statement is a string, then we can make that
5149 // string as frozen and static literal, and not touch the static
5150 // literal status of this string.
5151 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5153 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5154 MUTABLE_FLAGS(node);
5156 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5157 // If the embedded statement is an interpolated string, but that
5158 // string is marked as static literal, then we can keep our
5159 // static literal status for this string.
5160 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5161 MUTABLE_FLAGS(node);
5164 // In all other cases, we lose the static literal flag here and
5171 case PM_EMBEDDED_VARIABLE_NODE:
5172 // Embedded variables clear static literal, which means we also
5173 // should clear the mutability flags.
5176 case PM_X_STRING_NODE:
5177 case PM_INTERPOLATED_X_STRING_NODE:
5178 case PM_SYMBOL_NODE:
5179 case PM_INTERPOLATED_SYMBOL_NODE:
5180 // These will only happen in error cases. But we want to handle it
5181 // here so that we don't fail the assertion.
5183 pm_node_list_append(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
5185 case PM_ERROR_RECOVERY_NODE:
5189 assert(false && "unexpected node type");
5193 pm_node_list_append(arena, &node->parts, part);
5202static pm_interpolated_string_node_t *
5203pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5204 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5206 switch (parser->frozen_string_literal) {
5207 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5208 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5210 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5211 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5215 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5216 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5218 pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
5222 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5223 NTOK2LOC(parser, opening),
5224 ((pm_node_list_t) { 0 }),
5225 NTOK2LOC(parser, closing)
5228 if (parts != NULL) {
5230 PM_NODE_LIST_FOREACH(parts, index, part) {
5231 pm_interpolated_string_node_append(parser, node, part);
5242pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5243 node->closing_loc = TOK2LOC(parser, closing);
5244 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5248pm_interpolated_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5249 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5250 PM_NODE_START_SET_NODE(node, part);
5253 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5255 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5256 PM_NODE_LENGTH_SET_NODE(node, part);
5261pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5262 node->closing_loc = TOK2LOC(parser, closing);
5263 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5269static pm_interpolated_symbol_node_t *
5270pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5271 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5272 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5274 pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
5277 PM_NODE_FLAG_STATIC_LITERAL,
5278 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5279 NTOK2LOC(parser, opening),
5280 ((pm_node_list_t) { 0 }),
5281 NTOK2LOC(parser, closing)
5284 if (parts != NULL) {
5286 PM_NODE_LIST_FOREACH(parts, index, part) {
5287 pm_interpolated_symbol_node_append(parser->arena, node, part);
5297static pm_interpolated_x_string_node_t *
5298pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5299 return pm_interpolated_x_string_node_new(
5303 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5304 TOK2LOC(parser, opening),
5305 ((pm_node_list_t) { 0 }),
5306 TOK2LOC(parser, closing)
5310static PRISM_INLINE void
5311pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5312 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5313 PM_NODE_LENGTH_SET_NODE(node, part);
5316static PRISM_INLINE void
5317pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5318 node->closing_loc = TOK2LOC(parser, closing);
5319 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5325static pm_it_local_variable_read_node_t *
5326pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5327 return pm_it_local_variable_read_node_new(
5331 PM_LOCATION_INIT_TOKEN(parser, name)
5338static pm_it_parameters_node_t *
5339pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5340 return pm_it_parameters_node_new(
5344 PM_LOCATION_INIT_TOKENS(parser, opening, closing)
5351static pm_keyword_hash_node_t *
5352pm_keyword_hash_node_create(pm_parser_t *parser) {
5353 return pm_keyword_hash_node_new(
5356 PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5357 PM_LOCATION_INIT_UNSET,
5358 ((pm_node_list_t) { 0 })
5366pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *hash, pm_node_t *element) {
5367 // If the element being added is not an AssocNode or does not have a symbol
5368 // key, then we want to turn the SYMBOL_KEYS flag off.
5369 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5370 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5373 pm_node_list_append(arena, &hash->elements, element);
5374 if (PM_NODE_LENGTH(hash) == 0) {
5375 PM_NODE_START_SET_NODE(hash, element);
5377 PM_NODE_LENGTH_SET_NODE(hash, element);
5383static pm_required_keyword_parameter_node_t *
5384pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5385 return pm_required_keyword_parameter_node_new(
5389 PM_LOCATION_INIT_TOKEN(parser, name),
5390 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5391 TOK2LOC(parser, name)
5398static pm_optional_keyword_parameter_node_t *
5399pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5400 return pm_optional_keyword_parameter_node_new(
5404 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5405 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5406 TOK2LOC(parser, name),
5414static pm_keyword_rest_parameter_node_t *
5415pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5416 return pm_keyword_rest_parameter_node_new(
5420 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
5421 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
5422 NTOK2LOC(parser, name),
5423 TOK2LOC(parser, operator)
5430static pm_lambda_node_t *
5431pm_lambda_node_create(
5432 pm_parser_t *parser,
5433 pm_constant_id_list_t *locals,
5434 const pm_token_t *operator,
5435 const pm_token_t *opening,
5436 const pm_token_t *closing,
5437 pm_node_t *parameters,
5440 return pm_lambda_node_new(
5444 PM_LOCATION_INIT_TOKENS(parser, operator, closing),
5446 TOK2LOC(parser, operator),
5447 TOK2LOC(parser, opening),
5448 TOK2LOC(parser, closing),
5457static pm_local_variable_and_write_node_t *
5458pm_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) {
5459 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));
5460 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5462 return pm_local_variable_and_write_node_new(
5466 PM_LOCATION_INIT_NODES(target, value),
5468 TOK2LOC(parser, operator),
5478static pm_local_variable_operator_write_node_t *
5479pm_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) {
5480 return pm_local_variable_operator_write_node_new(
5484 PM_LOCATION_INIT_NODES(target, value),
5486 TOK2LOC(parser, operator),
5489 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
5497static pm_local_variable_or_write_node_t *
5498pm_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) {
5499 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));
5500 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5502 return pm_local_variable_or_write_node_new(
5506 PM_LOCATION_INIT_NODES(target, value),
5508 TOK2LOC(parser, operator),
5518static pm_local_variable_read_node_t *
5519pm_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) {
5520 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5522 return pm_local_variable_read_node_new(
5526 PM_LOCATION_INIT_TOKEN(parser, name),
5535static pm_local_variable_read_node_t *
5536pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5537 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5538 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5545static pm_local_variable_read_node_t *
5546pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5547 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5548 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5554static pm_local_variable_write_node_t *
5555pm_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) {
5556 return pm_local_variable_write_node_new(
5559 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5560 ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
5565 TOK2LOC(parser, operator)
5572static PRISM_INLINE bool
5573pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5574 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5581static PRISM_INLINE bool
5582pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
5585 (parser->start[start] == '_') &&
5586 (parser->start[start + 1] != '0') &&
5587 pm_char_is_decimal_digit(parser->start[start + 1])
5595static PRISM_INLINE void
5596pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
5597 if (pm_token_is_numbered_parameter(parser, start, length)) {
5598 PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
5606static pm_local_variable_target_node_t *
5607pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5608 pm_refute_numbered_parameter(parser, location->start, location->length);
5610 return pm_local_variable_target_node_new(
5614 ((pm_location_t) { .start = location->start, .length = location->length }),
5623static pm_match_predicate_node_t *
5624pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5625 pm_assert_value_expression(parser, value);
5627 return pm_match_predicate_node_new(
5631 PM_LOCATION_INIT_NODES(value, pattern),
5634 TOK2LOC(parser, operator)
5641static pm_match_required_node_t *
5642pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5643 pm_assert_value_expression(parser, value);
5645 return pm_match_required_node_new(
5649 PM_LOCATION_INIT_NODES(value, pattern),
5652 TOK2LOC(parser, operator)
5659static pm_match_write_node_t *
5660pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5661 return pm_match_write_node_new(
5665 PM_LOCATION_INIT_NODE(call),
5667 ((pm_node_list_t) { 0 })
5674static pm_module_node_t *
5675pm_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) {
5676 pm_constant_id_list_t module_locals = { .ids = NULL, .size = 0, .capacity = 0 };
5677 if (locals != NULL) module_locals = *locals;
5679 return pm_module_node_new(
5683 PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
5685 TOK2LOC(parser, module_keyword),
5688 TOK2LOC(parser, end_keyword),
5689 pm_parser_constant_id_token(parser, name)
5696static pm_multi_target_node_t *
5697pm_multi_target_node_create(pm_parser_t *parser) {
5698 return pm_multi_target_node_new(
5702 PM_LOCATION_INIT_UNSET,
5703 ((pm_node_list_t) { 0 }),
5705 ((pm_node_list_t) { 0 }),
5706 ((pm_location_t) { 0 }),
5707 ((pm_location_t) { 0 })
5715pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5716 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5717 if (node->rest == NULL) {
5718 node->rest = target;
5720 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5721 pm_node_list_append(parser->arena, &node->rights, target);
5723 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5724 if (node->rest == NULL) {
5725 node->rest = target;
5727 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5728 pm_node_list_append(parser->arena, &node->rights, target);
5730 } else if (node->rest == NULL) {
5731 pm_node_list_append(parser->arena, &node->lefts, target);
5733 pm_node_list_append(parser->arena, &node->rights, target);
5736 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
5737 PM_NODE_START_SET_NODE(node, target);
5740 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
5741 PM_NODE_LENGTH_SET_NODE(node, target);
5749pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
5750 PM_NODE_START_SET_TOKEN(parser, node, lparen);
5751 PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
5752 node->lparen_loc = TOK2LOC(parser, lparen);
5759pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
5760 PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
5761 node->rparen_loc = TOK2LOC(parser, rparen);
5767static pm_multi_write_node_t *
5768pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5769 /* The target is no longer necessary because we have reused its children. It
5770 * is arena-allocated so no explicit free is needed. */
5771 return pm_multi_write_node_new(
5774 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5775 PM_LOCATION_INIT_NODES(target, value),
5781 TOK2LOC(parser, operator),
5789static pm_next_node_t *
5790pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5791 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5793 return pm_next_node_new(
5797 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
5799 TOK2LOC(parser, keyword)
5806static pm_nil_node_t *
5807pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5808 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5810 return pm_nil_node_new(
5813 PM_NODE_FLAG_STATIC_LITERAL,
5814 PM_LOCATION_INIT_TOKEN(parser, token)
5821static pm_no_block_parameter_node_t *
5822pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5823 assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5824 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5826 return pm_no_block_parameter_node_new(
5830 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5831 TOK2LOC(parser, operator),
5832 TOK2LOC(parser, keyword)
5839static pm_no_keywords_parameter_node_t *
5840pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5841 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5842 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5844 return pm_no_keywords_parameter_node_new(
5848 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5849 TOK2LOC(parser, operator),
5850 TOK2LOC(parser, keyword)
5857static pm_numbered_parameters_node_t *
5858pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
5859 return pm_numbered_parameters_node_new(
5863 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5872#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5881pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5882 const uint8_t *start = token->start + 1;
5883 const uint8_t *end = token->end;
5885 ptrdiff_t diff = end - start;
5887#if PTRDIFF_MAX > SIZE_MAX
5888 assert(diff < (ptrdiff_t) SIZE_MAX);
5890 size_t length = (size_t) diff;
5892 char *digits = xcalloc(length + 1, sizeof(char));
5893 memcpy(digits, start, length);
5894 digits[length] = '\0';
5898 unsigned long value = strtoul(digits, &endptr, 10);
5900 if ((digits == endptr) || (*endptr != '\0')) {
5901 pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
5905 xfree_sized(digits, sizeof(char) * (length + 1));
5907 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5908 PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5912 return (uint32_t) value;
5920static pm_numbered_reference_read_node_t *
5921pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5922 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5924 return pm_numbered_reference_read_node_new(
5928 PM_LOCATION_INIT_TOKEN(parser, name),
5929 pm_numbered_reference_read_node_number(parser, name)
5936static pm_optional_parameter_node_t *
5937pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5938 return pm_optional_parameter_node_new(
5942 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5943 pm_parser_constant_id_token(parser, name),
5944 TOK2LOC(parser, name),
5945 TOK2LOC(parser, operator),
5953static pm_or_node_t *
5954pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5955 pm_assert_value_expression(parser, left);
5957 return pm_or_node_new(
5961 PM_LOCATION_INIT_NODES(left, right),
5964 TOK2LOC(parser, operator)
5971static pm_parameters_node_t *
5972pm_parameters_node_create(pm_parser_t *parser) {
5973 return pm_parameters_node_new(
5977 PM_LOCATION_INIT_UNSET,
5978 ((pm_node_list_t) { 0 }),
5979 ((pm_node_list_t) { 0 }),
5981 ((pm_node_list_t) { 0 }),
5982 ((pm_node_list_t) { 0 }),
5992pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5993 if ((params->base.location.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
5994 PM_NODE_START_SET_NODE(params, param);
5997 if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
5998 PM_NODE_LENGTH_SET_NODE(params, param);
6006pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6007 pm_parameters_node_location_set(params, param);
6008 pm_node_list_append(arena, ¶ms->requireds, param);
6015pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6016 pm_parameters_node_location_set(params, UP(param));
6017 pm_node_list_append(arena, ¶ms->optionals, UP(param));
6024pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6025 pm_parameters_node_location_set(params, param);
6026 pm_node_list_append(arena, ¶ms->posts, param);
6033pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6034 pm_parameters_node_location_set(params, param);
6035 params->rest = param;
6042pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6043 pm_parameters_node_location_set(params, param);
6044 pm_node_list_append(arena, ¶ms->keywords, param);
6051pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6052 assert(params->keyword_rest == NULL);
6053 pm_parameters_node_location_set(params, param);
6054 params->keyword_rest = param;
6061pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
6062 assert(params->block == NULL);
6063 pm_parameters_node_location_set(params, param);
6064 params->block = param;
6070static pm_program_node_t *
6071pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6072 return pm_program_node_new(
6076 PM_LOCATION_INIT_NODE(statements),
6085static pm_parentheses_node_t *
6086pm_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) {
6087 return pm_parentheses_node_new(
6091 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6093 TOK2LOC(parser, opening),
6094 TOK2LOC(parser, closing)
6101static pm_pinned_expression_node_t *
6102pm_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) {
6103 return pm_pinned_expression_node_new(
6107 PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
6109 TOK2LOC(parser, operator),
6110 TOK2LOC(parser, lparen),
6111 TOK2LOC(parser, rparen)
6118static pm_pinned_variable_node_t *
6119pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6120 return pm_pinned_variable_node_new(
6124 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
6126 TOK2LOC(parser, operator)
6133static pm_post_execution_node_t *
6134pm_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) {
6135 return pm_post_execution_node_new(
6139 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6141 TOK2LOC(parser, keyword),
6142 TOK2LOC(parser, opening),
6143 TOK2LOC(parser, closing)
6150static pm_pre_execution_node_t *
6151pm_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) {
6152 return pm_pre_execution_node_new(
6156 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6158 TOK2LOC(parser, keyword),
6159 TOK2LOC(parser, opening),
6160 TOK2LOC(parser, closing)
6167static pm_range_node_t *
6168pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6169 pm_assert_value_expression(parser, left);
6170 pm_assert_value_expression(parser, right);
6171 pm_node_flags_t flags = 0;
6173 // Indicate that this node is an exclusive range if the operator is `...`.
6174 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6175 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6178 // Indicate that this node is a static literal (i.e., can be compiled with
6179 // a putobject in CRuby) if the left and right are implicit nil, explicit
6180 // nil, or integers.
6182 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6183 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6185 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6188 uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
6189 uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
6191 return pm_range_node_new(
6195 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6198 TOK2LOC(parser, operator)
6205static pm_redo_node_t *
6206pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6207 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6209 return pm_redo_node_new(
6213 PM_LOCATION_INIT_TOKEN(parser, token)
6221static pm_regular_expression_node_t *
6222pm_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) {
6223 return pm_regular_expression_node_new(
6226 pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6227 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6228 TOK2LOC(parser, opening),
6229 TOK2LOC(parser, content),
6230 TOK2LOC(parser, closing),
6238static PRISM_INLINE pm_regular_expression_node_t *
6239pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6240 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6246static pm_required_parameter_node_t *
6247pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6248 return pm_required_parameter_node_new(
6252 PM_LOCATION_INIT_TOKEN(parser, token),
6253 pm_parser_constant_id_token(parser, token)
6260static pm_rescue_modifier_node_t *
6261pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6262 return pm_rescue_modifier_node_new(
6266 PM_LOCATION_INIT_NODES(expression, rescue_expression),
6268 TOK2LOC(parser, keyword),
6276static pm_rescue_node_t *
6277pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6278 return pm_rescue_node_new(
6282 PM_LOCATION_INIT_TOKEN(parser, keyword),
6283 TOK2LOC(parser, keyword),
6284 ((pm_node_list_t) { 0 }),
6285 ((pm_location_t) { 0 }),
6287 ((pm_location_t) { 0 }),
6293static PRISM_INLINE void
6294pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
6295 node->operator_loc = TOK2LOC(parser, operator);
6302pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6303 node->reference = reference;
6304 PM_NODE_LENGTH_SET_NODE(node, reference);
6311pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6312 node->statements = statements;
6313 if (pm_statements_node_body_length(statements) > 0) {
6314 PM_NODE_LENGTH_SET_NODE(node, statements);
6322pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6323 node->subsequent = subsequent;
6324 PM_NODE_LENGTH_SET_NODE(node, subsequent);
6331pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
6332 pm_node_list_append(arena, &node->exceptions, exception);
6333 PM_NODE_LENGTH_SET_NODE(node, exception);
6339static pm_rest_parameter_node_t *
6340pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6341 return pm_rest_parameter_node_new(
6345 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
6346 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
6347 NTOK2LOC(parser, name),
6348 TOK2LOC(parser, operator)
6355static pm_retry_node_t *
6356pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6357 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6359 return pm_retry_node_new(
6363 PM_LOCATION_INIT_TOKEN(parser, token)
6370static pm_return_node_t *
6371pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6372 return pm_return_node_new(
6376 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
6377 TOK2LOC(parser, keyword),
6385static pm_self_node_t *
6386pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6387 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6389 return pm_self_node_new(
6393 PM_LOCATION_INIT_TOKEN(parser, token)
6400static pm_shareable_constant_node_t *
6401pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6402 return pm_shareable_constant_node_new(
6405 (pm_node_flags_t) value,
6406 PM_LOCATION_INIT_NODE(write),
6414static pm_singleton_class_node_t *
6415pm_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) {
6416 return pm_singleton_class_node_new(
6420 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
6422 TOK2LOC(parser, class_keyword),
6423 TOK2LOC(parser, operator),
6426 TOK2LOC(parser, end_keyword)
6433static pm_source_encoding_node_t *
6434pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6435 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6437 return pm_source_encoding_node_new(
6440 PM_NODE_FLAG_STATIC_LITERAL,
6441 PM_LOCATION_INIT_TOKEN(parser, token)
6448static pm_source_file_node_t*
6449pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6450 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6452 pm_node_flags_t flags = 0;
6454 switch (parser->frozen_string_literal) {
6455 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6456 flags |= PM_STRING_FLAGS_MUTABLE;
6458 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6459 flags |= PM_STRING_FLAGS_FROZEN;
6460 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
6461 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6466 return pm_source_file_node_new(
6470 PM_LOCATION_INIT_TOKEN(parser, file_keyword),
6478static pm_source_line_node_t *
6479pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6480 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6482 return pm_source_line_node_new(
6485 PM_NODE_FLAG_STATIC_LITERAL,
6486 PM_LOCATION_INIT_TOKEN(parser, token)
6493static pm_splat_node_t *
6494pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6495 return pm_splat_node_new(
6499 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
6500 TOK2LOC(parser, operator),
6508static pm_statements_node_t *
6509pm_statements_node_create(pm_parser_t *parser) {
6510 return pm_statements_node_new(
6514 PM_LOCATION_INIT_UNSET,
6515 ((pm_node_list_t) { 0 })
6523pm_statements_node_body_length(pm_statements_node_t *node) {
6524 return node && node->body.size;
6531static PRISM_INLINE void
6532pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6533 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6534 PM_NODE_START_SET_NODE(node, statement);
6537 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6538 PM_NODE_LENGTH_SET_NODE(node, statement);
6546pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6547 pm_statements_node_body_update(node, statement);
6549 if (node->body.size > 0) {
6550 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6552 switch (PM_NODE_TYPE(previous)) {
6557 case PM_RETURN_NODE:
6558 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6565 pm_node_list_append(parser->arena, &node->body, statement);
6566 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6573pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
6574 pm_statements_node_body_update(node, statement);
6575 pm_node_list_prepend(arena, &node->body, statement);
6576 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6582static PRISM_INLINE pm_string_node_t *
6583pm_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) {
6584 pm_node_flags_t flags = 0;
6586 switch (parser->frozen_string_literal) {
6587 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6588 flags = PM_STRING_FLAGS_MUTABLE;
6590 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6591 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6595 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6596 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6598 return pm_string_node_new(
6602 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6603 NTOK2LOC(parser, opening),
6604 TOK2LOC(parser, content),
6605 NTOK2LOC(parser, closing),
6613static pm_string_node_t *
6614pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6615 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6622static pm_string_node_t *
6623pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6624 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6625 parser->current_string = PM_STRING_EMPTY;
6632static pm_super_node_t *
6633pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6634 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6636 const pm_location_t *end = pm_arguments_end(arguments);
6637 assert(end != NULL && "unreachable");
6639 return pm_super_node_new(
6643 ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
6644 TOK2LOC(parser, keyword),
6645 arguments->opening_loc,
6646 arguments->arguments,
6647 arguments->closing_loc,
6657pm_ascii_only_p(const pm_string_t *contents) {
6658 const size_t length = pm_string_length(contents);
6659 const uint8_t *source = pm_string_source(contents);
6661 for (size_t index = 0; index < length; index++) {
6662 if (source[index] & 0x80) return false;
6672parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6673 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6674 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6677 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6690parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6691 const pm_encoding_t *encoding = parser->encoding;
6693 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6694 size_t width = encoding->char_width(cursor, end - cursor);
6697 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6714static PRISM_INLINE pm_node_flags_t
6715parse_symbol_encoding(pm_parser_t *parser, const pm_encoding_t *explicit_encoding, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6716 if (explicit_encoding != NULL) {
6717 // A Symbol may optionally have its encoding explicitly set. This will
6718 // happen if an escape sequence results in a non-ASCII code point.
6719 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6720 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6721 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6722 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6723 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6724 } else if (validate) {
6725 parse_symbol_encoding_validate_other(parser, location, contents);
6727 } else if (pm_ascii_only_p(contents)) {
6728 // Ruby stipulates that all source files must use an ASCII-compatible
6729 // encoding. Thus, all symbols appearing in source are eligible for
6730 // "downgrading" to US-ASCII.
6731 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6732 } else if (validate) {
6733 parse_symbol_encoding_validate_other(parser, location, contents);
6743static pm_symbol_node_t *
6744pm_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) {
6745 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6746 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6748 return pm_symbol_node_new(
6751 PM_NODE_FLAG_STATIC_LITERAL | flags,
6752 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6753 NTOK2LOC(parser, opening),
6754 NTOK2LOC(parser, value),
6755 NTOK2LOC(parser, closing),
6763static PRISM_INLINE pm_symbol_node_t *
6764pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6765 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6771static pm_symbol_node_t *
6772pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6773 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));
6774 parser->current_string = PM_STRING_EMPTY;
6781static pm_symbol_node_t *
6782pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6783 assert(token->type == PM_TOKEN_LABEL);
6785 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6786 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6787 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6789 assert((label.end - label.start) >= 0);
6790 pm_string_shared_init(&node->unescaped, label.start, label.end);
6791 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, parser->explicit_encoding, &label, &node->unescaped, false));
6799static pm_symbol_node_t *
6800pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6801 pm_symbol_node_t *node = pm_symbol_node_new(
6804 PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
6805 PM_LOCATION_INIT_UNSET,
6806 ((pm_location_t) { 0 }),
6807 ((pm_location_t) { 0 }),
6808 ((pm_location_t) { 0 }),
6809 ((pm_string_t) { 0 })
6812 pm_string_constant_init(&node->unescaped, content, strlen(content));
6820pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6821 const pm_location_t *location = NULL;
6823 switch (PM_NODE_TYPE(node)) {
6824 case PM_SYMBOL_NODE: {
6825 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6826 if (cast->closing_loc.length > 0) {
6827 location = &cast->closing_loc;
6831 case PM_INTERPOLATED_SYMBOL_NODE: {
6832 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6833 if (cast->closing_loc.length > 0) {
6834 location = &cast->closing_loc;
6842 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6848static pm_symbol_node_t *
6849pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6850 pm_symbol_node_t *new_node = pm_symbol_node_new(
6853 PM_NODE_FLAG_STATIC_LITERAL,
6854 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6855 TOK2LOC(parser, opening),
6857 TOK2LOC(parser, closing),
6861 pm_token_t content = {
6862 .type = PM_TOKEN_IDENTIFIER,
6863 .start = parser->start + node->content_loc.start,
6864 .end = parser->start + node->content_loc.start + node->content_loc.length
6867 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, parser->explicit_encoding, &content, &node->unescaped, true));
6869 /* The old node is arena-allocated so no explicit free is needed. */
6876static pm_string_node_t *
6877pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6878 pm_node_flags_t flags = 0;
6880 switch (parser->frozen_string_literal) {
6881 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6882 flags = PM_STRING_FLAGS_MUTABLE;
6884 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6885 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6889 pm_string_node_t *new_node = pm_string_node_new(
6893 PM_LOCATION_INIT_NODE(node),
6900 /* The old node is arena-allocated so no explicit free is needed. */
6907static pm_true_node_t *
6908pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6909 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6911 return pm_true_node_new(
6914 PM_NODE_FLAG_STATIC_LITERAL,
6915 PM_LOCATION_INIT_TOKEN(parser, token)
6922static pm_true_node_t *
6923pm_true_node_synthesized_create(pm_parser_t *parser) {
6924 return pm_true_node_new(
6927 PM_NODE_FLAG_STATIC_LITERAL,
6928 PM_LOCATION_INIT_UNSET
6935static pm_undef_node_t *
6936pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6937 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6939 return pm_undef_node_new(
6943 PM_LOCATION_INIT_TOKEN(parser, token),
6944 ((pm_node_list_t) { 0 }),
6945 TOK2LOC(parser, token)
6953pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6954 PM_NODE_LENGTH_SET_NODE(node, name);
6955 pm_node_list_append(arena, &node->names, name);
6961static pm_unless_node_t *
6962pm_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) {
6963 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6964 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6966 return pm_unless_node_new(
6969 PM_NODE_FLAG_NEWLINE,
6970 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
6971 TOK2LOC(parser, keyword),
6973 NTOK2LOC(parser, then_keyword),
6976 ((pm_location_t) { 0 })
6983static pm_unless_node_t *
6984pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6985 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6987 pm_statements_node_t *statements = pm_statements_node_create(parser);
6988 pm_statements_node_body_append(parser, statements, statement, true);
6990 return pm_unless_node_new(
6993 PM_NODE_FLAG_NEWLINE,
6994 PM_LOCATION_INIT_NODES(statement, predicate),
6995 TOK2LOC(parser, unless_keyword),
6997 ((pm_location_t) { 0 }),
7000 ((pm_location_t) { 0 })
7004static PRISM_INLINE void
7005pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
7006 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
7007 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
7016pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7017 assert(parser->current_block_exits != NULL);
7019 // All of the block exits that we want to remove should be within the
7020 // statements, and since we are modifying the statements, we shouldn't have
7021 // to check the end location.
7022 uint32_t start = statements->base.location.start;
7024 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7025 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7026 if (block_exit->location.start < start) break;
7028 // Implicitly remove from the list by lowering the size.
7029 parser->current_block_exits->size--;
7036static pm_until_node_t *
7037pm_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) {
7038 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7040 return pm_until_node_new(
7044 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7045 TOK2LOC(parser, keyword),
7046 NTOK2LOC(parser, do_keyword),
7047 TOK2LOC(parser, closing),
7056static pm_until_node_t *
7057pm_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) {
7058 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7059 pm_loop_modifier_block_exits(parser, statements);
7061 return pm_until_node_new(
7065 PM_LOCATION_INIT_NODES(statements, predicate),
7066 TOK2LOC(parser, keyword),
7067 ((pm_location_t) { 0 }),
7068 ((pm_location_t) { 0 }),
7077static pm_when_node_t *
7078pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7079 return pm_when_node_new(
7083 PM_LOCATION_INIT_TOKEN(parser, keyword),
7084 TOK2LOC(parser, keyword),
7085 ((pm_node_list_t) { 0 }),
7086 ((pm_location_t) { 0 }),
7095pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
7096 PM_NODE_LENGTH_SET_NODE(node, condition);
7097 pm_node_list_append(arena, &node->conditions, condition);
7103static PRISM_INLINE void
7104pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
7105 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
7106 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
7113pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7114 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
7115 PM_NODE_LENGTH_SET_NODE(node, statements);
7118 node->statements = statements;
7124static pm_while_node_t *
7125pm_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) {
7126 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7128 return pm_while_node_new(
7132 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7133 TOK2LOC(parser, keyword),
7134 NTOK2LOC(parser, do_keyword),
7135 TOK2LOC(parser, closing),
7144static pm_while_node_t *
7145pm_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) {
7146 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7147 pm_loop_modifier_block_exits(parser, statements);
7149 return pm_while_node_new(
7153 PM_LOCATION_INIT_NODES(statements, predicate),
7154 TOK2LOC(parser, keyword),
7155 ((pm_location_t) { 0 }),
7156 ((pm_location_t) { 0 }),
7165static pm_while_node_t *
7166pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7167 return pm_while_node_new(
7171 PM_LOCATION_INIT_UNSET,
7172 ((pm_location_t) { 0 }),
7173 ((pm_location_t) { 0 }),
7174 ((pm_location_t) { 0 }),
7184static pm_x_string_node_t *
7185pm_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) {
7186 return pm_x_string_node_new(
7189 PM_STRING_FLAGS_FROZEN,
7190 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
7191 TOK2LOC(parser, opening),
7192 TOK2LOC(parser, content),
7193 TOK2LOC(parser, closing),
7201static PRISM_INLINE pm_x_string_node_t *
7202pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7203 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7209static pm_yield_node_t *
7210pm_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) {
7211 uint32_t start = PM_TOKEN_START(parser, keyword);
7214 if (rparen_loc->length > 0) {
7215 end = PM_LOCATION_END(rparen_loc);
7216 } else if (arguments != NULL) {
7217 end = PM_NODE_END(arguments);
7218 } else if (lparen_loc->length > 0) {
7219 end = PM_LOCATION_END(lparen_loc);
7221 end = PM_TOKEN_END(parser, keyword);
7224 return pm_yield_node_new(
7228 ((pm_location_t) { .start = start, .length = U32(end - start) }),
7229 TOK2LOC(parser, keyword),
7241pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7242 pm_scope_t *scope = parser->current_scope;
7245 while (scope != NULL) {
7246 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7247 if (scope->closed) break;
7249 scope = scope->previous;
7261static PRISM_INLINE int
7262pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7263 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7269static PRISM_INLINE void
7270pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7271 pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
7277static pm_constant_id_t
7278pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7279 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
7280 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7287static PRISM_INLINE pm_constant_id_t
7288pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
7289 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
7295static PRISM_INLINE pm_constant_id_t
7296pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7297 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
7303static pm_constant_id_t
7304pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7305 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7306 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7313static pm_constant_id_t
7314pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7315 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7316 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7328pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7329 // We want to check whether the parameter name is a numbered parameter or
7331 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7333 // Otherwise we'll fetch the constant id for the parameter name and check
7334 // whether it's already in the current scope.
7335 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7337 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7338 // Add an error if the parameter doesn't start with _ and has been seen before
7339 if ((name->start < name->end) && (*name->start != '_')) {
7340 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7351pm_parser_scope_pop(pm_parser_t *parser) {
7352 pm_scope_t *scope = parser->current_scope;
7353 parser->current_scope = scope->previous;
7354 pm_locals_free(&scope->locals);
7355 xfree_sized(scope, sizeof(pm_scope_t));
7358/******************************************************************************/
7360/******************************************************************************/
7365static PRISM_INLINE void
7366pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7367 *stack = (*stack << 1) | (value & 1);
7373static PRISM_INLINE void
7374pm_state_stack_pop(pm_state_stack_t *stack) {
7381static PRISM_INLINE bool
7382pm_state_stack_p(const pm_state_stack_t *stack) {
7386static PRISM_INLINE void
7387pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7388 // Use the negation of the value to prevent stack overflow.
7389 pm_state_stack_push(&parser->accepts_block_stack, !value);
7392static PRISM_INLINE void
7393pm_accepts_block_stack_pop(pm_parser_t *parser) {
7394 pm_state_stack_pop(&parser->accepts_block_stack);
7397static PRISM_INLINE bool
7398pm_accepts_block_stack_p(pm_parser_t *parser) {
7399 return !pm_state_stack_p(&parser->accepts_block_stack);
7402static PRISM_INLINE void
7403pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7404 pm_state_stack_push(&parser->do_loop_stack, value);
7407static PRISM_INLINE void
7408pm_do_loop_stack_pop(pm_parser_t *parser) {
7409 pm_state_stack_pop(&parser->do_loop_stack);
7412static PRISM_INLINE bool
7413pm_do_loop_stack_p(pm_parser_t *parser) {
7414 return pm_state_stack_p(&parser->do_loop_stack);
7441static PRISM_INLINE void
7442pm_enclosure_frame_push(pm_parser_t *parser) {
7443 pm_do_loop_stack_push(parser, false);
7444 pm_accepts_block_stack_push(parser, true);
7447static PRISM_INLINE void
7448pm_enclosure_frame_pop(pm_parser_t *parser) {
7449 pm_do_loop_stack_pop(parser);
7450 pm_accepts_block_stack_pop(parser);
7453/******************************************************************************/
7454/* Lexer check helpers */
7455/******************************************************************************/
7461static PRISM_INLINE uint8_t
7462peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7463 if (cursor < parser->end) {
7475static PRISM_INLINE uint8_t
7476peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7477 return peek_at(parser, parser->current.end + offset);
7484static PRISM_INLINE uint8_t
7485peek(const pm_parser_t *parser) {
7486 return peek_at(parser, parser->current.end);
7493static PRISM_INLINE bool
7494match(pm_parser_t *parser, uint8_t value) {
7495 if (peek(parser) == value) {
7496 parser->current.end++;
7506static PRISM_INLINE size_t
7507match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7508 if (peek_at(parser, cursor) == '\n') {
7511 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7522static PRISM_INLINE size_t
7523match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7524 return match_eol_at(parser, parser->current.end + offset);
7532static PRISM_INLINE size_t
7533match_eol(pm_parser_t *parser) {
7534 return match_eol_at(parser, parser->current.end);
7540static PRISM_INLINE const uint8_t *
7541next_newline(const uint8_t *cursor, ptrdiff_t length) {
7542 assert(length >= 0);
7544 // Note that it's okay for us to use memchr here to look for \n because none
7545 // of the encodings that we support have \n as a component of a multi-byte
7547 return memchr(cursor, '\n', (size_t) length);
7553static PRISM_INLINE bool
7554ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7555 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));
7563parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7564 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7566 if (encoding != NULL) {
7567 if (parser->encoding != encoding) {
7568 parser->encoding = encoding;
7569 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7572 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7584parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7585 const uint8_t *cursor = parser->current.start + 1;
7586 const uint8_t *end = parser->current.end;
7588 bool separator = false;
7590 if (end - cursor <= 6) return;
7591 switch (cursor[6]) {
7592 case 'C': case 'c': cursor += 6; continue;
7593 case 'O': case 'o': cursor += 5; continue;
7594 case 'D': case 'd': cursor += 4; continue;
7595 case 'I': case 'i': cursor += 3; continue;
7596 case 'N': case 'n': cursor += 2; continue;
7597 case 'G': case 'g': cursor += 1; continue;
7604 if (pm_char_is_whitespace(*cursor)) break;
7607 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7613 if (++cursor >= end) return;
7614 } while (pm_char_is_whitespace(*cursor));
7616 if (separator) break;
7617 if (*cursor != '=' && *cursor != ':') return;
7623 const uint8_t *value_start = cursor;
7624 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7626 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7627 // If we were unable to parse the encoding value, then we've got an
7628 // issue because we didn't understand the encoding that the user was
7629 // trying to use. In this case we'll keep using the default encoding but
7630 // add an error to the parser to indicate an unsuccessful parse.
7631 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7636 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7637 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7638 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7639} pm_magic_comment_boolean_value_t;
7645static pm_magic_comment_boolean_value_t
7646parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7647 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7648 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7649 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7650 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7652 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7656static PRISM_INLINE bool
7657pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7658 return b == '\'' || b == '"' || b == ':' || b == ';';
7667parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7671 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1,
'*', (
size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7672 if (cursor[-1] ==
'-' && cursor + 1 < end && cursor[1] ==
'-') {
7690parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7693 const uint8_t *start = parser->current.start + 1;
7694 const uint8_t *end = parser->current.end;
7695 if (end - start <= 7)
return false;
7697 const uint8_t *cursor;
7698 bool indicator =
false;
7700 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7703 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7715 if (pm_memchr(start,
':', (
size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
7721 start += pm_strspn_whitespace(start, end - start);
7725 while (cursor < end) {
7727 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7730 const uint8_t *key_start = cursor;
7731 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7733 const uint8_t *key_end = cursor;
7734 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7735 if (cursor == end)
break;
7737 if (*cursor ==
':') {
7740 if (!indicator)
return false;
7744 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7745 if (cursor == end)
break;
7747 const uint8_t *value_start;
7748 const uint8_t *value_end;
7750 if (*cursor ==
'"') {
7751 value_start = ++cursor;
7752 for (; cursor < end && *cursor !=
'"'; cursor++) {
7753 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7756 if (cursor < end && *cursor ==
'"') cursor++;
7758 value_start = cursor;
7759 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7764 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7766 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7767 if (cursor != end)
return false;
7773 const size_t key_length = (size_t) (key_end - key_start);
7774 const uint8_t *dash = pm_memchr(key_start,
'-', key_length, parser->encoding_changed, parser->encoding);
7777 pm_string_shared_init(&key, key_start, key_end);
7779 uint8_t *buffer =
xmalloc(key_length);
7780 if (buffer == NULL)
break;
7782 memcpy(buffer, key_start, key_length);
7783 buffer[dash - key_start] =
'_';
7785 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7786 buffer[dash - key_start] =
'_';
7789 pm_string_owned_init(&key, buffer, key_length);
7794 const uint8_t *key_source = pm_string_source(&key);
7795 uint32_t value_length = (uint32_t) (value_end - value_start);
7799 if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7801 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7802 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7804 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7808 if (key_length == 11) {
7809 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7810 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7811 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7812 PM_PARSER_WARN_TOKEN_FORMAT(
7815 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7817 (
const char *) key_source,
7819 (
const char *) value_start
7822 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7823 parser->warn_mismatched_indentation =
false;
7825 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7826 parser->warn_mismatched_indentation =
true;
7830 }
else if (key_length == 21) {
7831 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7834 if (semantic_token_seen) {
7835 pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7837 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7838 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7839 PM_PARSER_WARN_TOKEN_FORMAT(
7842 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7844 (
const char *) key_source,
7846 (
const char *) value_start
7849 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7852 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7858 }
else if (key_length == 24) {
7859 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7860 const uint8_t *cursor = parser->current.start;
7861 while ((cursor > parser->start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7863 if (!((cursor == parser->start) || (cursor[-1] ==
'\n'))) {
7864 pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7865 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7866 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7867 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7868 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7869 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7870 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7871 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7872 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7874 PM_PARSER_WARN_TOKEN_FORMAT(
7877 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7879 (
const char *) key_source,
7881 (
const char *) value_start
7889 pm_string_cleanup(&key);
7906static const uint32_t context_terminators[] = {
7907 [PM_CONTEXT_NONE] = 0,
7908 [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7909 [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7910 [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7911 [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7912 [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7913 [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7914 [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7915 [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7916 [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
7917 [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7918 [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7919 [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7920 [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7921 [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7922 [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7923 [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7924 [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7925 [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7926 [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7927 [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7928 [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
7929 [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
7930 [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7931 [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
7932 [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7933 [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
7934 [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
7935 [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
7936 [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7937 [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7938 [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7939 [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7940 [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7941 [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7942 [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
7943 [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
7944 [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7945 [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7946 [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7947 [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7948 [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
7949 [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7950 [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7951 [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7952 [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7953 [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
7954 [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7955 [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7956 [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7957 [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7958 [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
7959 [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7960 [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
7961 [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
7965context_terminator(pm_context_t context,
pm_token_t *token) {
7966 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7977 while (context_node != NULL) {
7978 if (context_terminator(context_node->context, token))
return context_node->context;
7979 context_node = context_node->prev;
7982 return PM_CONTEXT_NONE;
7985PM_STATIC_ASSERT(__LINE__, PM_CONTEXT_MAXIMUM <= 64,
"Expected every context to fit in the context mask.");
7988context_push(
pm_parser_t *parser, pm_context_t context) {
7990 if (context_node == NULL)
return false;
7996 .mask = (previous == NULL ? 0 : previous->mask) | ((uint64_t) 1 << context)
7999 parser->current_context = context_node;
8007 parser->current_context = prev;
8011context_p(
const pm_parser_t *parser, pm_context_t context) {
8012 return parser->current_context != NULL && (parser->current_context->mask & ((uint64_t) 1 << context)) != 0;
8019 while (context_node != NULL) {
8020 switch (context_node->context) {
8021 case PM_CONTEXT_DEF:
8022 case PM_CONTEXT_DEF_PARAMS:
8023 case PM_CONTEXT_DEF_ENSURE:
8024 case PM_CONTEXT_DEF_RESCUE:
8025 case PM_CONTEXT_DEF_ELSE:
8027 case PM_CONTEXT_CLASS:
8028 case PM_CONTEXT_CLASS_ENSURE:
8029 case PM_CONTEXT_CLASS_RESCUE:
8030 case PM_CONTEXT_CLASS_ELSE:
8031 case PM_CONTEXT_MODULE:
8032 case PM_CONTEXT_MODULE_ENSURE:
8033 case PM_CONTEXT_MODULE_RESCUE:
8034 case PM_CONTEXT_MODULE_ELSE:
8035 case PM_CONTEXT_SCLASS:
8036 case PM_CONTEXT_SCLASS_ENSURE:
8037 case PM_CONTEXT_SCLASS_RESCUE:
8038 case PM_CONTEXT_SCLASS_ELSE:
8041 context_node = context_node->prev;
8053context_human(pm_context_t context) {
8055 case PM_CONTEXT_NONE:
8056 case PM_CONTEXT_MAXIMUM:
8057 assert(
false &&
"unreachable");
8059 case PM_CONTEXT_BEGIN:
return "begin statement";
8060 case PM_CONTEXT_BLOCK_BRACES:
return "'{'..'}' block";
8061 case PM_CONTEXT_BLOCK_KEYWORDS:
return "'do'..'end' block";
8062 case PM_CONTEXT_BLOCK_PARAMETERS:
return "'|'..'|' block parameter";
8063 case PM_CONTEXT_CASE_WHEN:
return "'when' clause";
8064 case PM_CONTEXT_CASE_IN:
return "'in' clause";
8065 case PM_CONTEXT_CLASS:
return "class definition";
8066 case PM_CONTEXT_DEF:
return "method definition";
8067 case PM_CONTEXT_DEF_PARAMS:
return "method parameters";
8068 case PM_CONTEXT_DEFAULT_PARAMS:
return "parameter default value";
8069 case PM_CONTEXT_DEFINED:
return "'defined?' expression";
8070 case PM_CONTEXT_ELSE:
8071 case PM_CONTEXT_BEGIN_ELSE:
8072 case PM_CONTEXT_BLOCK_ELSE:
8073 case PM_CONTEXT_CLASS_ELSE:
8074 case PM_CONTEXT_DEF_ELSE:
8075 case PM_CONTEXT_LAMBDA_ELSE:
8076 case PM_CONTEXT_MODULE_ELSE:
8077 case PM_CONTEXT_SCLASS_ELSE:
return "'else' clause";
8078 case PM_CONTEXT_ELSIF:
return "'elsif' clause";
8079 case PM_CONTEXT_EMBEXPR:
return "embedded expression";
8080 case PM_CONTEXT_BEGIN_ENSURE:
8081 case PM_CONTEXT_BLOCK_ENSURE:
8082 case PM_CONTEXT_CLASS_ENSURE:
8083 case PM_CONTEXT_DEF_ENSURE:
8084 case PM_CONTEXT_LAMBDA_ENSURE:
8085 case PM_CONTEXT_MODULE_ENSURE:
8086 case PM_CONTEXT_SCLASS_ENSURE:
return "'ensure' clause";
8087 case PM_CONTEXT_FOR:
return "for loop";
8088 case PM_CONTEXT_FOR_INDEX:
return "for loop index";
8089 case PM_CONTEXT_IF:
return "if statement";
8090 case PM_CONTEXT_LAMBDA_BRACES:
return "'{'..'}' lambda block";
8091 case PM_CONTEXT_LAMBDA_DO_END:
return "'do'..'end' lambda block";
8092 case PM_CONTEXT_LOOP_PREDICATE:
return "loop predicate";
8093 case PM_CONTEXT_MAIN:
return "top level context";
8094 case PM_CONTEXT_MODULE:
return "module definition";
8095 case PM_CONTEXT_MULTI_TARGET:
return "multiple targets";
8096 case PM_CONTEXT_PARENS:
return "parentheses";
8097 case PM_CONTEXT_POSTEXE:
return "'END' block";
8098 case PM_CONTEXT_PREDICATE:
return "predicate";
8099 case PM_CONTEXT_PREEXE:
return "'BEGIN' block";
8100 case PM_CONTEXT_BEGIN_RESCUE:
8101 case PM_CONTEXT_BLOCK_RESCUE:
8102 case PM_CONTEXT_CLASS_RESCUE:
8103 case PM_CONTEXT_DEF_RESCUE:
8104 case PM_CONTEXT_LAMBDA_RESCUE:
8105 case PM_CONTEXT_MODULE_RESCUE:
8106 case PM_CONTEXT_RESCUE_MODIFIER:
8107 case PM_CONTEXT_SCLASS_RESCUE:
return "'rescue' clause";
8108 case PM_CONTEXT_SCLASS:
return "singleton class definition";
8109 case PM_CONTEXT_TERNARY:
return "ternary expression";
8110 case PM_CONTEXT_UNLESS:
return "unless statement";
8111 case PM_CONTEXT_UNTIL:
return "until statement";
8112 case PM_CONTEXT_WHILE:
return "while statement";
8115 assert(
false &&
"unreachable");
8124pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8125 if (invalid != NULL) {
8126 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8127 pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
8132pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8133 const uint8_t *invalid = NULL;
8134 size_t length = pm_strspn_binary_number(
string, parser->end -
string, &invalid);
8135 pm_strspn_number_validate(parser,
string, length, invalid);
8140pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8141 const uint8_t *invalid = NULL;
8142 size_t length = pm_strspn_octal_number(
string, parser->end -
string, &invalid);
8143 pm_strspn_number_validate(parser,
string, length, invalid);
8148pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8149 const uint8_t *invalid = NULL;
8150 size_t length = pm_strspn_decimal_number(
string, parser->end -
string, &invalid);
8151 pm_strspn_number_validate(parser,
string, length, invalid);
8156pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8157 const uint8_t *invalid = NULL;
8158 size_t length = pm_strspn_hexadecimal_number(
string, parser->end -
string, &invalid);
8159 pm_strspn_number_validate(parser,
string, length, invalid);
8163static pm_token_type_t
8164lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8165 pm_token_type_t
type = PM_TOKEN_INTEGER;
8169 if (peek(parser) ==
'.') {
8170 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8171 parser->current.end += 2;
8172 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8173 type = PM_TOKEN_FLOAT;
8183 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8184 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8185 parser->current.end += 2;
8187 if (pm_char_is_decimal_digit(peek(parser))) {
8188 parser->current.end++;
8189 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8191 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8193 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8194 parser->current.end++;
8195 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8201 type = PM_TOKEN_FLOAT;
8207static pm_token_type_t
8208lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8209 pm_token_type_t
type = PM_TOKEN_INTEGER;
8212 if (peek_offset(parser, -1) ==
'0') {
8213 switch (*parser->current.end) {
8217 parser->current.end++;
8218 if (pm_char_is_decimal_digit(peek(parser))) {
8219 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8222 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8230 parser->current.end++;
8231 if (pm_char_is_binary_digit(peek(parser))) {
8232 parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
8235 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8238 parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
8244 parser->current.end++;
8245 if (pm_char_is_octal_digit(peek(parser))) {
8246 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8249 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8252 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8265 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8266 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8272 parser->current.end++;
8273 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8274 parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
8277 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8280 parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8285 type = lex_optional_float_suffix(parser, seen_e);
8292 type = lex_optional_float_suffix(parser, seen_e);
8301 const uint8_t *cursor = parser->current.end;
8302 const uint8_t *end = parser->end;
8303 uint64_t value = (uint64_t) (cursor[-1] -
'0');
8305 bool has_underscore =
false;
8306 bool prev_underscore =
false;
8307 const uint8_t *invalid = NULL;
8309 while (cursor < end) {
8310 uint8_t c = *cursor;
8311 if (c >=
'0' && c <=
'9') {
8312 if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c -
'0');
8313 prev_underscore =
false;
8315 }
else if (c ==
'_') {
8316 has_underscore =
true;
8317 if (prev_underscore && invalid == NULL) invalid = cursor;
8318 prev_underscore =
true;
8325 if (has_underscore) {
8326 if (prev_underscore && invalid == NULL) invalid = cursor - 1;
8327 pm_strspn_number_validate(parser, parser->current.end, (
size_t) (cursor - parser->current.end), invalid);
8330 if (value <= UINT32_MAX) {
8331 parser->integer.value = (uint32_t) value;
8332 parser->integer.lexed =
true;
8335 parser->current.end = cursor;
8343 uint8_t next = peek(parser);
8344 if (next ==
'.' || next ==
'e' || next ==
'E') {
8345 type = lex_optional_float_suffix(parser, seen_e);
8349 if (
type != PM_TOKEN_INTEGER) {
8350 parser->integer.lexed =
false;
8359 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8360 const uint8_t *fraction_start = parser->current.end;
8361 const uint8_t *fraction_end = parser->current.end + 2;
8362 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
8363 pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
8369static pm_token_type_t
8371 pm_token_type_t
type = PM_TOKEN_INTEGER;
8372 parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8373 parser->integer.lexed =
false;
8375 if (parser->current.end < parser->end) {
8376 bool seen_e =
false;
8377 type = lex_numeric_prefix(parser, &seen_e);
8379 const uint8_t *end = parser->current.end;
8380 pm_token_type_t suffix_type =
type;
8382 if (
type == PM_TOKEN_INTEGER) {
8383 if (match(parser,
'r')) {
8384 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8386 if (match(parser,
'i')) {
8387 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8389 }
else if (match(parser,
'i')) {
8390 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8393 if (!seen_e && match(parser,
'r')) {
8394 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8396 if (match(parser,
'i')) {
8397 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8399 }
else if (match(parser,
'i')) {
8400 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8404 const uint8_t b = peek(parser);
8405 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8406 parser->current.end = end;
8415static pm_token_type_t
8417 if (parser->current.end >= parser->end) {
8418 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8419 return PM_TOKEN_GLOBAL_VARIABLE;
8424 bool allow_multiple =
true;
8426 switch (*parser->current.end) {
8443 parser->current.end++;
8444 return PM_TOKEN_GLOBAL_VARIABLE;
8450 parser->current.end++;
8451 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8454 parser->current.end++;
8457 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8459 parser->current.end += width;
8460 }
while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8463 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;
8464 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
8467 return PM_TOKEN_GLOBAL_VARIABLE;
8479 parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
8480 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8483 parser->current.end++;
8484 allow_multiple =
false;
8489 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8491 parser->current.end += width;
8492 }
while (allow_multiple && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8493 }
else if (pm_char_is_whitespace(peek(parser))) {
8496 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8500 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;
8501 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8502 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);
8505 return PM_TOKEN_GLOBAL_VARIABLE;
8523lex_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) {
8524 if (memcmp(current_start, value, vlen) == 0) {
8525 pm_lex_state_t last_state = parser->lex_state;
8527 if (parser->lex_state & PM_LEX_STATE_FNAME) {
8528 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8530 lex_state_set(parser, state);
8531 if (state == PM_LEX_STATE_BEG) {
8532 parser->command_start =
true;
8535 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8536 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8537 return modifier_type;
8544 return PM_TOKEN_EOF;
8547static pm_token_type_t
8548lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8551 const uint8_t *end = parser->end;
8552 const uint8_t *current_start = parser->current.start;
8553 const uint8_t *current_end = parser->current.end;
8554 bool encoding_changed = parser->encoding_changed;
8556 if (encoding_changed) {
8557 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8558 current_end += width;
8562 current_end += scan_identifier_ascii(current_end, end);
8565 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8566 current_end += width;
8569 parser->current.end = current_end;
8573 width = (size_t) (current_end - current_start);
8575 if (current_end < end) {
8576 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8582 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8583 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8587 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8588 (void) match(parser,
':');
8592 parser->explicit_encoding = NULL;
8593 return PM_TOKEN_LABEL;
8596 if (parser->lex_state != PM_LEX_STATE_DOT) {
8597 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8598 return PM_TOKEN_KEYWORD_DEFINED;
8602 return PM_TOKEN_METHOD_NAME;
8605 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,
'=')) {
8608 return PM_TOKEN_IDENTIFIER;
8612 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8613 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8617 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8618 (void) match(parser,
':');
8622 parser->explicit_encoding = NULL;
8623 return PM_TOKEN_LABEL;
8627 if (parser->lex_state != PM_LEX_STATE_DOT) {
8628 pm_token_type_t
type;
8632 pm_lex_state_t previous_lex_state = parser->lex_state;
8636 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8644 if (previous_lex_state & PM_LEX_STATE_FNAME) {
8645 return PM_TOKEN_KEYWORD_DO;
8647 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
8661 parser->lambda_enclosure_nesting = -1;
8662 return PM_TOKEN_KEYWORD_DO_LAMBDA;
8664 if (pm_do_loop_stack_p(parser)) {
8665 return PM_TOKEN_KEYWORD_DO_LOOP;
8667 if (!pm_accepts_block_stack_p(parser)) {
8668 return PM_TOKEN_KEYWORD_DO_BLOCK;
8670 return PM_TOKEN_KEYWORD_DO;
8673 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;
8674 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;
8675 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;
8678 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;
8679 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;
8680 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;
8681 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;
8682 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;
8683 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;
8684 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;
8687 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;
8688 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;
8689 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;
8690 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;
8691 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;
8692 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;
8693 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;
8694 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;
8697 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;
8698 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;
8699 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;
8700 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;
8701 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;
8702 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;
8703 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;
8704 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;
8705 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;
8706 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;
8707 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;
8708 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;
8709 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;
8712 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;
8713 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;
8714 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;
8715 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;
8716 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;
8719 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;
8720 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;
8723 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;
8728 if (encoding_changed) {
8729 return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8735 if (*current_start < 0x80) {
8736 return (*current_start >=
'A' && *current_start <=
'Z') ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8738 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8747 return (parser->current.start == parser->start) || (parser->current.start[-1] ==
'\n');
8764static pm_token_type_t
8765lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8768 if (pound + 1 >= parser->end) {
8769 parser->current.end = pound + 1;
8770 return PM_TOKEN_STRING_CONTENT;
8779 if (pound + 2 >= parser->end) {
8780 parser->current.end = pound + 1;
8781 return PM_TOKEN_STRING_CONTENT;
8786 const uint8_t *variable = pound + 2;
8787 if (*variable ==
'@' && pound + 3 < parser->end) variable++;
8789 if (char_is_identifier_start(parser, variable, parser->end - variable)) {
8793 if (pound > parser->current.start) {
8794 parser->current.end = pound;
8795 return PM_TOKEN_STRING_CONTENT;
8800 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8801 parser->current.end = pound + 1;
8802 return PM_TOKEN_EMBVAR;
8808 parser->current.end = pound + 1;
8814 if (pound + 2 >= parser->end) {
8815 parser->current.end = pound + 1;
8816 return PM_TOKEN_STRING_CONTENT;
8822 const uint8_t *check = pound + 2;
8824 if (pound[2] ==
'-') {
8825 if (pound + 3 >= parser->end) {
8826 parser->current.end = pound + 2;
8827 return PM_TOKEN_STRING_CONTENT;
8838 char_is_identifier_start(parser, check, parser->end - check) ||
8839 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8844 if (pound > parser->current.start) {
8845 parser->current.end = pound;
8846 return PM_TOKEN_STRING_CONTENT;
8851 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8852 parser->current.end = pound + 1;
8853 return PM_TOKEN_EMBVAR;
8858 parser->current.end = pound + 1;
8864 if (pound > parser->current.start) {
8865 parser->current.end = pound;
8866 return PM_TOKEN_STRING_CONTENT;
8869 parser->enclosure_nesting++;
8873 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8874 parser->current.end = pound + 2;
8875 parser->command_start =
true;
8876 pm_enclosure_frame_push(parser);
8877 return PM_TOKEN_EMBEXPR_BEGIN;
8882 parser->current.end = pound + 1;
8887static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8888static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8889static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8890static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8891static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8896static const bool ascii_printable_chars[] = {
8897 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8898 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8899 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8900 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8901 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8902 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8903 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8904 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8908char_is_ascii_printable(
const uint8_t b) {
8909 return (b < 0x80) && ascii_printable_chars[b];
8917escape_hexadecimal_digit(
const uint8_t value) {
8918 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8927escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const pm_location_t *error_location,
const uint8_t flags) {
8929 for (
size_t index = 0; index < length; index++) {
8930 if (index != 0) value <<= 4;
8931 value |= escape_hexadecimal_digit(
string[index]);
8936 if (value >= 0xD800 && value <= 0xDFFF) {
8937 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8940 }
else if (error_location != NULL) {
8941 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
8943 pm_parser_err(parser, U32(
string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
8955escape_byte(uint8_t value,
const uint8_t flags) {
8956 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8957 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8965escape_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) {
8969 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8970 if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
8971 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8975 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
8979 parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
8982 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8983 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8987 pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
8990 pm_buffer_append_byte(buffer, 0xEF);
8991 pm_buffer_append_byte(buffer, 0xBF);
8992 pm_buffer_append_byte(buffer, 0xBD);
9003 if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
9004 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9008 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
9012 parser->explicit_encoding = parser->encoding;
9015 pm_buffer_append_byte(buffer,
byte);
9035 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9036 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9039 escape_write_byte_encoded(parser, buffer, flags,
byte);
9048 if (parser->encoding_changed) {
9049 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9051 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9055 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);
9056 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
9057 }
else if (width > 1) {
9059 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9060 pm_buffer_append_bytes(b, parser->current.end, width);
9061 parser->current.end += width;
9065 parser->current.end++;
9066 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9076escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9077#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9079 PM_PARSER_WARN_TOKEN_FORMAT(
9082 PM_WARN_INVALID_CHARACTER,
9096 uint8_t peeked = peek(parser);
9099 parser->current.end++;
9100 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9104 parser->current.end++;
9105 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9109 parser->current.end++;
9110 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9114 parser->current.end++;
9115 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9119 parser->current.end++;
9120 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9124 parser->current.end++;
9125 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9129 parser->current.end++;
9130 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9134 parser->current.end++;
9135 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9139 parser->current.end++;
9140 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9144 parser->current.end++;
9145 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9149 parser->current.end++;
9150 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9153 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9154 uint8_t value = (uint8_t) (*parser->current.end -
'0');
9155 parser->current.end++;
9157 if (pm_char_is_octal_digit(peek(parser))) {
9158 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9159 parser->current.end++;
9161 if (pm_char_is_octal_digit(peek(parser))) {
9162 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9163 parser->current.end++;
9167 value = escape_byte(value, flags);
9168 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9172 const uint8_t *start = parser->current.end - 1;
9174 parser->current.end++;
9175 uint8_t
byte = peek(parser);
9177 if (pm_char_is_hexadecimal_digit(
byte)) {
9178 uint8_t value = escape_hexadecimal_digit(
byte);
9179 parser->current.end++;
9181 byte = peek(parser);
9182 if (pm_char_is_hexadecimal_digit(
byte)) {
9183 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9184 parser->current.end++;
9187 value = escape_byte(value, flags);
9188 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9189 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9190 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9192 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9196 escape_write_byte_encoded(parser, buffer, flags, value);
9198 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9204 const uint8_t *start = parser->current.end - 1;
9205 parser->current.end++;
9207 if (parser->current.end == parser->end) {
9208 const uint8_t *start = parser->current.end - 2;
9209 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9210 }
else if (peek(parser) ==
'{') {
9211 const uint8_t *unicode_codepoints_start = parser->current.end - 2;
9212 parser->current.end++;
9216 if ((whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end)) > 0) {
9217 parser->current.end += whitespace;
9218 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9223 parser->current.end += 2;
9229 const uint8_t *extra_codepoints_start = NULL;
9230 int codepoints_count = 0;
9232 while ((parser->current.end < parser->end) && (*parser->current.end !=
'}')) {
9233 const uint8_t *unicode_start = parser->current.end;
9234 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
9236 if (hexadecimal_length > 6) {
9238 pm_parser_err(parser, U32(unicode_start - parser->start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9239 }
else if (hexadecimal_length == 0) {
9242 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9247 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9249 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
9250 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9256 parser->current.end += hexadecimal_length;
9258 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9259 extra_codepoints_start = unicode_start;
9262 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
9263 escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
9265 parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
9270 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9271 pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9274 if (parser->current.end == parser->end) {
9275 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);
9276 }
else if (peek(parser) ==
'}') {
9277 parser->current.end++;
9279 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9284 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9286 pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9290 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9291 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->current.end - unicode_codepoints_start));
9294 size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
9297 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9298 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9300 const uint8_t *start = parser->current.end - 2;
9301 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9303 }
else if (length == 4) {
9304 uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
9306 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9307 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end + 4 - start));
9310 escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
9311 parser->current.end += 4;
9313 parser->current.end += length;
9315 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9319 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9321 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9329 parser->current.end++;
9330 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9331 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9334 if (parser->current.end == parser->end) {
9335 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9339 uint8_t peeked = peek(parser);
9342 parser->current.end++;
9343 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9347 parser->current.end++;
9349 if (match(parser,
'u') || match(parser,
'U')) {
9350 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9354 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9357 parser->current.end++;
9358 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9359 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9362 parser->current.end++;
9363 escape_read_warn(parser, flags, 0,
"\\t");
9364 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9367 if (!char_is_ascii_printable(peeked)) {
9368 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9372 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);
9373 parser->current.end++;
9374 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9380 parser->current.end++;
9381 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9382 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9385 if (peek(parser) !=
'-') {
9386 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9387 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9391 parser->current.end++;
9392 if (parser->current.end == parser->end) {
9393 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9397 uint8_t peeked = peek(parser);
9400 parser->current.end++;
9401 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9405 parser->current.end++;
9407 if (match(parser,
'u') || match(parser,
'U')) {
9408 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9412 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9415 parser->current.end++;
9416 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9417 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9420 parser->current.end++;
9421 escape_read_warn(parser, flags, 0,
"\\t");
9422 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9425 if (!char_is_ascii_printable(peeked)) {
9426 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9427 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9431 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);
9432 parser->current.end++;
9433 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9439 parser->current.end++;
9440 if (flags & PM_ESCAPE_FLAG_META) {
9441 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9444 if (peek(parser) !=
'-') {
9445 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9446 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9450 parser->current.end++;
9451 if (parser->current.end == parser->end) {
9452 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9456 uint8_t peeked = peek(parser);
9459 parser->current.end++;
9461 if (match(parser,
'u') || match(parser,
'U')) {
9462 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9466 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9469 parser->current.end++;
9470 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9471 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9474 parser->current.end++;
9475 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9476 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9479 if (!char_is_ascii_printable(peeked)) {
9480 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9481 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9485 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);
9486 parser->current.end++;
9487 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9492 if (peek_offset(parser, 1) ==
'\n') {
9493 if (parser->heredoc_end == NULL) pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
9494 parser->current.end += 2;
9495 escape_write_byte_encoded(parser, buffer, flags, escape_byte(
'\n', flags));
9501 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9502 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9503 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9506 if (parser->current.end < parser->end) {
9507 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9509 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9541static pm_token_type_t
9543 if (lex_state_end_p(parser)) {
9544 lex_state_set(parser, PM_LEX_STATE_BEG);
9545 return PM_TOKEN_QUESTION_MARK;
9553 parser->explicit_encoding = NULL;
9555 if (parser->current.end >= parser->end) {
9556 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9557 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9558 return PM_TOKEN_CHARACTER_LITERAL;
9561 if (pm_char_is_whitespace(*parser->current.end)) {
9562 lex_state_set(parser, PM_LEX_STATE_BEG);
9563 return PM_TOKEN_QUESTION_MARK;
9566 lex_state_set(parser, PM_LEX_STATE_BEG);
9568 if (match(parser,
'\\')) {
9569 lex_state_set(parser, PM_LEX_STATE_END);
9572 pm_buffer_init(&buffer, 3);
9574 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9577 void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length,
PRISM_ALIGNOF(uint8_t));
9578 pm_string_constant_init(&parser->current_string, (
const char *) arena_data, buffer.length);
9579 pm_buffer_cleanup(&buffer);
9581 return PM_TOKEN_CHARACTER_LITERAL;
9583 size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9588 !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) ==
'_') ||
9590 (parser->current.end + encoding_width >= parser->end) ||
9591 !char_is_identifier(parser, parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
9594 lex_state_set(parser, PM_LEX_STATE_END);
9595 parser->current.end += encoding_width;
9596 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9597 return PM_TOKEN_CHARACTER_LITERAL;
9601 return PM_TOKEN_QUESTION_MARK;
9608static pm_token_type_t
9610 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9611 const uint8_t *end = parser->end;
9614 if ((width = char_is_identifier_start(parser, parser->current.end, end - parser->current.end)) > 0) {
9615 parser->current.end += width;
9617 while ((width = char_is_identifier(parser, parser->current.end, end - parser->current.end)) > 0) {
9618 parser->current.end += width;
9620 }
else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
9621 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9622 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
9623 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9626 size_t width = parser->encoding->char_width(parser->current.end, end - parser->current.end);
9627 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, (
int) ((parser->current.end + width) - parser->current.start), (
const char *) parser->current.start);
9629 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9630 pm_parser_err_token(parser, &parser->current, diag_id);
9635 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
9636 lex_mode_pop(parser);
9647 if (parser->lex_callback.callback) {
9648 parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
9661 .location = TOK2LOC(parser, &parser->current)
9672static pm_token_type_t
9675 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9677 if (newline == NULL) {
9678 parser->current.end = parser->end;
9680 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9681 parser->current.end = newline + 1;
9684 parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
9685 parser_lex_callback(parser);
9688 const uint8_t *comment_start = parser->current.start;
9689 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9693 while (parser->current.end + 4 <= parser->end) {
9694 parser->current.start = parser->current.end;
9699 (memcmp(parser->current.end,
"=end", 4) == 0) &&
9701 (parser->current.end + 4 == parser->end) ||
9702 pm_char_is_whitespace(parser->current.end[4]) ||
9703 (parser->current.end[4] ==
'\0') ||
9704 (parser->current.end[4] ==
'\004') ||
9705 (parser->current.end[4] ==
'\032')
9708 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9710 if (newline == NULL) {
9711 parser->current.end = parser->end;
9713 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9714 parser->current.end = newline + 1;
9717 parser->current.type = PM_TOKEN_EMBDOC_END;
9718 parser_lex_callback(parser);
9720 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9721 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9723 return PM_TOKEN_EMBDOC_END;
9728 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9730 if (newline == NULL) {
9731 parser->current.end = parser->end;
9733 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9734 parser->current.end = newline + 1;
9737 parser->current.type = PM_TOKEN_EMBDOC_LINE;
9738 parser_lex_callback(parser);
9741 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9743 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9744 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9746 return PM_TOKEN_EOF;
9756 parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
9757 parser_lex_callback(parser);
9771 assert(parser->heredoc_end <= parser->end);
9772 parser->next_start = parser->heredoc_end;
9773 parser->heredoc_end = NULL;
9781 const uint8_t *cursor = parser->current.end;
9783 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9784 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9847 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9861 if (parser->encoding_changed) {
9862 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9864 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9869 return (width == 0 ? 1 : width);
9877 size_t width = parser_char_width(parser);
9878 pm_buffer_append_bytes(&token_buffer->
buffer, parser->current.end, width);
9879 parser->current.end += width;
9884 size_t width = parser_char_width(parser);
9885 const uint8_t *start = parser->current.end;
9886 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, width);
9887 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, width);
9888 parser->current.end += width;
9900 size_t len = pm_buffer_length(&token_buffer->
buffer);
9901 void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->
buffer),
len,
PRISM_ALIGNOF(uint8_t));
9902 pm_string_constant_init(&parser->current_string, (
const char *) arena_data,
len);
9903 pm_buffer_cleanup(&token_buffer->
buffer);
9908 pm_token_buffer_copy(parser, &token_buffer->
base);
9923 if (token_buffer->
cursor == NULL) {
9924 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9926 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->current.end - token_buffer->
cursor));
9927 pm_token_buffer_copy(parser, token_buffer);
9934 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9936 const uint8_t *cursor = token_buffer->
base.
cursor;
9937 size_t length = (size_t) (parser->current.end - cursor);
9938 pm_buffer_append_bytes(&token_buffer->
base.
buffer, cursor, length);
9939 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, cursor, length);
9940 pm_regexp_token_buffer_copy(parser, token_buffer);
9944#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9956 const uint8_t *start;
9957 if (token_buffer->
cursor == NULL) {
9958 pm_buffer_init(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9959 start = parser->current.start;
9961 start = token_buffer->
cursor;
9964 const uint8_t *end = parser->current.end - 1;
9965 assert(end >= start);
9966 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9968 token_buffer->
cursor = end;
9973 const uint8_t *start;
9975 pm_buffer_init(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9976 pm_buffer_init(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9977 start = parser->current.start;
9982 const uint8_t *end = parser->current.end - 1;
9983 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9984 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9989#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9996pm_heredoc_strspn_inline_whitespace(
pm_parser_t *parser,
const uint8_t **cursor, pm_heredoc_indent_t indent) {
9997 size_t whitespace = 0;
10000 case PM_HEREDOC_INDENT_NONE:
10005 case PM_HEREDOC_INDENT_DASH:
10007 *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
10009 case PM_HEREDOC_INDENT_TILDE:
10012 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10013 if (**cursor ==
'\t') {
10014 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10033 size_t eol_length = match_eol(parser);
10036 if (parser->heredoc_end) {
10040 parser_flush_heredoc_end(parser);
10043 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
10046 uint8_t delimiter = *parser->current.end;
10050 if (eol_length == 2) {
10051 delimiter = *(parser->current.end + 1);
10054 parser->current.end += eol_length;
10058 return *parser->current.end++;
10065#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10075 assert(parser->current.end <= parser->end);
10076 parser->previous = parser->current;
10079 bool previous_command_start = parser->command_start;
10080 parser->command_start =
false;
10084 bool lexed_comment =
false;
10088 unsigned int semantic_token_seen = parser->semantic_token_seen;
10089 parser->semantic_token_seen =
true;
10097 switch (parser->lex_modes.current->mode) {
10098 case PM_LEX_DEFAULT:
10099 case PM_LEX_EMBEXPR:
10100 case PM_LEX_EMBVAR:
10109 if (parser->next_start != NULL) {
10110 parser->current.end = parser->next_start;
10111 parser->next_start = NULL;
10116 bool space_seen =
false;
10121 bool chomping =
true;
10128 static const uint8_t inline_whitespace[256] = {
10129 [
' '] = 1, [
'\t'] = 1, [
'\f'] = 1, [
'\v'] = 1
10131 const uint8_t *scan = parser->current.end;
10132 while (scan < parser->end && inline_whitespace[*scan]) scan++;
10133 if (scan > parser->current.end) {
10134 parser->current.end = scan;
10137 if (scan >= parser->end)
break;
10140 switch (*parser->current.end) {
10142 if (match_eol_offset(parser, 1)) {
10145 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10146 parser->current.end++;
10151 size_t eol_length = match_eol_offset(parser, 1);
10153 if (parser->heredoc_end) {
10154 parser->current.end = parser->heredoc_end;
10155 parser->heredoc_end = NULL;
10157 parser->current.end += eol_length + 1;
10158 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10161 }
else if (pm_char_is_inline_whitespace(*parser->current.end)) {
10162 parser->current.end += 2;
10176 parser->current.start = parser->current.end;
10180 if (parser->current.end >= parser->end) {
10184 if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
10185 lex_mode_pop(parser);
10186 goto switch_lex_modes;
10194 if (parser->current.start > parser->start && (*(parser->current.start - 1) ==
'\n')) {
10195 parser->current.start -= 1;
10202 switch (*parser->current.end++) {
10206 parser->current.end--;
10210 const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
10211 parser->current.end = ending == NULL ? parser->end : ending;
10216 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10217 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
10219 parser->current.type = PM_TOKEN_COMMENT;
10220 parser_lex_callback(parser);
10224 if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
10225 ptrdiff_t length = parser->current.end - parser->current.start;
10231 if (length >= 10 && !parser->encoding_locked) {
10232 parser_lex_magic_comment_encoding(parser);
10240 if (ending == NULL) {
10241 lexed_comment =
true;
10243 parser->current.start = ending;
10244 parser->current.end = ending + 1;
10250 parser->semantic_token_seen = semantic_token_seen & 0x1;
10251 size_t eol_length = match_eol_at(parser, parser->current.end - 1);
10263 if (!lexed_comment) {
10264 parser->current.end += eol_length - 1;
10267 if (parser->heredoc_end == NULL) {
10268 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10272 if (parser->heredoc_end) {
10273 parser_flush_heredoc_end(parser);
10278 switch (lex_state_ignored_p(parser)) {
10279 case PM_IGNORED_NEWLINE_NONE:
10281 case PM_IGNORED_NEWLINE_PATTERN:
10282 if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
10283 if (!lexed_comment) {
10284 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10285 parser_lex_callback(parser);
10288 lex_state_set(parser, PM_LEX_STATE_BEG);
10289 parser->command_start =
true;
10290 parser->current.type = PM_TOKEN_NEWLINE;
10294 case PM_IGNORED_NEWLINE_ALL:
10295 if (!lexed_comment) parser_lex_ignored_newline(parser);
10296 lexed_comment =
false;
10297 goto lex_next_token;
10304 const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
10305 next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
10307 if (next_content < parser->end) {
10313 if (next_content[0] ==
'#') {
10315 const uint8_t *following = next_newline(next_content, parser->end - next_content);
10317 while (following && (following + 1 < parser->end)) {
10319 following += pm_strspn_inline_whitespace(following, parser->end - following);
10323 if (peek_at(parser, following) !=
'#')
break;
10327 following = next_newline(following, parser->end - following);
10332 if (lex_state_ignored_p(parser)) {
10333 if (!lexed_comment) parser_lex_ignored_newline(parser);
10334 lexed_comment =
false;
10335 goto lex_next_token;
10341 (peek_at(parser, following) ==
'.') ||
10342 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10344 if (!lexed_comment) parser_lex_ignored_newline(parser);
10345 lexed_comment =
false;
10346 goto lex_next_token;
10354 (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
10356 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10357 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10359 peek_at(parser, following) ==
'a' &&
10360 peek_at(parser, following + 1) ==
'n' &&
10361 peek_at(parser, following + 2) ==
'd' &&
10362 peek_at(parser, next_content + 3) !=
'!' &&
10363 peek_at(parser, next_content + 3) !=
'?' &&
10364 !char_is_identifier(parser, following + 3, parser->end - (following + 3))
10367 peek_at(parser, following) ==
'o' &&
10368 peek_at(parser, following + 1) ==
'r' &&
10369 peek_at(parser, next_content + 2) !=
'!' &&
10370 peek_at(parser, next_content + 2) !=
'?' &&
10371 !char_is_identifier(parser, following + 2, parser->end - (following + 2))
10375 if (!lexed_comment) parser_lex_ignored_newline(parser);
10376 lexed_comment =
false;
10377 goto lex_next_token;
10383 if (next_content[0] ==
'.') {
10387 if (peek_at(parser, next_content + 1) ==
'.') {
10388 if (!lexed_comment) {
10389 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10390 parser_lex_callback(parser);
10393 lex_state_set(parser, PM_LEX_STATE_BEG);
10394 parser->command_start =
true;
10395 parser->current.type = PM_TOKEN_NEWLINE;
10399 if (!lexed_comment) parser_lex_ignored_newline(parser);
10400 lex_state_set(parser, PM_LEX_STATE_DOT);
10401 parser->current.start = next_content;
10402 parser->current.end = next_content + 1;
10403 parser->next_start = NULL;
10409 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10410 if (!lexed_comment) parser_lex_ignored_newline(parser);
10411 lex_state_set(parser, PM_LEX_STATE_DOT);
10412 parser->current.start = next_content;
10413 parser->current.end = next_content + 2;
10414 parser->next_start = NULL;
10415 LEX(PM_TOKEN_AMPERSAND_DOT);
10418 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
10421 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10422 if (!lexed_comment) parser_lex_ignored_newline(parser);
10423 lex_state_set(parser, PM_LEX_STATE_BEG);
10424 parser->current.start = next_content;
10425 parser->current.end = next_content + 2;
10426 parser->next_start = NULL;
10427 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10432 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10433 if (!lexed_comment) parser_lex_ignored_newline(parser);
10434 lex_state_set(parser, PM_LEX_STATE_BEG);
10435 parser->current.start = next_content;
10436 parser->current.end = next_content + 2;
10437 parser->next_start = NULL;
10438 LEX(PM_TOKEN_PIPE_PIPE);
10444 peek_at(parser, next_content) ==
'a' &&
10445 peek_at(parser, next_content + 1) ==
'n' &&
10446 peek_at(parser, next_content + 2) ==
'd' &&
10447 peek_at(parser, next_content + 3) !=
'!' &&
10448 peek_at(parser, next_content + 3) !=
'?' &&
10449 !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
10451 if (!lexed_comment) parser_lex_ignored_newline(parser);
10452 lex_state_set(parser, PM_LEX_STATE_BEG);
10453 parser->current.start = next_content;
10454 parser->current.end = next_content + 3;
10455 parser->next_start = NULL;
10456 parser->command_start =
true;
10457 LEX(PM_TOKEN_KEYWORD_AND);
10463 peek_at(parser, next_content) ==
'o' &&
10464 peek_at(parser, next_content + 1) ==
'r' &&
10465 peek_at(parser, next_content + 2) !=
'!' &&
10466 peek_at(parser, next_content + 2) !=
'?' &&
10467 !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
10469 if (!lexed_comment) parser_lex_ignored_newline(parser);
10470 lex_state_set(parser, PM_LEX_STATE_BEG);
10471 parser->current.start = next_content;
10472 parser->current.end = next_content + 2;
10473 parser->next_start = NULL;
10474 parser->command_start =
true;
10475 LEX(PM_TOKEN_KEYWORD_OR);
10482 lex_state_set(parser, PM_LEX_STATE_BEG);
10483 parser->command_start =
true;
10484 parser->current.type = PM_TOKEN_NEWLINE;
10485 if (!lexed_comment) parser_lex_callback(parser);
10491 if ((parser->previous.
type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
10492 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
10495 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10496 LEX(PM_TOKEN_COMMA);
10504 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10506 if (lex_state_beg_p(parser)) {
10507 type = PM_TOKEN_PARENTHESIS_LEFT_GROUPING;
10508 }
else if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10509 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10512 parser->enclosure_nesting++;
10513 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10514 pm_enclosure_frame_push(parser);
10520 parser->enclosure_nesting--;
10521 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10522 pm_enclosure_frame_pop(parser);
10523 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10527 lex_state_set(parser, PM_LEX_STATE_BEG);
10528 parser->command_start =
true;
10529 LEX(PM_TOKEN_SEMICOLON);
10533 parser->enclosure_nesting++;
10534 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10536 if (lex_state_operator_p(parser)) {
10537 if (match(parser,
']')) {
10538 parser->enclosure_nesting--;
10539 lex_state_set(parser, PM_LEX_STATE_ARG);
10540 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10543 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10547 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10548 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10551 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10552 pm_enclosure_frame_push(parser);
10557 parser->enclosure_nesting--;
10558 lex_state_set(parser, PM_LEX_STATE_END);
10559 pm_enclosure_frame_pop(parser);
10560 LEX(PM_TOKEN_BRACKET_RIGHT);
10564 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10566 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
10568 parser->command_start =
true;
10569 lex_state_set(parser, PM_LEX_STATE_BEG);
10570 type = PM_TOKEN_LAMBDA_BEGIN;
10571 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10573 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10574 type = PM_TOKEN_BRACE_LEFT_HASH;
10575 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10577 parser->command_start =
true;
10578 lex_state_set(parser, PM_LEX_STATE_BEG);
10579 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10582 parser->command_start =
true;
10583 lex_state_set(parser, PM_LEX_STATE_BEG);
10584 type = PM_TOKEN_BRACE_LEFT_ARGUMENT;
10587 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10588 type = PM_TOKEN_BRACE_LEFT_HASH;
10591 parser->enclosure_nesting++;
10592 parser->brace_nesting++;
10593 pm_enclosure_frame_push(parser);
10600 parser->enclosure_nesting--;
10601 pm_enclosure_frame_pop(parser);
10603 if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
10604 lex_mode_pop(parser);
10605 LEX(PM_TOKEN_EMBEXPR_END);
10608 parser->brace_nesting--;
10609 lex_state_set(parser, PM_LEX_STATE_END);
10610 LEX(PM_TOKEN_BRACE_RIGHT);
10614 if (match(parser,
'*')) {
10615 if (match(parser,
'=')) {
10616 lex_state_set(parser, PM_LEX_STATE_BEG);
10617 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10620 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10622 if (lex_state_spcarg_p(parser, space_seen)) {
10623 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10624 type = PM_TOKEN_USTAR_STAR;
10625 }
else if (lex_state_beg_p(parser)) {
10626 type = PM_TOKEN_USTAR_STAR;
10627 }
else if (ambiguous_operator_p(parser, space_seen)) {
10628 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10631 if (lex_state_operator_p(parser)) {
10632 lex_state_set(parser, PM_LEX_STATE_ARG);
10634 lex_state_set(parser, PM_LEX_STATE_BEG);
10640 if (match(parser,
'=')) {
10641 lex_state_set(parser, PM_LEX_STATE_BEG);
10642 LEX(PM_TOKEN_STAR_EQUAL);
10645 pm_token_type_t
type = PM_TOKEN_STAR;
10647 if (lex_state_spcarg_p(parser, space_seen)) {
10648 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10649 type = PM_TOKEN_USTAR;
10650 }
else if (lex_state_beg_p(parser)) {
10651 type = PM_TOKEN_USTAR;
10652 }
else if (ambiguous_operator_p(parser, space_seen)) {
10653 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10656 if (lex_state_operator_p(parser)) {
10657 lex_state_set(parser, PM_LEX_STATE_ARG);
10659 lex_state_set(parser, PM_LEX_STATE_BEG);
10667 if (lex_state_operator_p(parser)) {
10668 lex_state_set(parser, PM_LEX_STATE_ARG);
10669 if (match(parser,
'@')) {
10670 LEX(PM_TOKEN_BANG);
10673 lex_state_set(parser, PM_LEX_STATE_BEG);
10676 if (match(parser,
'=')) {
10677 LEX(PM_TOKEN_BANG_EQUAL);
10680 if (match(parser,
'~')) {
10681 LEX(PM_TOKEN_BANG_TILDE);
10684 LEX(PM_TOKEN_BANG);
10689 current_token_starts_line(parser) &&
10690 (parser->current.end + 5 <= parser->end) &&
10691 memcmp(parser->current.end,
"begin", 5) == 0 &&
10692 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10694 pm_token_type_t
type = lex_embdoc(parser);
10695 if (
type == PM_TOKEN_EOF) {
10699 goto lex_next_token;
10702 if (lex_state_operator_p(parser)) {
10703 lex_state_set(parser, PM_LEX_STATE_ARG);
10705 lex_state_set(parser, PM_LEX_STATE_BEG);
10708 if (match(parser,
'>')) {
10709 LEX(PM_TOKEN_EQUAL_GREATER);
10712 if (match(parser,
'~')) {
10713 LEX(PM_TOKEN_EQUAL_TILDE);
10716 if (match(parser,
'=')) {
10717 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10720 LEX(PM_TOKEN_EQUAL);
10724 if (match(parser,
'<')) {
10726 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10727 !lex_state_end_p(parser) &&
10728 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10730 const uint8_t *end = parser->current.end;
10732 pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
10733 pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
10735 if (match(parser,
'-')) {
10736 indent = PM_HEREDOC_INDENT_DASH;
10738 else if (match(parser,
'~')) {
10739 indent = PM_HEREDOC_INDENT_TILDE;
10742 if (match(parser,
'`')) {
10743 quote = PM_HEREDOC_QUOTE_BACKTICK;
10745 else if (match(parser,
'"')) {
10746 quote = PM_HEREDOC_QUOTE_DOUBLE;
10748 else if (match(parser,
'\'')) {
10749 quote = PM_HEREDOC_QUOTE_SINGLE;
10752 const uint8_t *ident_start = parser->current.end;
10755 if (parser->current.end >= parser->end) {
10756 parser->current.end = end;
10757 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) == 0) {
10758 parser->current.end = end;
10760 if (quote == PM_HEREDOC_QUOTE_NONE) {
10761 parser->current.end += width;
10763 while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end))) {
10764 parser->current.end += width;
10769 while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
10770 if (*parser->current.end ==
'\r' || *parser->current.end ==
'\n')
break;
10771 parser->current.end++;
10775 size_t ident_length = (size_t) (parser->current.end - ident_start);
10776 bool ident_error =
false;
10778 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10779 pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10780 ident_error =
true;
10783 parser->explicit_encoding = NULL;
10785 .mode = PM_LEX_HEREDOC,
10788 .ident_start = ident_start,
10789 .ident_length = ident_length,
10793 .next_start = parser->current.end,
10794 .common_whitespace = NULL,
10795 .line_continuation =
false
10799 if (parser->heredoc_end == NULL) {
10800 const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
10802 if (body_start == NULL) {
10807 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10808 body_start = parser->end;
10812 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
10816 parser->next_start = body_start;
10818 parser->next_start = parser->heredoc_end;
10821 LEX(PM_TOKEN_HEREDOC_START);
10825 if (match(parser,
'=')) {
10826 lex_state_set(parser, PM_LEX_STATE_BEG);
10827 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10830 if (ambiguous_operator_p(parser, space_seen)) {
10831 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10834 if (lex_state_operator_p(parser)) {
10835 lex_state_set(parser, PM_LEX_STATE_ARG);
10837 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10838 lex_state_set(parser, PM_LEX_STATE_BEG);
10841 LEX(PM_TOKEN_LESS_LESS);
10844 if (lex_state_operator_p(parser)) {
10845 lex_state_set(parser, PM_LEX_STATE_ARG);
10847 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10848 lex_state_set(parser, PM_LEX_STATE_BEG);
10851 if (match(parser,
'=')) {
10852 if (match(parser,
'>')) {
10853 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10856 LEX(PM_TOKEN_LESS_EQUAL);
10859 LEX(PM_TOKEN_LESS);
10863 if (match(parser,
'>')) {
10864 if (lex_state_operator_p(parser)) {
10865 lex_state_set(parser, PM_LEX_STATE_ARG);
10867 lex_state_set(parser, PM_LEX_STATE_BEG);
10869 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10872 if (lex_state_operator_p(parser)) {
10873 lex_state_set(parser, PM_LEX_STATE_ARG);
10875 lex_state_set(parser, PM_LEX_STATE_BEG);
10878 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10882 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10883 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10884 LEX(PM_TOKEN_STRING_BEGIN);
10889 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10890 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10891 LEX(PM_TOKEN_BACKTICK);
10894 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10895 if (previous_command_start) {
10896 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10898 lex_state_set(parser, PM_LEX_STATE_ARG);
10901 LEX(PM_TOKEN_BACKTICK);
10904 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10905 LEX(PM_TOKEN_XSTRING_BEGIN);
10910 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10911 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10912 LEX(PM_TOKEN_STRING_BEGIN);
10917 LEX(lex_question_mark(parser));
10921 if (match(parser,
'&')) {
10922 lex_state_set(parser, PM_LEX_STATE_BEG);
10924 if (match(parser,
'=')) {
10925 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10928 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10931 if (match(parser,
'=')) {
10932 lex_state_set(parser, PM_LEX_STATE_BEG);
10933 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10936 if (match(parser,
'.')) {
10937 lex_state_set(parser, PM_LEX_STATE_DOT);
10938 LEX(PM_TOKEN_AMPERSAND_DOT);
10941 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10942 if (lex_state_spcarg_p(parser, space_seen)) {
10943 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10944 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10946 const uint8_t delim = peek_offset(parser, 1);
10948 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->current.end + 1, parser->end - (parser->current.end + 1))) {
10949 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10953 type = PM_TOKEN_UAMPERSAND;
10954 }
else if (lex_state_beg_p(parser)) {
10955 type = PM_TOKEN_UAMPERSAND;
10956 }
else if (ambiguous_operator_p(parser, space_seen)) {
10957 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10960 if (lex_state_operator_p(parser)) {
10961 lex_state_set(parser, PM_LEX_STATE_ARG);
10963 lex_state_set(parser, PM_LEX_STATE_BEG);
10971 if (match(parser,
'|')) {
10972 if (match(parser,
'=')) {
10973 lex_state_set(parser, PM_LEX_STATE_BEG);
10974 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10977 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10978 parser->current.end--;
10979 LEX(PM_TOKEN_PIPE);
10982 lex_state_set(parser, PM_LEX_STATE_BEG);
10983 LEX(PM_TOKEN_PIPE_PIPE);
10986 if (match(parser,
'=')) {
10987 lex_state_set(parser, PM_LEX_STATE_BEG);
10988 LEX(PM_TOKEN_PIPE_EQUAL);
10991 if (lex_state_operator_p(parser)) {
10992 lex_state_set(parser, PM_LEX_STATE_ARG);
10994 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10997 LEX(PM_TOKEN_PIPE);
11001 if (lex_state_operator_p(parser)) {
11002 lex_state_set(parser, PM_LEX_STATE_ARG);
11004 if (match(parser,
'@')) {
11005 LEX(PM_TOKEN_UPLUS);
11008 LEX(PM_TOKEN_PLUS);
11011 if (match(parser,
'=')) {
11012 lex_state_set(parser, PM_LEX_STATE_BEG);
11013 LEX(PM_TOKEN_PLUS_EQUAL);
11017 lex_state_beg_p(parser) ||
11018 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11020 lex_state_set(parser, PM_LEX_STATE_BEG);
11022 if (pm_char_is_decimal_digit(peek(parser))) {
11023 parser->current.end++;
11024 pm_token_type_t
type = lex_numeric(parser);
11025 lex_state_set(parser, PM_LEX_STATE_END);
11029 LEX(PM_TOKEN_UPLUS);
11032 if (ambiguous_operator_p(parser, space_seen)) {
11033 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11036 lex_state_set(parser, PM_LEX_STATE_BEG);
11037 LEX(PM_TOKEN_PLUS);
11042 if (lex_state_operator_p(parser)) {
11043 lex_state_set(parser, PM_LEX_STATE_ARG);
11045 if (match(parser,
'@')) {
11046 LEX(PM_TOKEN_UMINUS);
11049 LEX(PM_TOKEN_MINUS);
11052 if (match(parser,
'=')) {
11053 lex_state_set(parser, PM_LEX_STATE_BEG);
11054 LEX(PM_TOKEN_MINUS_EQUAL);
11057 if (match(parser,
'>')) {
11058 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11059 LEX(PM_TOKEN_MINUS_GREATER);
11062 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11063 bool is_beg = lex_state_beg_p(parser);
11064 if (!is_beg && spcarg) {
11065 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11068 if (is_beg || spcarg) {
11069 lex_state_set(parser, PM_LEX_STATE_BEG);
11070 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11073 if (ambiguous_operator_p(parser, space_seen)) {
11074 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11077 lex_state_set(parser, PM_LEX_STATE_BEG);
11078 LEX(PM_TOKEN_MINUS);
11083 bool beg_p = lex_state_beg_p(parser);
11085 if (match(parser,
'.')) {
11086 if (match(parser,
'.')) {
11088 if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) {
11089 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11090 lex_state_set(parser, PM_LEX_STATE_BEG);
11092 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11094 LEX(PM_TOKEN_UDOT_DOT_DOT);
11097 if (parser->enclosure_nesting == 0 && parser_end_of_line_p(parser)) {
11098 pm_parser_warn_token(parser, &parser->current, PM_WARN_DOT_DOT_DOT_EOL);
11101 lex_state_set(parser, PM_LEX_STATE_BEG);
11102 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11105 lex_state_set(parser, PM_LEX_STATE_BEG);
11106 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11109 lex_state_set(parser, PM_LEX_STATE_DOT);
11124 pm_token_type_t
type = lex_numeric(parser);
11125 lex_state_set(parser, PM_LEX_STATE_END);
11131 if (match(parser,
':')) {
11132 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)) {
11133 lex_state_set(parser, PM_LEX_STATE_BEG);
11134 LEX(PM_TOKEN_UCOLON_COLON);
11137 lex_state_set(parser, PM_LEX_STATE_DOT);
11138 LEX(PM_TOKEN_COLON_COLON);
11141 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11142 lex_state_set(parser, PM_LEX_STATE_BEG);
11143 LEX(PM_TOKEN_COLON);
11146 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11147 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->current.end);
11148 parser->current.end++;
11155 parser->explicit_encoding = NULL;
11158 lex_state_set(parser, PM_LEX_STATE_FNAME);
11159 LEX(PM_TOKEN_SYMBOL_BEGIN);
11163 if (lex_state_beg_p(parser)) {
11164 lex_mode_push_regexp(parser,
'\0',
'/');
11165 LEX(PM_TOKEN_REGEXP_BEGIN);
11168 if (match(parser,
'=')) {
11169 lex_state_set(parser, PM_LEX_STATE_BEG);
11170 LEX(PM_TOKEN_SLASH_EQUAL);
11173 if (lex_state_spcarg_p(parser, space_seen)) {
11175 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_4_0) {
11176 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
11178 lex_mode_push_regexp(parser,
'\0',
'/');
11179 LEX(PM_TOKEN_REGEXP_BEGIN);
11182 if (ambiguous_operator_p(parser, space_seen)) {
11183 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11186 if (lex_state_operator_p(parser)) {
11187 lex_state_set(parser, PM_LEX_STATE_ARG);
11189 lex_state_set(parser, PM_LEX_STATE_BEG);
11192 LEX(PM_TOKEN_SLASH);
11196 if (lex_state_operator_p(parser)) {
11197 lex_state_set(parser, PM_LEX_STATE_ARG);
11199 lex_state_set(parser, PM_LEX_STATE_BEG);
11201 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11205 if (lex_state_operator_p(parser)) {
11206 (void) match(parser,
'@');
11207 lex_state_set(parser, PM_LEX_STATE_ARG);
11209 lex_state_set(parser, PM_LEX_STATE_BEG);
11212 LEX(PM_TOKEN_TILDE);
11220 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
11221 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11222 LEX(PM_TOKEN_PERCENT);
11225 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11226 lex_state_set(parser, PM_LEX_STATE_BEG);
11227 LEX(PM_TOKEN_PERCENT_EQUAL);
11229 lex_state_beg_p(parser) ||
11230 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11231 lex_state_spcarg_p(parser, space_seen)
11233 if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) {
11234 if (*parser->current.end >= 0x80) {
11235 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11236 goto lex_next_token;
11239 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11240 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11241 LEX(PM_TOKEN_STRING_BEGIN);
11246 uint8_t delimiter = peek_offset(parser, 1);
11247 if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) {
11248 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11249 goto lex_next_token;
11252 switch (peek(parser)) {
11254 parser->current.end++;
11256 if (parser->current.end < parser->end) {
11257 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11259 lex_mode_push_list_eof(parser);
11262 LEX(PM_TOKEN_PERCENT_LOWER_I);
11265 parser->current.end++;
11267 if (parser->current.end < parser->end) {
11268 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11270 lex_mode_push_list_eof(parser);
11273 LEX(PM_TOKEN_PERCENT_UPPER_I);
11276 parser->current.end++;
11278 if (parser->current.end < parser->end) {
11279 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11280 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11282 lex_mode_push_regexp(parser,
'\0',
'\0');
11285 LEX(PM_TOKEN_REGEXP_BEGIN);
11288 parser->current.end++;
11290 if (parser->current.end < parser->end) {
11291 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11292 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11294 lex_mode_push_string_eof(parser);
11297 LEX(PM_TOKEN_STRING_BEGIN);
11300 parser->current.end++;
11302 if (parser->current.end < parser->end) {
11303 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11304 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11306 lex_mode_push_string_eof(parser);
11309 LEX(PM_TOKEN_STRING_BEGIN);
11312 parser->current.end++;
11314 if (parser->current.end < parser->end) {
11315 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11316 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11317 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11319 lex_mode_push_string_eof(parser);
11322 LEX(PM_TOKEN_SYMBOL_BEGIN);
11325 parser->current.end++;
11327 if (parser->current.end < parser->end) {
11328 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11330 lex_mode_push_list_eof(parser);
11333 LEX(PM_TOKEN_PERCENT_LOWER_W);
11336 parser->current.end++;
11338 if (parser->current.end < parser->end) {
11339 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11341 lex_mode_push_list_eof(parser);
11344 LEX(PM_TOKEN_PERCENT_UPPER_W);
11347 parser->current.end++;
11349 if (parser->current.end < parser->end) {
11350 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11351 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11353 lex_mode_push_string_eof(parser);
11356 LEX(PM_TOKEN_PERCENT_LOWER_X);
11363 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11364 goto lex_next_token;
11368 if (ambiguous_operator_p(parser, space_seen)) {
11369 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11372 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11373 LEX(PM_TOKEN_PERCENT);
11378 pm_token_type_t
type = lex_global_variable(parser);
11382 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
11383 lex_mode_pop(parser);
11386 lex_state_set(parser, PM_LEX_STATE_END);
11392 lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11393 LEX(lex_at_variable(parser));
11396 if (*parser->current.start !=
'_') {
11397 size_t width = char_is_identifier_start(parser, parser->current.start, parser->end - parser->current.start);
11404 if (*parser->current.start >= 0x80) {
11405 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
11406 }
else if (*parser->current.start ==
'\\') {
11407 switch (peek_at(parser, parser->current.start + 1)) {
11409 parser->current.end++;
11410 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11413 parser->current.end++;
11414 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11417 parser->current.end++;
11418 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11421 parser->current.end++;
11422 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11425 if (peek_at(parser, parser->current.start + 2) !=
'\n') {
11426 parser->current.end++;
11427 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11432 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11435 }
else if (char_is_ascii_printable(*parser->current.start)) {
11436 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
11438 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
11441 goto lex_next_token;
11444 parser->current.end = parser->current.start + width;
11447 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11454 ((parser->current.end - parser->current.start) == 7) &&
11455 current_token_starts_line(parser) &&
11456 (memcmp(parser->current.start,
"__END__", 7) == 0) &&
11457 (parser->current.end == parser->end || match_eol(parser))
11462 const uint8_t *cursor = parser->current.end;
11463 while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
11464 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
11467 parser->current.end = parser->end;
11468 parser->current.type = PM_TOKEN___END__;
11469 parser_lex_callback(parser);
11471 parser->data_loc.
start = PM_TOKEN_START(parser, &parser->current);
11472 parser->data_loc.
length = PM_TOKEN_LENGTH(&parser->current);
11477 pm_lex_state_t last_state = parser->lex_state;
11479 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11480 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11481 if (previous_command_start) {
11482 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11484 lex_state_set(parser, PM_LEX_STATE_ARG);
11486 }
else if (parser->lex_state == PM_LEX_STATE_FNAME) {
11487 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11489 lex_state_set(parser, PM_LEX_STATE_END);
11494 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11495 (
type == PM_TOKEN_IDENTIFIER) &&
11496 ((pm_parser_local_depth(parser, &parser->current) != -1) ||
11497 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
11499 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11506 case PM_LEX_LIST: {
11507 if (parser->next_start != NULL) {
11508 parser->current.end = parser->next_start;
11509 parser->next_start = NULL;
11513 parser->current.start = parser->current.end;
11521 if (parser->heredoc_end) {
11522 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11523 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11526 }
else if (lex_mode->as.list.terminator ==
'\n') {
11531 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11533 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));
11536 if (whitespace > 0) {
11537 parser->current.end += whitespace;
11538 if (peek_offset(parser, -1) ==
'\n') {
11540 parser_flush_heredoc_end(parser);
11543 lex_mode->as.list.started =
true;
11544 lex_mode->as.list.separated =
true;
11545 LEX(PM_TOKEN_WORDS_SEP);
11550 if (parser->current.end >= parser->end) {
11559 if (!lex_mode->as.list.started) {
11560 lex_mode->as.list.started =
true;
11561 lex_mode->as.list.separated =
true;
11562 parser->current.type = PM_TOKEN_WORDS_SEP_IMPLICIT;
11563 parser_lex_callback(parser);
11568 const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
11569 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11575 while (breakpoint != NULL) {
11580 if (pm_char_is_whitespace(*breakpoint) && *breakpoint != lex_mode->as.list.terminator) {
11581 parser->current.end = breakpoint;
11582 pm_token_buffer_flush(parser, &token_buffer);
11583 lex_mode->as.list.separated =
false;
11584 LEX(PM_TOKEN_STRING_CONTENT);
11589 if (*breakpoint == lex_mode->as.list.terminator) {
11592 if (lex_mode->as.list.nesting > 0) {
11593 parser->current.end = breakpoint + 1;
11594 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11595 lex_mode->as.list.nesting--;
11601 if (breakpoint > parser->current.start) {
11602 parser->current.end = breakpoint;
11603 pm_token_buffer_flush(parser, &token_buffer);
11604 lex_mode->as.list.separated =
false;
11605 LEX(PM_TOKEN_STRING_CONTENT);
11613 if (!lex_mode->as.list.separated) {
11614 lex_mode->as.list.separated =
true;
11615 parser->current.end = breakpoint;
11616 parser->current.type = PM_TOKEN_WORDS_SEP_IMPLICIT;
11617 parser_lex_callback(parser);
11622 parser->current.end = breakpoint + 1;
11627 if (*breakpoint ==
'\n') {
11628 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11631 lex_mode_pop(parser);
11632 lex_state_set(parser, PM_LEX_STATE_END);
11633 LEX(PM_TOKEN_STRING_END);
11637 if (*breakpoint ==
'\0') {
11638 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1),
true);
11645 if (*breakpoint ==
'\\') {
11646 parser->current.end = breakpoint + 1;
11650 if (parser->current.end == parser->end) {
11655 pm_token_buffer_escape(parser, &token_buffer);
11656 uint8_t peeked = peek(parser);
11664 pm_token_buffer_push_byte(&token_buffer, peeked);
11665 parser->current.end++;
11668 parser->current.end++;
11669 if (peek(parser) !=
'\n') {
11670 pm_token_buffer_push_byte(&token_buffer,
'\r');
11675 pm_token_buffer_push_byte(&token_buffer,
'\n');
11677 if (parser->heredoc_end) {
11681 parser_flush_heredoc_end(parser);
11682 pm_token_buffer_copy(parser, &token_buffer);
11683 LEX(PM_TOKEN_STRING_CONTENT);
11686 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11689 parser->current.end++;
11692 if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
11693 pm_token_buffer_push_byte(&token_buffer, peeked);
11694 parser->current.end++;
11695 }
else if (lex_mode->as.list.interpolation) {
11696 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11698 pm_token_buffer_push_byte(&token_buffer,
'\\');
11699 pm_token_buffer_push_escaped(&token_buffer, parser);
11705 token_buffer.
cursor = parser->current.end;
11706 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11711 if (*breakpoint ==
'#') {
11712 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11719 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11723 if (
type == PM_TOKEN_STRING_CONTENT) {
11724 pm_token_buffer_flush(parser, &token_buffer);
11727 lex_mode->as.list.separated =
false;
11733 assert(*breakpoint == lex_mode->as.list.incrementor);
11734 parser->current.end = breakpoint + 1;
11735 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11736 lex_mode->as.list.nesting++;
11740 if (parser->current.end > parser->current.start) {
11741 pm_token_buffer_flush(parser, &token_buffer);
11742 LEX(PM_TOKEN_STRING_CONTENT);
11747 parser->current.end = parser->end;
11748 pm_token_buffer_flush(parser, &token_buffer);
11749 LEX(PM_TOKEN_STRING_CONTENT);
11751 case PM_LEX_REGEXP: {
11753 if (parser->next_start == NULL) {
11754 parser->current.start = parser->current.end;
11756 parser->current.start = parser->next_start;
11757 parser->current.end = parser->next_start;
11758 parser->next_start = NULL;
11763 if (parser->current.end >= parser->end) {
11773 const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
11774 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11777 while (breakpoint != NULL) {
11778 uint8_t term = lex_mode->as.regexp.terminator;
11779 bool is_terminator = (*breakpoint == term);
11784 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11785 if (term ==
'\n') {
11786 is_terminator =
true;
11792 if (term ==
'\r') {
11793 is_terminator =
false;
11799 if (is_terminator) {
11800 if (lex_mode->as.regexp.nesting > 0) {
11801 parser->current.end = breakpoint + 1;
11802 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11803 lex_mode->as.regexp.nesting--;
11810 if (breakpoint > parser->current.start) {
11811 parser->current.end = breakpoint;
11812 pm_regexp_token_buffer_flush(parser, &token_buffer);
11813 LEX(PM_TOKEN_STRING_CONTENT);
11817 size_t eol_length = match_eol_at(parser, breakpoint);
11819 parser->current.end = breakpoint + eol_length;
11824 if (parser->heredoc_end == NULL) {
11825 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11828 parser->current.end = breakpoint + 1;
11833 parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
11835 lex_mode_pop(parser);
11836 lex_state_set(parser, PM_LEX_STATE_END);
11837 LEX(PM_TOKEN_REGEXP_END);
11842 if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
11843 parser->current.end = breakpoint + 1;
11844 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11845 lex_mode->as.regexp.nesting++;
11849 switch (*breakpoint) {
11852 parser->current.end = breakpoint + 1;
11853 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11856 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11857 parser->current.end = breakpoint + 1;
11858 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11863 parser->current.end = breakpoint;
11864 pm_regexp_token_buffer_escape(parser, &token_buffer);
11871 if (parser->heredoc_end == NULL) {
11872 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
11873 parser->current.end = breakpoint + 1;
11874 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11878 parser->current.end = breakpoint + 1;
11879 parser_flush_heredoc_end(parser);
11880 pm_regexp_token_buffer_flush(parser, &token_buffer);
11881 LEX(PM_TOKEN_STRING_CONTENT);
11886 parser->current.end = breakpoint + 1;
11890 if (parser->current.end == parser->end) {
11895 pm_regexp_token_buffer_escape(parser, &token_buffer);
11896 uint8_t peeked = peek(parser);
11900 parser->current.end++;
11901 if (peek(parser) !=
'\n') {
11902 if (lex_mode->as.regexp.terminator !=
'\r') {
11903 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11905 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11906 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11911 if (parser->heredoc_end) {
11915 parser_flush_heredoc_end(parser);
11916 pm_regexp_token_buffer_copy(parser, &token_buffer);
11917 LEX(PM_TOKEN_STRING_CONTENT);
11920 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11923 parser->current.end++;
11933 if (lex_mode->as.regexp.terminator == peeked) {
11938 case '$':
case ')':
case '*':
case '+':
11939 case '.':
case '>':
case '?':
case ']':
11940 case '^':
case '|':
case '}':
11941 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11947 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11948 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11949 parser->current.end++;
11953 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11954 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11958 token_buffer.
base.
cursor = parser->current.end;
11959 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11965 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11972 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11976 if (
type == PM_TOKEN_STRING_CONTENT) {
11977 pm_regexp_token_buffer_flush(parser, &token_buffer);
11983 assert(
false &&
"unreachable");
11988 if (parser->current.end > parser->current.start) {
11989 pm_regexp_token_buffer_flush(parser, &token_buffer);
11990 LEX(PM_TOKEN_STRING_CONTENT);
11995 parser->current.end = parser->end;
11996 pm_regexp_token_buffer_flush(parser, &token_buffer);
11997 LEX(PM_TOKEN_STRING_CONTENT);
11999 case PM_LEX_STRING: {
12001 if (parser->next_start == NULL) {
12002 parser->current.start = parser->current.end;
12004 parser->current.start = parser->next_start;
12005 parser->current.end = parser->next_start;
12006 parser->next_start = NULL;
12011 if (parser->current.end >= parser->end) {
12018 const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
12019 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12025 while (breakpoint != NULL) {
12028 if (lex_mode->as.string.incrementor !=
'\0' && *breakpoint == lex_mode->as.string.incrementor) {
12029 lex_mode->as.string.nesting++;
12030 parser->current.end = breakpoint + 1;
12031 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12035 uint8_t term = lex_mode->as.string.terminator;
12036 bool is_terminator = (*breakpoint == term);
12041 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12042 if (term ==
'\n') {
12043 is_terminator =
true;
12049 if (term ==
'\r') {
12050 is_terminator =
false;
12057 if (is_terminator) {
12060 if (lex_mode->as.string.nesting > 0) {
12061 parser->current.end = breakpoint + 1;
12062 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12063 lex_mode->as.string.nesting--;
12069 if (breakpoint > parser->current.start) {
12070 parser->current.end = breakpoint;
12071 pm_token_buffer_flush(parser, &token_buffer);
12072 LEX(PM_TOKEN_STRING_CONTENT);
12077 size_t eol_length = match_eol_at(parser, breakpoint);
12079 parser->current.end = breakpoint + eol_length;
12084 if (parser->heredoc_end == NULL) {
12085 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
12088 parser->current.end = breakpoint + 1;
12091 if (lex_mode->as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12092 parser->current.end++;
12093 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12094 lex_mode_pop(parser);
12095 LEX(PM_TOKEN_LABEL_END);
12101 if (term ==
'\n' && parser->heredoc_end) {
12102 parser_flush_heredoc_end(parser);
12105 lex_state_set(parser, PM_LEX_STATE_END);
12106 lex_mode_pop(parser);
12107 LEX(PM_TOKEN_STRING_END);
12110 switch (*breakpoint) {
12113 parser->current.end = breakpoint + 1;
12114 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12117 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12118 parser->current.end = breakpoint + 1;
12119 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12126 parser->current.end = breakpoint;
12127 pm_token_buffer_escape(parser, &token_buffer);
12128 token_buffer.
cursor = breakpoint;
12136 if (parser->heredoc_end == NULL) {
12137 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12138 parser->current.end = breakpoint + 1;
12139 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12143 parser->current.end = breakpoint + 1;
12144 parser_flush_heredoc_end(parser);
12145 pm_token_buffer_flush(parser, &token_buffer);
12146 LEX(PM_TOKEN_STRING_CONTENT);
12149 parser->current.end = breakpoint + 1;
12153 if (parser->current.end == parser->end) {
12158 pm_token_buffer_escape(parser, &token_buffer);
12159 uint8_t peeked = peek(parser);
12163 pm_token_buffer_push_byte(&token_buffer,
'\\');
12164 parser->current.end++;
12167 parser->current.end++;
12168 if (peek(parser) !=
'\n') {
12169 if (!lex_mode->as.string.interpolation) {
12170 pm_token_buffer_push_byte(&token_buffer,
'\\');
12172 pm_token_buffer_push_byte(&token_buffer,
'\r');
12177 if (!lex_mode->as.string.interpolation) {
12178 pm_token_buffer_push_byte(&token_buffer,
'\\');
12179 pm_token_buffer_push_byte(&token_buffer,
'\n');
12182 if (parser->heredoc_end) {
12186 parser_flush_heredoc_end(parser);
12187 pm_token_buffer_copy(parser, &token_buffer);
12188 LEX(PM_TOKEN_STRING_CONTENT);
12191 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
12194 parser->current.end++;
12197 if (lex_mode->as.string.incrementor !=
'\0' && peeked == lex_mode->as.string.incrementor) {
12198 pm_token_buffer_push_byte(&token_buffer, peeked);
12199 parser->current.end++;
12200 }
else if (lex_mode->as.string.terminator !=
'\0' && peeked == lex_mode->as.string.terminator) {
12201 pm_token_buffer_push_byte(&token_buffer, peeked);
12202 parser->current.end++;
12203 }
else if (lex_mode->as.string.interpolation) {
12204 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12206 pm_token_buffer_push_byte(&token_buffer,
'\\');
12207 pm_token_buffer_push_escaped(&token_buffer, parser);
12213 token_buffer.
cursor = parser->current.end;
12214 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12218 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12225 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12229 if (
type == PM_TOKEN_STRING_CONTENT) {
12230 pm_token_buffer_flush(parser, &token_buffer);
12236 assert(
false &&
"unreachable");
12240 if (parser->current.end > parser->current.start) {
12241 pm_token_buffer_flush(parser, &token_buffer);
12242 LEX(PM_TOKEN_STRING_CONTENT);
12247 parser->current.end = parser->end;
12248 pm_token_buffer_flush(parser, &token_buffer);
12249 LEX(PM_TOKEN_STRING_CONTENT);
12251 case PM_LEX_HEREDOC: {
12253 if (parser->next_start == NULL) {
12254 parser->current.start = parser->current.end;
12256 parser->current.start = parser->next_start;
12257 parser->current.end = parser->next_start;
12258 parser->heredoc_end = NULL;
12259 parser->next_start = NULL;
12267 bool line_continuation = lex_mode->as.heredoc.line_continuation;
12268 lex_mode->as.heredoc.line_continuation =
false;
12274 if (parser->current.end >= parser->end) {
12275 pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
12276 parser->next_start = lex_mode->as.heredoc.next_start;
12277 parser->heredoc_end = parser->current.end;
12278 lex_state_set(parser, PM_LEX_STATE_END);
12279 lex_mode_pop(parser);
12280 LEX(PM_TOKEN_HEREDOC_END);
12283 const uint8_t *ident_start = heredoc_lex_mode->ident_start;
12284 size_t ident_length = heredoc_lex_mode->ident_length;
12288 if (current_token_starts_line(parser)) {
12289 const uint8_t *start = parser->current.start;
12291 if (!line_continuation && (start + ident_length <= parser->end)) {
12292 const uint8_t *newline = next_newline(start, parser->end - start);
12293 const uint8_t *ident_end = newline;
12294 const uint8_t *terminator_end = newline;
12296 if (newline == NULL) {
12297 terminator_end = parser->end;
12298 ident_end = parser->end;
12301 if (newline[-1] ==
'\r') {
12313 if ((
size_t) (ident_end - start) >= ident_length) {
12314 const uint8_t *terminator_start = ident_end - ident_length;
12315 const uint8_t *cursor = start;
12317 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12318 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12324 (cursor == terminator_start) &&
12325 (memcmp(terminator_start, ident_start, ident_length) == 0)
12327 if (newline != NULL) {
12328 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
12331 parser->current.end = terminator_end;
12332 if (*lex_mode->as.heredoc.next_start ==
'\\') {
12333 parser->next_start = NULL;
12335 parser->next_start = lex_mode->as.heredoc.next_start;
12336 parser->heredoc_end = parser->current.end;
12339 lex_state_set(parser, PM_LEX_STATE_END);
12340 lex_mode_pop(parser);
12341 LEX(PM_TOKEN_HEREDOC_END);
12346 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
12348 heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
12349 lex_mode->as.heredoc.common_whitespace != NULL &&
12350 (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
12351 peek_at(parser, start) !=
'\n'
12353 *lex_mode->as.heredoc.common_whitespace = whitespace;
12360 uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] =
"\r\n\\#";
12362 pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
12363 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12364 breakpoints[3] =
'\0';
12367 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12369 bool was_line_continuation =
false;
12371 while (breakpoint != NULL) {
12372 switch (*breakpoint) {
12375 parser->current.end = breakpoint + 1;
12376 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12379 parser->current.end = breakpoint + 1;
12381 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12382 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12389 pm_token_buffer_escape(parser, &token_buffer);
12390 token_buffer.
cursor = breakpoint;
12394 if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
12395 parser_flush_heredoc_end(parser);
12396 parser->current.end = breakpoint + 1;
12397 pm_token_buffer_flush(parser, &token_buffer);
12398 LEX(PM_TOKEN_STRING_CONTENT);
12401 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12405 const uint8_t *start = breakpoint + 1;
12407 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12410 const uint8_t *newline = next_newline(start, parser->end - start);
12412 if (newline == NULL) {
12413 newline = parser->end;
12414 }
else if (newline[-1] ==
'\r') {
12426 if ((
size_t) (newline - start) >= ident_length) {
12428 const uint8_t *terminator_start = newline - ident_length;
12432 const uint8_t *cursor = start;
12434 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12435 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12441 cursor == terminator_start &&
12442 (memcmp(terminator_start, ident_start, ident_length) == 0)
12444 parser->current.end = breakpoint + 1;
12445 pm_token_buffer_flush(parser, &token_buffer);
12446 LEX(PM_TOKEN_STRING_CONTENT);
12451 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
12458 if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12459 if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12460 *lex_mode->as.heredoc.common_whitespace = whitespace;
12463 parser->current.end = breakpoint + 1;
12464 pm_token_buffer_flush(parser, &token_buffer);
12465 LEX(PM_TOKEN_STRING_CONTENT);
12470 parser->current.end = breakpoint + 1;
12471 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12481 parser->current.end = breakpoint + 1;
12485 if (parser->current.end == parser->end) {
12490 pm_token_buffer_escape(parser, &token_buffer);
12491 uint8_t peeked = peek(parser);
12493 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12496 parser->current.end++;
12497 if (peek(parser) !=
'\n') {
12498 pm_token_buffer_push_byte(&token_buffer,
'\\');
12499 pm_token_buffer_push_byte(&token_buffer,
'\r');
12504 pm_token_buffer_push_byte(&token_buffer,
'\\');
12505 pm_token_buffer_push_byte(&token_buffer,
'\n');
12506 token_buffer.
cursor = parser->current.end + 1;
12507 breakpoint = parser->current.end;
12510 pm_token_buffer_push_byte(&token_buffer,
'\\');
12511 pm_token_buffer_push_escaped(&token_buffer, parser);
12517 parser->current.end++;
12518 if (peek(parser) !=
'\n') {
12519 pm_token_buffer_push_byte(&token_buffer,
'\r');
12527 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12528 const uint8_t *end = parser->current.end;
12530 if (parser->heredoc_end == NULL) {
12531 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
12536 parser->current.end = breakpoint;
12537 pm_token_buffer_flush(parser, &token_buffer);
12541 parser->current.end = end + 1;
12542 lex_mode->as.heredoc.line_continuation =
true;
12543 LEX(PM_TOKEN_STRING_CONTENT);
12546 was_line_continuation =
true;
12547 token_buffer.
cursor = parser->current.end + 1;
12548 breakpoint = parser->current.end;
12551 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12556 token_buffer.
cursor = parser->current.end;
12557 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12561 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12569 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12573 if (
type == PM_TOKEN_STRING_CONTENT) {
12574 pm_token_buffer_flush(parser, &token_buffer);
12580 assert(
false &&
"unreachable");
12583 was_line_continuation =
false;
12586 if (parser->current.end > parser->current.start) {
12587 parser->current.end = parser->end;
12588 pm_token_buffer_flush(parser, &token_buffer);
12589 LEX(PM_TOKEN_STRING_CONTENT);
12594 parser->current.end = parser->end;
12595 pm_token_buffer_flush(parser, &token_buffer);
12596 LEX(PM_TOKEN_STRING_CONTENT);
12600 assert(
false &&
"unreachable");
12618 PM_BINDING_POWER_UNSET = 0,
12619 PM_BINDING_POWER_STATEMENT = 2,
12620 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12621 PM_BINDING_POWER_MODIFIER = 6,
12622 PM_BINDING_POWER_COMPOSITION = 8,
12623 PM_BINDING_POWER_NOT = 10,
12624 PM_BINDING_POWER_MATCH = 12,
12625 PM_BINDING_POWER_DEFINED = 14,
12626 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12627 PM_BINDING_POWER_ASSIGNMENT = 18,
12628 PM_BINDING_POWER_TERNARY = 20,
12629 PM_BINDING_POWER_RANGE = 22,
12630 PM_BINDING_POWER_LOGICAL_OR = 24,
12631 PM_BINDING_POWER_LOGICAL_AND = 26,
12632 PM_BINDING_POWER_EQUALITY = 28,
12633 PM_BINDING_POWER_COMPARISON = 30,
12634 PM_BINDING_POWER_BITWISE_OR = 32,
12635 PM_BINDING_POWER_BITWISE_AND = 34,
12636 PM_BINDING_POWER_SHIFT = 36,
12637 PM_BINDING_POWER_TERM = 38,
12638 PM_BINDING_POWER_FACTOR = 40,
12639 PM_BINDING_POWER_UMINUS = 42,
12640 PM_BINDING_POWER_EXPONENT = 44,
12641 PM_BINDING_POWER_UNARY = 46,
12642 PM_BINDING_POWER_INDEX = 48,
12643 PM_BINDING_POWER_CALL = 50,
12644 PM_BINDING_POWER_MAX = 52
12645} pm_binding_power_t;
12668#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12669#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12670#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12671#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12672#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12676 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12679 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12680 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12681 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12682 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12685 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12686 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12689 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12690 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12693 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12694 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12695 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12696 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12697 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12698 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12699 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12700 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12701 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12702 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12703 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12704 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12705 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12706 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12709 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12712 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12713 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12714 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12715 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12718 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12721 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12724 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12725 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12726 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12727 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12728 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12729 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12732 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12733 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12734 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12735 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12738 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12739 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12742 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12745 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12746 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12749 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12750 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12753 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12754 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12755 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12756 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12759 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12760 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12763 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12764 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12767 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12768 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12769 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12772 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12775 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12776 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12777 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12780#undef BINDING_POWER_ASSIGNMENT
12781#undef LEFT_ASSOCIATIVE
12782#undef RIGHT_ASSOCIATIVE
12783#undef RIGHT_ASSOCIATIVE_UNARY
12790 return parser->current.type ==
type;
12797match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12798 return match1(parser, type1) || match1(parser, type2);
12805match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12806 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12813match4(
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) {
12814 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12821match5(
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) {
12822 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5);
12829match6(
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) {
12830 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
12837match8(
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) {
12838 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);
12849 if (match1(parser,
type)) {
12850 parser_lex(parser);
12861accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12862 if (match2(parser, type1, type2)) {
12863 parser_lex(parser);
12881expect1(
pm_parser_t *parser, pm_token_type_t
type, pm_diagnostic_id_t diag_id) {
12882 if (accept1(parser,
type))
return;
12884 const uint8_t *location = parser->previous.
end;
12885 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12887 parser->previous.
start = location;
12888 parser->previous.
type = 0;
12896expect2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
12897 if (accept2(parser, type1, type2))
return;
12899 const uint8_t *location = parser->previous.
end;
12900 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12902 parser->previous.
start = location;
12903 parser->previous.
type = 0;
12911expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12912 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12913 parser_lex(parser);
12915 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12916 parser->previous.
start = parser->previous.
end;
12917 parser->previous.
type = 0;
12929 if (accept1(parser,
type))
return;
12931 const uint8_t *start = opening->
start;
12932 pm_parser_err(parser, U32(start - parser->start), U32(opening->
end - start), diag_id);
12934 parser->previous.
start = parser->previous.
end;
12935 parser->previous.
type = 0;
12939#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
12940#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
12941#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
12942#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
12953#define PM_PARSE_ACCEPTS_STATEMENT ((uint8_t) 0x10)
12956parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
12963parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
12964 pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
12965 pm_assert_value_expression(parser, node);
12988token_begins_expression_p(pm_token_type_t
type) {
12990 case PM_TOKEN_EQUAL_GREATER:
12991 case PM_TOKEN_KEYWORD_IN:
12995 case PM_TOKEN_BRACE_RIGHT:
12996 case PM_TOKEN_BRACKET_RIGHT:
12997 case PM_TOKEN_COLON:
12998 case PM_TOKEN_COMMA:
12999 case PM_TOKEN_EMBEXPR_END:
13001 case PM_TOKEN_LAMBDA_BEGIN:
13002 case PM_TOKEN_KEYWORD_DO:
13003 case PM_TOKEN_KEYWORD_DO_BLOCK:
13004 case PM_TOKEN_KEYWORD_DO_LAMBDA:
13005 case PM_TOKEN_KEYWORD_DO_LOOP:
13006 case PM_TOKEN_KEYWORD_END:
13007 case PM_TOKEN_KEYWORD_ELSE:
13008 case PM_TOKEN_KEYWORD_ELSIF:
13009 case PM_TOKEN_KEYWORD_ENSURE:
13010 case PM_TOKEN_KEYWORD_THEN:
13011 case PM_TOKEN_KEYWORD_RESCUE:
13012 case PM_TOKEN_KEYWORD_WHEN:
13013 case PM_TOKEN_NEWLINE:
13014 case PM_TOKEN_PARENTHESIS_RIGHT:
13015 case PM_TOKEN_SEMICOLON:
13021 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13023 case PM_TOKEN_UAMPERSAND:
13027 case PM_TOKEN_UCOLON_COLON:
13028 case PM_TOKEN_UMINUS:
13029 case PM_TOKEN_UMINUS_NUM:
13030 case PM_TOKEN_UPLUS:
13031 case PM_TOKEN_BANG:
13032 case PM_TOKEN_TILDE:
13033 case PM_TOKEN_UDOT_DOT:
13034 case PM_TOKEN_UDOT_DOT_DOT:
13041 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13061token_begins_pattern_p(pm_token_type_t
type) {
13063 token_begins_expression_p(
type) ||
13064 type == PM_TOKEN_USTAR ||
13065 type == PM_TOKEN_USTAR_STAR ||
13066 type == PM_TOKEN_CARET
13075parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
13076 if (accept1(parser, PM_TOKEN_USTAR)) {
13078 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));
13079 return UP(pm_splat_node_create(parser, &
operator, expression));
13082 return parse_value_expression(parser, binding_power, flags, diag_id, depth);
13086pm_node_unreference_each(
const pm_node_t *node,
void *data) {
13087 switch (PM_NODE_TYPE(node)) {
13092 case PM_BREAK_NODE:
13094 case PM_REDO_NODE: {
13098 while (index < parser->current_block_exits->size) {
13099 pm_node_t *block_exit = parser->current_block_exits->
nodes[index];
13101 if (block_exit == node) {
13102 if (index + 1 < parser->current_block_exits->
size) {
13104 &parser->current_block_exits->
nodes[index],
13105 &parser->current_block_exits->
nodes[index + 1],
13106 (parser->current_block_exits->
size - index - 1) *
sizeof(
pm_node_t *)
13109 parser->current_block_exits->
size--;
13124 case PM_LOCAL_VARIABLE_READ_NODE:
13125 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13127 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
13129 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13130 if (implicit_parameters->
nodes[index] == node) {
13134 if (index != implicit_parameters->
size - 1) {
13135 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13138 implicit_parameters->
size--;
13157 pm_visit_node(node, pm_node_unreference_each, parser);
13170 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *name_field);
13171 size_t length = constant->length;
13172 uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
13174 memcpy(name, constant->start, length);
13175 name[length] =
'=';
13177 *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
13188 switch (PM_NODE_TYPE(target)) {
13189 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13190 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13191 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13192 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13193 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13194 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13195 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13199 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
13215 switch (PM_NODE_TYPE(target)) {
13216 case PM_ERROR_RECOVERY_NODE:
13218 case PM_SOURCE_ENCODING_NODE:
13219 case PM_FALSE_NODE:
13220 case PM_SOURCE_FILE_NODE:
13221 case PM_SOURCE_LINE_NODE:
13224 case PM_TRUE_NODE: {
13227 return parse_unwriteable_target(parser, target);
13229 case PM_CLASS_VARIABLE_READ_NODE:
13231 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13233 case PM_CONSTANT_PATH_NODE:
13234 if (context_def_p(parser)) {
13235 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13239 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13242 case PM_CONSTANT_READ_NODE:
13243 if (context_def_p(parser)) {
13244 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13248 target->
type = PM_CONSTANT_TARGET_NODE;
13251 case PM_BACK_REFERENCE_READ_NODE:
13252 case PM_NUMBERED_REFERENCE_READ_NODE:
13253 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13254 return UP(pm_error_recovery_node_create_unexpected(parser, target));
13255 case PM_GLOBAL_VARIABLE_READ_NODE:
13257 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13259 case PM_LOCAL_VARIABLE_READ_NODE: {
13260 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13261 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
13262 pm_node_unreference(parser, target);
13266 uint32_t name = cast->
name;
13267 uint32_t depth = cast->
depth;
13268 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13271 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13275 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13277 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
13279 pm_node_unreference(parser, target);
13283 case PM_INSTANCE_VARIABLE_READ_NODE:
13285 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13287 case PM_MULTI_TARGET_NODE:
13288 if (splat_parent) {
13291 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13295 case PM_SPLAT_NODE: {
13304 case PM_CALL_NODE: {
13316 (call->
block == NULL)
13329 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
13331 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
13335 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13336 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13339 parse_write_name(parser, &call->
name);
13340 return UP(pm_call_target_node_create(parser, call));
13347 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13348 return UP(pm_index_target_node_create(parser, call));
13356 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13367 pm_node_t *result = parse_target(parser, target, multiple,
false);
13372 !match1(parser, PM_TOKEN_EQUAL) &&
13373 !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
13374 !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13376 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13388 pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
13390 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13391 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
13402 switch (PM_NODE_TYPE(target)) {
13403 case PM_ERROR_RECOVERY_NODE:
13405 case PM_CLASS_VARIABLE_READ_NODE: {
13409 case PM_CONSTANT_PATH_NODE: {
13412 if (context_def_p(parser)) {
13413 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13416 return parse_shareable_constant_write(parser, node);
13418 case PM_CONSTANT_READ_NODE: {
13421 if (context_def_p(parser)) {
13422 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13425 return parse_shareable_constant_write(parser, node);
13427 case PM_BACK_REFERENCE_READ_NODE:
13428 case PM_NUMBERED_REFERENCE_READ_NODE:
13429 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13431 case PM_GLOBAL_VARIABLE_READ_NODE: {
13435 case PM_LOCAL_VARIABLE_READ_NODE: {
13440 uint32_t depth = local_read->
depth;
13441 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13443 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13444 pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13445 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
13446 pm_node_unreference(parser, target);
13449 pm_locals_unread(&scope->locals, name);
13451 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
13453 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13455 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
13457 pm_node_unreference(parser, target);
13461 case PM_INSTANCE_VARIABLE_READ_NODE: {
13465 case PM_MULTI_TARGET_NODE:
13467 case PM_SPLAT_NODE: {
13475 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
13477 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
13479 case PM_CALL_NODE: {
13491 (call->
block == NULL)
13505 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
13506 pm_parser_local_add_location(parser, &message_loc, 0);
13508 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));
13509 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
13528 pm_arguments_node_arguments_append(parser->arena, arguments, value);
13529 PM_NODE_LENGTH_SET_NODE(call, arguments);
13530 call->
equal_loc = TOK2LOC(parser,
operator);
13532 parse_write_name(parser, &call->
name);
13533 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13542 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13544 call->
arguments = pm_arguments_node_create(parser);
13547 pm_arguments_node_arguments_append(parser->arena, call->
arguments, value);
13548 PM_NODE_LENGTH_SET_NODE(target, value);
13551 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13552 call->
equal_loc = TOK2LOC(parser,
operator);
13556 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13571 pm_node_unreference(parser, value);
13578 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13591 switch (PM_NODE_TYPE(target)) {
13592 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13593 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13594 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13595 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13596 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13597 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13598 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13619parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13620 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13623 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13625 while (accept1(parser, PM_TOKEN_COMMA)) {
13626 if (accept1(parser, PM_TOKEN_USTAR)) {
13631 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13634 pm_token_t star_operator = parser->previous;
13637 if (token_begins_expression_p(parser->current.type)) {
13638 name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13639 name = parse_target(parser, name,
true,
true);
13642 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13643 pm_multi_target_node_targets_append(parser, result, splat);
13645 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
13646 context_push(parser, PM_CONTEXT_MULTI_TARGET);
13647 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13648 target = parse_target(parser, target,
true,
false);
13650 pm_multi_target_node_targets_append(parser, result, target);
13651 context_pop(parser);
13652 }
else if (token_begins_expression_p(parser->current.type)) {
13653 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13654 target = parse_target(parser, target,
true,
false);
13656 pm_multi_target_node_targets_append(parser, result, target);
13657 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13660 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
13661 pm_multi_target_node_targets_append(parser, result, rest);
13674parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13675 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13680 if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
13681 accept1(parser, PM_TOKEN_NEWLINE);
13685 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13686 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13696parse_statements(
pm_parser_t *parser, pm_context_t context, uint16_t depth) {
13699 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13702 if (context_terminator(context, &parser->current))
return NULL;
13708 context_push(parser, context);
13711 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));
13712 pm_statements_node_body_append(parser, statements, node,
true);
13716 if (parser->recovering) {
13719 if (context_terminator(context, &parser->current)) parser->recovering =
false;
13725 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13728 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13729 if (context_terminator(context, &parser->current))
break;
13739 if (context_terminator(context, &parser->current))
break;
13751 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
13752 parser_lex(parser);
13758 if (match1(parser, PM_TOKEN_EOF)) {
13759 parser->recovering =
true;
13763 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13764 if (context_terminator(context, &parser->current))
break;
13765 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13769 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
13770 parser->previous.
start = parser->previous.
end;
13771 parser->previous.
type = 0;
13775 context_pop(parser);
13777 bool last_value =
true;
13779 case PM_CONTEXT_BEGIN_ENSURE:
13780 case PM_CONTEXT_DEF_ENSURE:
13781 last_value =
false;
13786 pm_void_statements_check(parser, statements, last_value);
13797 pm_static_literal_inspect(&buffer, &parser->line_offsets, parser->start, parser->start_line, parser->encoding, duplicated);
13799 pm_diagnostic_list_append_format(
13800 &parser->metadata_arena,
13801 &parser->warning_list,
13804 PM_WARN_DUPLICATED_HASH_KEY,
13805 (
int) pm_buffer_length(&buffer),
13806 pm_buffer_value(&buffer),
13807 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line
13810 pm_buffer_cleanup(&buffer);
13819 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
true);
13821 if (duplicated != NULL) {
13822 pm_hash_key_duplicated_warn(parser, duplicated, node);
13837 for (
size_t index = 0; index < elements->
size; index++) {
13840 switch (PM_NODE_TYPE(element)) {
13841 case PM_ASSOC_NODE: {
13843 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, key,
true);
13845 if (duplicated != NULL && PM_NODE_START(duplicated) < boundary) {
13846 pm_hash_key_duplicated_warn(parser, duplicated, key);
13851 case PM_ASSOC_SPLAT_NODE: {
13854 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13855 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, boundary);
13874 if ((previous = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
false)) != NULL) {
13875 pm_diagnostic_list_append_format(
13876 &parser->metadata_arena,
13877 &parser->warning_list,
13878 PM_NODE_START(node),
13879 PM_NODE_LENGTH(node),
13880 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13881 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line,
13882 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).
line
13892 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13893 bool contains_keyword_splat =
false;
13898 switch (parser->current.type) {
13899 case PM_TOKEN_USTAR_STAR: {
13900 parser_lex(parser);
13904 if (token_begins_expression_p(parser->current.type)) {
13905 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));
13909 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13910 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, PM_NODE_START(value));
13913 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13916 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13917 contains_keyword_splat =
true;
13920 case PM_TOKEN_LABEL: {
13922 parser_lex(parser);
13924 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13925 pm_hash_key_static_literals_add(parser, literals, key);
13929 if (token_begins_expression_p(parser->current.type)) {
13930 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13932 if (parser->encoding->isupper_char(label.
start, (label.
end - 1) - label.
start)) {
13933 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13934 value = UP(pm_constant_read_node_create(parser, &constant));
13939 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13940 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13942 depth = pm_parser_local_depth(parser, &identifier);
13946 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13948 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13953 value = UP(pm_implicit_node_create(parser, value));
13956 element = UP(pm_assoc_node_create(parser, key, NULL, value));
13960 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));
13964 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13965 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13968 pm_hash_key_static_literals_add(parser, literals, key);
13971 if (!pm_symbol_node_label_p(parser, key)) {
13972 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13973 operator = parser->previous;
13976 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));
13977 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
13982 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13983 pm_hash_node_elements_append(parser->arena, (
pm_hash_node_t *) node, element);
13989 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13993 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13997 if (token_begins_expression_p(parser->current.type))
continue;
14003 return contains_keyword_splat;
14008 if (pm_symbol_node_label_p(parser, argument)) {
14012 switch (PM_NODE_TYPE(argument)) {
14013 case PM_CALL_NODE: {
14016 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
14019 if (cast->
block != NULL) {
14027 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
14036 arguments->
arguments = pm_arguments_node_create(parser);
14039 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, argument);
14050 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
14069 call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE) &&
14084 switch (PM_NODE_TYPE(node)) {
14085 case PM_CALL_NODE: {
14090 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)) {
14095 if (pm_constant_path_command_call_p(parser, call)) {
14102 return pm_command_call_value_p(parser, call->
receiver);
14107 case PM_SUPER_NODE: {
14114 !(cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE));
14116 case PM_YIELD_NODE: {
14120 case PM_RESCUE_MODIFIER_NODE:
14122 case PM_DEF_NODE: {
14126 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
14129 return pm_command_call_value_p(parser, body);
14145pm_block_call_p(
const pm_node_t *node) {
14146 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
14177 if (PM_NODE_TYPE_P(node, PM_SUPER_NODE)) {
14189parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
14190 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
14195 match2(parser, terminator, PM_TOKEN_EOF) ||
14196 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14197 context_terminator(parser->current_context->context, &parser->current)
14202 bool parsed_first_argument =
false;
14203 bool parsed_bare_hash =
false;
14204 bool parsed_block_argument =
false;
14205 bool parsed_forwarding_arguments =
false;
14207 while (!match1(parser, PM_TOKEN_EOF)) {
14208 if (parsed_forwarding_arguments) {
14209 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14214 switch (parser->current.type) {
14215 case PM_TOKEN_USTAR_STAR:
14216 case PM_TOKEN_LABEL: {
14217 if (parsed_bare_hash) {
14218 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14222 argument = UP(hash);
14225 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
14227 parse_arguments_append(parser, arguments, argument);
14229 pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14230 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14231 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14233 pm_static_literals_free(&hash_keys);
14234 parsed_bare_hash =
true;
14238 case PM_TOKEN_UAMPERSAND: {
14239 parser_lex(parser);
14243 if (token_begins_expression_p(parser->current.type)) {
14244 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14246 pm_parser_scope_forwarding_block_check(parser, &
operator);
14249 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
14250 if (parsed_block_argument) {
14251 parse_arguments_append(parser, arguments, argument);
14253 arguments->
block = argument;
14256 if (match1(parser, PM_TOKEN_COMMA)) {
14257 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14260 parsed_block_argument =
true;
14263 case PM_TOKEN_USTAR: {
14264 parser_lex(parser);
14267 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14268 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14269 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
14270 if (parsed_bare_hash) {
14271 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14274 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));
14276 if (parsed_bare_hash) {
14277 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);
14280 argument = UP(pm_splat_node_create(parser, &
operator, expression));
14283 parse_arguments_append(parser, arguments, argument);
14286 case PM_TOKEN_UDOT_DOT_DOT: {
14287 if (accepts_forwarding) {
14288 parser_lex(parser);
14290 if (token_begins_expression_p(parser->current.type)) {
14295 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));
14300 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14302 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14305 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
14307 pm_parser_scope_forwarding_all_check(parser, &parser->previous);
14308 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14309 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14312 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->previous));
14313 parse_arguments_append(parser, arguments, argument);
14314 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14316 parsed_forwarding_arguments =
true;
14323 if (argument == NULL) {
14324 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));
14327 bool contains_keywords =
false;
14328 bool contains_keyword_splat =
false;
14330 if (argument_allowed_for_bare_hash(parser, argument)) {
14331 if (parsed_bare_hash) {
14332 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14341 if (pm_command_call_value_p(parser, argument) || pm_block_call_p(argument)) {
14342 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->previous.
type));
14346 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
14347 operator = parser->previous;
14351 contains_keywords =
true;
14355 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14358 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));
14359 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
14361 pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
14362 argument = UP(bare_hash);
14365 if (accept1(parser, PM_TOKEN_COMMA) && (
14366 token_begins_expression_p(parser->current.type) ||
14367 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14369 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
14372 pm_static_literals_free(&hash_keys);
14373 parsed_bare_hash =
true;
14376 parse_arguments_append(parser, arguments, argument);
14378 pm_node_flags_t node_flags = 0;
14379 if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14380 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14381 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14387 parsed_first_argument =
true;
14390 if (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_NODE) || parser->recovering)
break;
14395 bool accepted_newline =
false;
14396 if (terminator != PM_TOKEN_EOF) {
14397 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14400 if (parser->previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14404 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14407 if (accepted_newline) {
14408 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14414 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
14417 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14429 if (match1(parser, terminator)) {
14435 if (parsed_forwarding_arguments) {
14436 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14455parse_required_destructured_parameter(
pm_parser_t *parser) {
14456 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14459 pm_multi_target_node_opening_set(parser, node, &parser->previous);
14468 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14469 param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14470 pm_multi_target_node_targets_append(parser, node, param);
14471 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14475 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
14476 param = UP(parse_required_destructured_parameter(parser));
14477 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14481 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14483 value = UP(pm_required_parameter_node_create(parser, &name));
14484 if (pm_parser_parameter_name_check(parser, &name)) {
14485 pm_node_flag_set_repeated_parameter(value);
14487 pm_parser_local_add_token(parser, &name, 1);
14490 param = UP(pm_splat_node_create(parser, &star, value));
14492 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14495 param = UP(pm_required_parameter_node_create(parser, &name));
14496 if (pm_parser_parameter_name_check(parser, &name)) {
14497 pm_node_flag_set_repeated_parameter(param);
14499 pm_parser_local_add_token(parser, &name, 1);
14502 pm_multi_target_node_targets_append(parser, node, param);
14503 }
while (accept1(parser, PM_TOKEN_COMMA));
14505 accept1(parser, PM_TOKEN_NEWLINE);
14506 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14507 pm_multi_target_node_closing_set(parser, node, &parser->previous);
14517 PM_PARAMETERS_NO_CHANGE = 0,
14518 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14519 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14520 PM_PARAMETERS_ORDER_KEYWORDS,
14521 PM_PARAMETERS_ORDER_REST,
14522 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14523 PM_PARAMETERS_ORDER_OPTIONAL,
14524 PM_PARAMETERS_ORDER_NAMED,
14525 PM_PARAMETERS_ORDER_NONE,
14526} pm_parameters_order_t;
14531static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14532 [0] = PM_PARAMETERS_NO_CHANGE,
14533 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14534 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14535 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14536 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14537 [PM_TOKEN_PARENTHESIS_LEFT_GROUPING] = PM_PARAMETERS_ORDER_NAMED,
14538 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14539 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14540 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14541 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14542 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14543 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14555 pm_parameters_order_t state = parameters_ordering[token->type];
14556 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14560 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14561 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14563 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14567 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14568 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14570 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14571 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14573 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14575 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14579 if (state < *current) *current = state;
14584parse_parameters_handle_trailing_comma(
14587 pm_parameters_order_t order,
14589 bool allows_trailing_comma
14591 if (!allows_trailing_comma) {
14592 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14597 if (order >= PM_PARAMETERS_ORDER_NAMED) {
14599 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14601 if (params->
rest == NULL) {
14602 pm_parameters_node_rest_set(params, param);
14604 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14605 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14609 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14614 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
14615 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14626 pm_binding_power_t binding_power,
14627 bool uses_parentheses,
14628 bool allows_trailing_comma,
14629 bool allows_forwarding_parameters,
14630 bool accepts_blocks_in_defaults,
14632 pm_diagnostic_id_t diag_id_forwarding,
14635 pm_do_loop_stack_push(parser,
false);
14638 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14641 bool parsing =
true;
14643 switch (parser->current.type) {
14644 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
14645 update_parameter_state(parser, &parser->current, &order);
14646 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
14648 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14649 pm_parameters_node_requireds_append(parser->arena, params, param);
14651 pm_parameters_node_posts_append(parser->arena, params, param);
14655 case PM_TOKEN_UAMPERSAND:
14656 case PM_TOKEN_AMPERSAND: {
14657 update_parameter_state(parser, &parser->current, &order);
14658 parser_lex(parser);
14663 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14664 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->previous);
14668 bool repeated =
false;
14669 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14670 name = parser->previous;
14671 repeated = pm_parser_parameter_name_check(parser, &name);
14672 pm_parser_local_add_token(parser, &name, 1);
14674 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
14677 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
14679 pm_node_flag_set_repeated_parameter(param);
14683 if (params->
block == NULL) {
14684 pm_parameters_node_block_set(params, param);
14686 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
14687 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14692 case PM_TOKEN_UDOT_DOT_DOT: {
14693 if (!allows_forwarding_parameters) {
14694 pm_parser_err_current(parser, diag_id_forwarding);
14697 bool succeeded = update_parameter_state(parser, &parser->current, &order);
14698 parser_lex(parser);
14700 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
14707 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, keyword_rest)));
14708 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14712 pm_parameters_node_keyword_rest_set(params, UP(param));
14715 case PM_TOKEN_CLASS_VARIABLE:
14716 case PM_TOKEN_IDENTIFIER:
14717 case PM_TOKEN_CONSTANT:
14718 case PM_TOKEN_INSTANCE_VARIABLE:
14719 case PM_TOKEN_GLOBAL_VARIABLE:
14720 case PM_TOKEN_METHOD_NAME: {
14721 parser_lex(parser);
14722 switch (parser->previous.
type) {
14723 case PM_TOKEN_CONSTANT:
14724 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14726 case PM_TOKEN_INSTANCE_VARIABLE:
14727 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14729 case PM_TOKEN_GLOBAL_VARIABLE:
14730 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14732 case PM_TOKEN_CLASS_VARIABLE:
14733 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14735 case PM_TOKEN_METHOD_NAME:
14736 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14741 if (parser->current.type == PM_TOKEN_EQUAL) {
14742 update_parameter_state(parser, &parser->current, &order);
14744 update_parameter_state(parser, &parser->previous, &order);
14748 bool repeated = pm_parser_parameter_name_check(parser, &name);
14749 pm_parser_local_add_token(parser, &name, 1);
14751 if (match1(parser, PM_TOKEN_EQUAL)) {
14753 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14754 parser_lex(parser);
14757 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14759 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14760 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14761 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14766 pm_node_flag_set_repeated_parameter(UP(param));
14768 pm_parameters_node_optionals_append(parser->arena, params, param);
14773 if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14774 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
14777 context_pop(parser);
14782 if (parser->recovering) {
14786 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14789 pm_node_flag_set_repeated_parameter(UP(param));
14791 pm_parameters_node_requireds_append(parser->arena, params, UP(param));
14795 pm_node_flag_set_repeated_parameter(UP(param));
14797 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14802 case PM_TOKEN_LABEL: {
14803 if (!uses_parentheses && !in_block) parser->in_keyword_arg =
true;
14804 update_parameter_state(parser, &parser->current, &order);
14806 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14807 parser_lex(parser);
14813 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)) {
14814 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14815 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14816 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14819 bool repeated = pm_parser_parameter_name_check(parser, &local);
14820 pm_parser_local_add_token(parser, &local, 1);
14822 switch (parser->current.type) {
14823 case PM_TOKEN_COMMA:
14824 case PM_TOKEN_PARENTHESIS_RIGHT:
14825 case PM_TOKEN_PIPE: {
14826 context_pop(parser);
14828 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14830 pm_node_flag_set_repeated_parameter(param);
14833 pm_parameters_node_keywords_append(parser->arena, params, param);
14836 case PM_TOKEN_SEMICOLON:
14837 case PM_TOKEN_NEWLINE: {
14838 context_pop(parser);
14840 if (uses_parentheses) {
14845 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14847 pm_node_flag_set_repeated_parameter(param);
14850 pm_parameters_node_keywords_append(parser->arena, params, param);
14856 if (token_begins_expression_p(parser->current.type)) {
14858 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14860 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14861 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));
14862 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14864 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14865 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
14868 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14871 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14875 pm_node_flag_set_repeated_parameter(param);
14878 context_pop(parser);
14879 pm_parameters_node_keywords_append(parser->arena, params, param);
14884 if (parser->recovering) {
14891 parser->in_keyword_arg =
false;
14894 case PM_TOKEN_USTAR:
14895 case PM_TOKEN_STAR: {
14896 update_parameter_state(parser, &parser->current, &order);
14897 parser_lex(parser);
14901 bool repeated =
false;
14903 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14904 name = parser->previous;
14905 repeated = pm_parser_parameter_name_check(parser, &name);
14906 pm_parser_local_add_token(parser, &name, 1);
14908 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
14911 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14913 pm_node_flag_set_repeated_parameter(param);
14916 if (params->
rest == NULL) {
14917 pm_parameters_node_rest_set(params, param);
14919 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14920 pm_parameters_node_posts_append(parser->arena, params, param);
14925 case PM_TOKEN_STAR_STAR:
14926 case PM_TOKEN_USTAR_STAR: {
14927 pm_parameters_order_t previous_order = order;
14928 update_parameter_state(parser, &parser->current, &order);
14929 parser_lex(parser);
14934 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14935 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14936 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14939 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
14943 bool repeated =
false;
14944 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14945 name = parser->previous;
14946 repeated = pm_parser_parameter_name_check(parser, &name);
14947 pm_parser_local_add_token(parser, &name, 1);
14949 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
14952 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14954 pm_node_flag_set_repeated_parameter(param);
14959 pm_parameters_node_keyword_rest_set(params, param);
14961 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14962 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14968 if (parser->previous.
type == PM_TOKEN_COMMA) {
14969 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
14979 if (!parsing)
break;
14981 bool accepted_newline =
false;
14982 if (uses_parentheses) {
14983 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14986 if (accept1(parser, PM_TOKEN_COMMA)) {
14989 if (accepted_newline) {
14990 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14998 pm_do_loop_stack_pop(parser);
15001 if (PM_NODE_START(params) == PM_NODE_END(params)) {
15014 if (parser->heredoc_end == NULL) {
15018 return parser->line_offsets.
size - 1;
15024 return (
size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
15033token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
15034 const uint8_t *cursor = parser->start + parser->line_offsets.
offsets[newline_index];
15035 const uint8_t *end = token->start;
15039 newline_index == 0 &&
15040 parser->start[0] == 0xef &&
15041 parser->start[1] == 0xbb &&
15042 parser->start[2] == 0xbf
15045 int64_t column = 0;
15046 for (; cursor < end; cursor++) {
15049 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15056 if (break_on_non_space)
return -1;
15069parser_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) {
15071 if (!parser->warn_mismatched_indentation)
return;
15074 size_t closing_newline_index = token_newline_index(parser);
15075 if (opening_newline_index == closing_newline_index)
return;
15080 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15081 if (!if_after_else && (opening_column == -1))
return;
15085 pm_token_t *closing_token = &parser->current;
15088 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15089 if ((closing_column == -1) || (opening_column == closing_column))
return;
15093 if (allow_indent && (closing_column > opening_column))
return;
15096 PM_PARSER_WARN_FORMAT(
15098 PM_TOKEN_START(parser, closing_token),
15099 PM_TOKEN_LENGTH(closing_token),
15100 PM_WARN_INDENTATION_MISMATCH,
15101 (
int) (closing_token->
end - closing_token->
start),
15102 (
const char *) closing_token->
start,
15103 (
int) (opening_token->
end - opening_token->
start),
15104 (
const char *) opening_token->
start,
15105 ((int32_t) opening_newline_index) + parser->start_line
15110 PM_RESCUES_BEGIN = 1,
15117} pm_rescues_type_t;
15127 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15128 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15129 parser_lex(parser);
15131 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
15133 switch (parser->current.type) {
15134 case PM_TOKEN_EQUAL_GREATER: {
15138 parser_lex(parser);
15139 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15141 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15142 reference = parse_target(parser, reference,
false,
false);
15144 pm_rescue_node_reference_set(rescue, reference);
15147 case PM_TOKEN_NEWLINE:
15148 case PM_TOKEN_SEMICOLON:
15149 case PM_TOKEN_KEYWORD_THEN:
15154 if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
15159 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15160 pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
15164 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15168 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15169 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15171 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15172 reference = parse_target(parser, reference,
false,
false);
15174 pm_rescue_node_reference_set(rescue, reference);
15177 }
while (accept1(parser, PM_TOKEN_COMMA));
15182 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15183 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15187 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15191 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15192 pm_accepts_block_stack_push(parser,
true);
15193 pm_context_t context;
15196 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_RESCUE;
break;
15197 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_RESCUE;
break;
15198 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_RESCUE;
break;
15199 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_RESCUE;
break;
15200 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE;
break;
15201 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE;
break;
15202 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE;
break;
15203 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15207 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15209 pm_accepts_block_stack_pop(parser);
15210 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15213 if (current == NULL) {
15214 pm_begin_node_rescue_clause_set(parent_node, rescue);
15216 pm_rescue_node_subsequent_set(current, rescue);
15225 if (current != NULL) {
15228 while (clause != NULL) {
15229 PM_NODE_LENGTH_SET_NODE(clause, current);
15235 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15236 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15237 opening_newline_index = token_newline_index(parser);
15239 else_keyword = parser->current;
15240 opening = &else_keyword;
15242 parser_lex(parser);
15243 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15246 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15247 pm_accepts_block_stack_push(parser,
true);
15248 pm_context_t context;
15251 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ELSE;
break;
15252 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ELSE;
break;
15253 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ELSE;
break;
15254 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ELSE;
break;
15255 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE;
break;
15256 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE;
break;
15257 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE;
break;
15258 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_ELSE;
break;
15261 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15262 pm_accepts_block_stack_pop(parser);
15264 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15267 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
15268 pm_begin_node_else_clause_set(parent_node, else_clause);
15272 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
15275 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15276 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15277 pm_token_t ensure_keyword = parser->current;
15279 parser_lex(parser);
15280 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15283 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15284 pm_accepts_block_stack_push(parser,
true);
15285 pm_context_t context;
15288 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ENSURE;
break;
15289 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ENSURE;
break;
15290 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ENSURE;
break;
15291 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ENSURE;
break;
15292 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE;
break;
15293 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE;
break;
15294 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE;
break;
15295 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15298 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15299 pm_accepts_block_stack_pop(parser);
15301 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15304 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
15305 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15308 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15309 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15310 pm_begin_node_end_keyword_set(parser, parent_node, &parser->current);
15313 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
15323 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
15324 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15327 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
15336parse_block_parameters(
15338 bool allows_trailing_comma,
15340 bool is_lambda_literal,
15341 bool accepts_blocks_in_defaults,
15345 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15346 if (!is_lambda_literal) {
15347 context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
15349 parameters = parse_parameters(
15351 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15353 allows_trailing_comma,
15355 accepts_blocks_in_defaults,
15357 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
15358 (uint16_t) (depth + 1)
15360 if (!is_lambda_literal) {
15361 context_pop(parser);
15366 if (opening != NULL) {
15367 accept1(parser, PM_TOKEN_NEWLINE);
15369 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15371 switch (parser->current.type) {
15372 case PM_TOKEN_CONSTANT:
15373 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15374 parser_lex(parser);
15376 case PM_TOKEN_INSTANCE_VARIABLE:
15377 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15378 parser_lex(parser);
15380 case PM_TOKEN_GLOBAL_VARIABLE:
15381 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15382 parser_lex(parser);
15384 case PM_TOKEN_CLASS_VARIABLE:
15385 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15386 parser_lex(parser);
15389 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15393 bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
15394 pm_parser_local_add_token(parser, &parser->previous, 1);
15397 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
15399 pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
15400 }
while (accept1(parser, PM_TOKEN_COMMA));
15404 return block_parameters;
15412outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15413 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15414 if (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15425static const char *
const pm_numbered_parameter_names[] = {
15426 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15436 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
15440 if (parameters != NULL) {
15442 if (implicit_parameters->
size > 0) {
15445 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15446 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15447 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15448 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15450 assert(
false &&
"unreachable");
15459 if (implicit_parameters->
size == 0) {
15466 uint8_t numbered_parameter = 0;
15467 bool it_parameter =
false;
15469 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15472 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15473 if (it_parameter) {
15474 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15475 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15476 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15477 }
else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
15478 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15479 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
15480 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->
location.
start + 1] -
'0'));
15482 assert(
false &&
"unreachable");
15484 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15485 if (numbered_parameter > 0) {
15486 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15488 it_parameter =
true;
15493 if (numbered_parameter > 0) {
15496 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15497 scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15499 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
15502 if (it_parameter) {
15503 return UP(pm_it_parameters_node_create(parser, opening, closing));
15513parse_block(
pm_parser_t *parser, uint16_t depth) {
15515 accept1(parser, PM_TOKEN_NEWLINE);
15521 bool do_block = opening.
type != PM_TOKEN_BRACE_LEFT && opening.
type != PM_TOKEN_BRACE_LEFT_ARGUMENT;
15522 if (do_block) pm_accepts_block_stack_push(parser,
true);
15523 pm_parser_scope_push(parser,
false);
15527 if (accept1(parser, PM_TOKEN_PIPE)) {
15528 pm_token_t block_parameters_opening = parser->previous;
15529 if (match1(parser, PM_TOKEN_PIPE)) {
15530 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15531 parser->command_start =
true;
15532 parser_lex(parser);
15534 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15535 accept1(parser, PM_TOKEN_NEWLINE);
15536 parser->command_start =
true;
15537 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15540 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
15543 accept1(parser, PM_TOKEN_NEWLINE);
15547 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15548 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
15551 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
15553 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15554 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15555 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)));
15558 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15559 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15560 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
15566 pm_accepts_block_stack_pop(parser);
15567 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
15571 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
15572 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
15574 pm_parser_scope_pop(parser);
15575 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
15590parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool full_arguments, uint8_t flags, uint16_t depth) {
15595 !token_begins_expression_p(parser->current.type) &&
15596 !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)
15601 bool found =
false;
15602 bool parsed_command_args =
false;
15604 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15606 arguments->
opening_loc = TOK2LOC(parser, &parser->previous);
15608 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15609 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15611 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
15619 if (!full_arguments && parser->previous.
type == PM_TOKEN_COMMA) {
15620 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15623 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15624 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
15625 parser->previous.
start = parser->previous.
end;
15626 parser->previous.
type = 0;
15629 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15631 }
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)) {
15633 parsed_command_args =
true;
15643 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);
15644 if (lookahead_delimiter) pm_accepts_block_stack_pop(parser);
15645 pm_accepts_block_stack_push(parser,
false);
15646 if (lookahead_delimiter) pm_accepts_block_stack_push(parser,
true);
15651 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
15656 if (parser->previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15657 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15665 bool lookahead_brace = match2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT);
15666 if (lookahead_brace) pm_accepts_block_stack_pop(parser);
15667 pm_accepts_block_stack_pop(parser);
15668 if (lookahead_brace) pm_accepts_block_stack_push(parser,
true);
15674 if (full_arguments) {
15677 if (accept2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT)) {
15679 block = parse_block(parser, (uint16_t) (depth + 1));
15680 pm_arguments_validate_block(parser, arguments, block);
15681 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15683 block = parse_block(parser, (uint16_t) (depth + 1));
15684 }
else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
15686 block = parse_block(parser, (uint16_t) (depth + 1));
15689 if (block != NULL) {
15691 arguments->
block = UP(block);
15693 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
15695 if (arguments->
block != NULL) {
15697 arguments->
arguments = pm_arguments_node_create(parser);
15699 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, arguments->
block);
15701 arguments->
block = UP(block);
15715 bool in_sclass =
false;
15716 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15717 switch (context_node->context) {
15718 case PM_CONTEXT_BEGIN_ELSE:
15719 case PM_CONTEXT_BEGIN_ENSURE:
15720 case PM_CONTEXT_BEGIN_RESCUE:
15721 case PM_CONTEXT_BEGIN:
15722 case PM_CONTEXT_CASE_IN:
15723 case PM_CONTEXT_CASE_WHEN:
15724 case PM_CONTEXT_DEFAULT_PARAMS:
15725 case PM_CONTEXT_DEFINED:
15726 case PM_CONTEXT_ELSE:
15727 case PM_CONTEXT_ELSIF:
15728 case PM_CONTEXT_EMBEXPR:
15729 case PM_CONTEXT_FOR_INDEX:
15730 case PM_CONTEXT_FOR:
15731 case PM_CONTEXT_IF:
15732 case PM_CONTEXT_LOOP_PREDICATE:
15733 case PM_CONTEXT_MAIN:
15734 case PM_CONTEXT_MULTI_TARGET:
15735 case PM_CONTEXT_PARENS:
15736 case PM_CONTEXT_POSTEXE:
15737 case PM_CONTEXT_PREDICATE:
15738 case PM_CONTEXT_PREEXE:
15739 case PM_CONTEXT_RESCUE_MODIFIER:
15740 case PM_CONTEXT_TERNARY:
15741 case PM_CONTEXT_UNLESS:
15742 case PM_CONTEXT_UNTIL:
15743 case PM_CONTEXT_WHILE:
15747 case PM_CONTEXT_SCLASS_ELSE:
15748 case PM_CONTEXT_SCLASS_ENSURE:
15749 case PM_CONTEXT_SCLASS_RESCUE:
15750 case PM_CONTEXT_SCLASS:
15753 case PM_CONTEXT_CLASS_ELSE:
15754 case PM_CONTEXT_CLASS_ENSURE:
15755 case PM_CONTEXT_CLASS_RESCUE:
15756 case PM_CONTEXT_CLASS:
15757 case PM_CONTEXT_MODULE_ELSE:
15758 case PM_CONTEXT_MODULE_ENSURE:
15759 case PM_CONTEXT_MODULE_RESCUE:
15760 case PM_CONTEXT_MODULE:
15762 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15764 case PM_CONTEXT_BLOCK_BRACES:
15765 case PM_CONTEXT_BLOCK_ELSE:
15766 case PM_CONTEXT_BLOCK_ENSURE:
15767 case PM_CONTEXT_BLOCK_KEYWORDS:
15768 case PM_CONTEXT_BLOCK_RESCUE:
15769 case PM_CONTEXT_BLOCK_PARAMETERS:
15770 case PM_CONTEXT_DEF_ELSE:
15771 case PM_CONTEXT_DEF_ENSURE:
15772 case PM_CONTEXT_DEF_PARAMS:
15773 case PM_CONTEXT_DEF_RESCUE:
15774 case PM_CONTEXT_DEF:
15775 case PM_CONTEXT_LAMBDA_BRACES:
15776 case PM_CONTEXT_LAMBDA_DO_END:
15777 case PM_CONTEXT_LAMBDA_ELSE:
15778 case PM_CONTEXT_LAMBDA_ENSURE:
15779 case PM_CONTEXT_LAMBDA_RESCUE:
15783 case PM_CONTEXT_NONE:
15784 case PM_CONTEXT_MAXIMUM:
15786 assert(
false &&
"unreachable");
15790 if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
15791 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15801 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15802 switch (context_node->context) {
15803 case PM_CONTEXT_BLOCK_BRACES:
15804 case PM_CONTEXT_BLOCK_KEYWORDS:
15805 case PM_CONTEXT_BLOCK_ELSE:
15806 case PM_CONTEXT_BLOCK_ENSURE:
15807 case PM_CONTEXT_BLOCK_PARAMETERS:
15808 case PM_CONTEXT_BLOCK_RESCUE:
15809 case PM_CONTEXT_DEFINED:
15810 case PM_CONTEXT_FOR:
15811 case PM_CONTEXT_LAMBDA_BRACES:
15812 case PM_CONTEXT_LAMBDA_DO_END:
15813 case PM_CONTEXT_LAMBDA_ELSE:
15814 case PM_CONTEXT_LAMBDA_ENSURE:
15815 case PM_CONTEXT_LAMBDA_RESCUE:
15816 case PM_CONTEXT_LOOP_PREDICATE:
15817 case PM_CONTEXT_UNTIL:
15818 case PM_CONTEXT_WHILE:
15822 case PM_CONTEXT_POSTEXE:
15824 if (context_node->context == PM_CONTEXT_POSTEXE) {
15825 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
15830 case PM_CONTEXT_DEF:
15831 case PM_CONTEXT_DEF_PARAMS:
15832 case PM_CONTEXT_DEF_ELSE:
15833 case PM_CONTEXT_DEF_ENSURE:
15834 case PM_CONTEXT_DEF_RESCUE:
15835 case PM_CONTEXT_MAIN:
15836 case PM_CONTEXT_PREEXE:
15837 case PM_CONTEXT_SCLASS:
15838 case PM_CONTEXT_SCLASS_ELSE:
15839 case PM_CONTEXT_SCLASS_ENSURE:
15840 case PM_CONTEXT_SCLASS_RESCUE:
15850 assert(parser->current_block_exits != NULL);
15851 pm_node_list_append(parser->arena, parser->current_block_exits, node);
15853 case PM_CONTEXT_BEGIN_ELSE:
15854 case PM_CONTEXT_BEGIN_ENSURE:
15855 case PM_CONTEXT_BEGIN_RESCUE:
15856 case PM_CONTEXT_BEGIN:
15857 case PM_CONTEXT_CASE_IN:
15858 case PM_CONTEXT_CASE_WHEN:
15859 case PM_CONTEXT_CLASS_ELSE:
15860 case PM_CONTEXT_CLASS_ENSURE:
15861 case PM_CONTEXT_CLASS_RESCUE:
15862 case PM_CONTEXT_CLASS:
15863 case PM_CONTEXT_DEFAULT_PARAMS:
15864 case PM_CONTEXT_ELSE:
15865 case PM_CONTEXT_ELSIF:
15866 case PM_CONTEXT_EMBEXPR:
15867 case PM_CONTEXT_FOR_INDEX:
15868 case PM_CONTEXT_IF:
15869 case PM_CONTEXT_MODULE_ELSE:
15870 case PM_CONTEXT_MODULE_ENSURE:
15871 case PM_CONTEXT_MODULE_RESCUE:
15872 case PM_CONTEXT_MODULE:
15873 case PM_CONTEXT_MULTI_TARGET:
15874 case PM_CONTEXT_PARENS:
15875 case PM_CONTEXT_PREDICATE:
15876 case PM_CONTEXT_RESCUE_MODIFIER:
15877 case PM_CONTEXT_TERNARY:
15878 case PM_CONTEXT_UNLESS:
15882 case PM_CONTEXT_NONE:
15883 case PM_CONTEXT_MAXIMUM:
15885 assert(
false &&
"unreachable");
15897 pm_node_list_t *previous_block_exits = parser->current_block_exits;
15898 parser->current_block_exits = current_block_exits;
15899 return previous_block_exits;
15913 switch (PM_NODE_TYPE(block_exit)) {
15914 case PM_BREAK_NODE:
type =
"break";
break;
15915 case PM_NEXT_NODE:
type =
"next";
break;
15916 case PM_REDO_NODE:
type =
"redo";
break;
15917 default: assert(
false &&
"unreachable");
type =
"";
break;
15920 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15923 parser->current_block_exits = previous_block_exits;
15932 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15936 parser->current_block_exits = previous_block_exits;
15937 }
else if (previous_block_exits != NULL) {
15943 pm_node_list_concat(parser->arena, previous_block_exits, parser->current_block_exits);
15944 parser->current_block_exits = previous_block_exits;
15949 flush_block_exits(parser, previous_block_exits);
15954parse_predicate(
pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context,
pm_token_t *then_keyword, uint16_t depth) {
15955 context_push(parser, PM_CONTEXT_PREDICATE);
15956 pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
15957 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));
15960 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15962 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15963 predicate_closed =
true;
15964 *then_keyword = parser->previous;
15967 if (!predicate_closed) {
15968 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15971 context_pop(parser);
15976parse_conditional(
pm_parser_t *parser, pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15978 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15983 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, context, &then_keyword, (uint16_t) (depth + 1));
15986 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15987 pm_accepts_block_stack_push(parser,
true);
15988 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15989 pm_accepts_block_stack_pop(parser);
15990 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15996 case PM_CONTEXT_IF:
15997 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15999 case PM_CONTEXT_UNLESS:
16000 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
16003 assert(
false &&
"unreachable");
16011 if (context == PM_CONTEXT_IF) {
16012 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
16013 if (parser_end_of_line_p(parser)) {
16014 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
16017 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16019 parser_lex(parser);
16021 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
16022 pm_accepts_block_stack_push(parser,
true);
16024 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
16025 pm_accepts_block_stack_pop(parser);
16026 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16028 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
16034 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
16035 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16036 opening_newline_index = token_newline_index(parser);
16038 parser_lex(parser);
16041 pm_accepts_block_stack_push(parser,
true);
16042 pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
16043 pm_accepts_block_stack_pop(parser);
16045 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16046 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
16047 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
16049 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
16052 case PM_CONTEXT_IF:
16053 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
16055 case PM_CONTEXT_UNLESS:
16059 assert(
false &&
"unreachable");
16063 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
16064 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
16069 case PM_CONTEXT_IF: {
16071 bool recursing =
true;
16073 while (recursing) {
16074 switch (PM_NODE_TYPE(current)) {
16076 pm_if_node_end_keyword_loc_set(parser, (
pm_if_node_t *) current, &parser->previous);
16078 recursing = current != NULL;
16081 pm_else_node_end_keyword_loc_set(parser, (
pm_else_node_t *) current, &parser->previous);
16092 case PM_CONTEXT_UNLESS:
16093 pm_unless_node_end_keyword_loc_set(parser, (
pm_unless_node_t *) parent, &parser->previous);
16096 assert(
false &&
"unreachable");
16100 pop_block_exits(parser, previous_block_exits);
16108#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16109 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16110 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16111 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: \
16112 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16113 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16114 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16115 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16116 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16117 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16118 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16124#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16125 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16126 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16127 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16128 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16129 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16130 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16131 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16138#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16139 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16140 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16141 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_XSTRING_BEGIN: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16142 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16143 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16144 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16145 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16146 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16152#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16153 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16154 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16155 case PM_TOKEN_CLASS_VARIABLE
16161#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16162 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16163 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16164 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16168PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16176 if (explicit_encoding != NULL) {
16177 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
16180 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16181 }
else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
16186 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16197parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16198 switch (parser->current.type) {
16205 case PM_TOKEN_STRING_CONTENT: {
16206 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16207 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
16209 parser_lex(parser);
16218 case PM_TOKEN_EMBEXPR_BEGIN: {
16221 parser->explicit_encoding = NULL;
16223 pm_lex_state_t state = parser->lex_state;
16224 int brace_nesting = parser->brace_nesting;
16226 parser->brace_nesting = 0;
16227 lex_state_set(parser, PM_LEX_STATE_BEG);
16228 parser_lex(parser);
16233 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
16234 statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
16237 parser->brace_nesting = brace_nesting;
16238 lex_state_set(parser, state);
16239 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16244 if (statements != NULL && statements->
body.
size == 1) {
16245 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16248 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
16257 case PM_TOKEN_EMBVAR: {
16260 parser->explicit_encoding = NULL;
16262 lex_state_set(parser, PM_LEX_STATE_BEG);
16263 parser_lex(parser);
16268 switch (parser->current.type) {
16271 case PM_TOKEN_BACK_REFERENCE:
16272 parser_lex(parser);
16273 variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
16277 case PM_TOKEN_NUMBERED_REFERENCE:
16278 parser_lex(parser);
16279 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16283 case PM_TOKEN_GLOBAL_VARIABLE:
16284 parser_lex(parser);
16285 variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
16289 case PM_TOKEN_INSTANCE_VARIABLE:
16290 parser_lex(parser);
16291 variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
16295 case PM_TOKEN_CLASS_VARIABLE:
16296 parser_lex(parser);
16297 variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
16303 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16304 variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16308 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
16311 parser_lex(parser);
16312 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16322static const uint8_t *
16323parse_operator_symbol_name(
const pm_token_t *name) {
16324 switch (name->
type) {
16325 case PM_TOKEN_TILDE:
16326 case PM_TOKEN_BANG:
16327 if (name->
end[-1] ==
'@')
return name->
end - 1;
16336 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
16337 const uint8_t *end = parse_operator_symbol_name(&parser->current);
16339 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16340 parser_lex(parser);
16342 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, end);
16343 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16354parse_symbol(
pm_parser_t *parser, pm_lex_state_t next_state, uint16_t depth) {
16356 parser_lex(parser);
16358 const pm_token_t opening = parser->previous;
16360 if (lex_mode.mode != PM_LEX_STRING) {
16361 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16363 switch (parser->current.type) {
16364 case PM_CASE_OPERATOR:
16365 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16366 case PM_TOKEN_IDENTIFIER:
16367 case PM_TOKEN_CONSTANT:
16368 case PM_TOKEN_INSTANCE_VARIABLE:
16369 case PM_TOKEN_METHOD_NAME:
16370 case PM_TOKEN_CLASS_VARIABLE:
16371 case PM_TOKEN_GLOBAL_VARIABLE:
16372 case PM_TOKEN_NUMBERED_REFERENCE:
16373 case PM_TOKEN_BACK_REFERENCE:
16374 case PM_CASE_KEYWORD:
16375 parser_lex(parser);
16378 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16382 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
16383 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16384 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16389 if (lex_mode.as.string.interpolation) {
16391 if (match1(parser, PM_TOKEN_STRING_END)) {
16392 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16393 parser_lex(parser);
16395 .
type = PM_TOKEN_STRING_CONTENT,
16396 .start = parser->previous.
start,
16397 .end = parser->previous.
start
16400 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
16404 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16408 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16409 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16410 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16412 return UP(pm_string_node_to_symbol_node(parser, (
pm_string_node_t *) part, &opening, &parser->previous));
16416 if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16418 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16419 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16420 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16424 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16425 if (match1(parser, PM_TOKEN_EOF)) {
16426 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16428 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16431 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16438 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16439 content = parser->current;
16440 unescaped = parser->current_string;
16441 parser_lex(parser);
16452 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16454 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16455 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16457 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
16458 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16460 if (next_state != PM_LEX_STATE_NONE) {
16461 lex_state_set(parser, next_state);
16464 parser_lex(parser);
16465 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16467 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16471 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.
end, .end = parser->previous.
end };
16472 pm_string_shared_init(&unescaped, content.
start, content.
end);
16475 if (next_state != PM_LEX_STATE_NONE) {
16476 lex_state_set(parser, next_state);
16479 if (match1(parser, PM_TOKEN_EOF)) {
16480 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16482 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16485 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
false)));
16493parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16494 switch (parser->current.type) {
16495 case PM_CASE_OPERATOR:
16496 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
16497 case PM_CASE_KEYWORD:
16498 case PM_TOKEN_CONSTANT:
16499 case PM_TOKEN_IDENTIFIER:
16500 case PM_TOKEN_METHOD_NAME: {
16501 parser_lex(parser);
16503 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16504 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16505 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16509 case PM_TOKEN_SYMBOL_BEGIN:
16510 return parse_symbol(parser, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16512 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16513 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16524parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16525 switch (parser->current.type) {
16526 case PM_CASE_OPERATOR:
16527 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16528 case PM_CASE_KEYWORD:
16529 case PM_TOKEN_CONSTANT:
16530 case PM_TOKEN_IDENTIFIER:
16531 case PM_TOKEN_METHOD_NAME: {
16532 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16533 parser_lex(parser);
16535 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16536 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16537 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16541 case PM_TOKEN_SYMBOL_BEGIN:
16542 return parse_symbol(parser, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16543 case PM_TOKEN_BACK_REFERENCE:
16544 parser_lex(parser);
16545 return UP(pm_back_reference_read_node_create(parser, &parser->previous));
16546 case PM_TOKEN_NUMBERED_REFERENCE:
16547 parser_lex(parser);
16548 return UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16549 case PM_TOKEN_GLOBAL_VARIABLE:
16550 parser_lex(parser);
16551 return UP(pm_global_variable_read_node_create(parser, &parser->previous));
16553 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16554 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16564 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
16566 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
16568 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16569 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth,
false));
16572 pm_scope_t *current_scope = parser->current_scope;
16573 if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16574 if (is_numbered_param) {
16579 uint8_t maximum = (uint8_t) (parser->previous.
start[1] -
'0');
16580 for (uint8_t number = 1; number <= maximum; number++) {
16581 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16584 if (!match1(parser, PM_TOKEN_EQUAL)) {
16585 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
16588 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0,
false));
16589 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16592 }
else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.
start, parser->previous.
end)) {
16593 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16594 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16608 pm_node_flags_t flags = 0;
16610 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.
end[-1] !=
'!') && (parser->previous.
end[-1] !=
'?')) {
16611 pm_node_t *node = parse_variable(parser);
16612 if (node != NULL)
return node;
16613 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16616 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
16617 pm_node_flag_set(UP(node), flags);
16628parse_method_definition_name(
pm_parser_t *parser) {
16629 switch (parser->current.type) {
16630 case PM_CASE_KEYWORD:
16631 case PM_TOKEN_CONSTANT:
16632 case PM_TOKEN_METHOD_NAME:
16633 parser_lex(parser);
16634 return parser->previous;
16635 case PM_TOKEN_IDENTIFIER:
16636 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
16637 parser_lex(parser);
16638 return parser->previous;
16639 case PM_CASE_OPERATOR:
16640 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16641 parser_lex(parser);
16642 return parser->previous;
16644 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
16645 return (
pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end };
16656 if (string->
type != PM_STRING_OWNED) {
16657 size_t length = pm_string_length(
string);
16658 writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(
string), length,
PRISM_ALIGNOF(uint8_t));
16659 pm_string_constant_init(
string, (
const char *) writable, length);
16661 writable = (uint8_t *) string->
source;
16667 size_t dest_length = pm_string_length(
string);
16668 const uint8_t *source_cursor = writable;
16669 const uint8_t *source_end = source_cursor + dest_length;
16674 size_t trimmed_whitespace = 0;
16680 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16681 if (*source_cursor ==
'\t') {
16682 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16683 if (trimmed_whitespace > common_whitespace)
break;
16685 trimmed_whitespace++;
16692 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
16693 string->length = dest_length;
16703 const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->
content_loc);
16704 return pm_memchr(cursor,
'\\', string_node->
content_loc.
length, parser->encoding_changed, parser->encoding) == NULL;
16716 bool dedent_next =
true;
16720 size_t write_index = 0;
16727 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16728 nodes->
nodes[write_index++] = node;
16729 dedent_next =
false;
16735 parse_heredoc_dedent_string(parser->arena, &string_node->
unescaped, common_whitespace);
16738 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16740 nodes->
nodes[write_index++] = node;
16744 dedent_next =
true;
16747 nodes->
size = write_index;
16754parse_strings_empty_content(
const uint8_t *location) {
16755 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16763 assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
16764 bool concating =
false;
16766 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16772 assert(lex_mode->mode == PM_LEX_STRING);
16773 bool lex_interpolation = lex_mode->as.string.interpolation;
16774 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
16777 parser_lex(parser);
16779 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16780 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16784 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
16785 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->previous);
16789 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16793 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
16794 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
start);
16797 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16798 }
else if (!lex_interpolation) {
16804 if (match1(parser, PM_TOKEN_EOF)) {
16805 unescaped = PM_STRING_EMPTY;
16806 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
16808 unescaped = parser->current_string;
16809 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16810 content = parser->previous;
16824 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16826 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16827 pm_node_list_append(parser->arena, &parts, part);
16830 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16831 pm_node_list_append(parser->arena, &parts, part);
16832 parser_lex(parser);
16833 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16835 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16836 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16837 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16838 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
true)));
16839 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16840 }
else if (match1(parser, PM_TOKEN_EOF)) {
16841 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16842 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16843 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16844 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16846 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.
type));
16847 parser->previous.
start = parser->previous.
end;
16848 parser->previous.
type = 0;
16849 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16851 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16858 const pm_encoding_t *explicit_encoding = parser->explicit_encoding;
16859 parser_lex(parser);
16861 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16862 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16863 pm_node_flag_set(node, parse_unescaped_encoding(parser, explicit_encoding));
16869 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16870 const uint8_t *location = parser->previous.
end;
16871 if (location > parser->start && location[-1] ==
'\n') location--;
16872 pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
16874 parser->previous.
start = parser->previous.
end;
16875 parser->previous.
type = 0;
16877 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16878 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, explicit_encoding, &content, &unescaped,
true)));
16879 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16884 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
16885 pm_node_flag_set(part, parse_unescaped_encoding(parser, explicit_encoding));
16886 pm_node_list_append(parser->arena, &parts, part);
16888 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16889 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16890 pm_node_list_append(parser->arena, &parts, part);
16894 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16895 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16896 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16897 }
else if (match1(parser, PM_TOKEN_EOF)) {
16898 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16899 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16901 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16902 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16912 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16913 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16914 pm_node_list_append(parser->arena, &parts, part);
16918 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16919 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16920 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16921 }
else if (match1(parser, PM_TOKEN_EOF)) {
16922 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16923 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16925 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16926 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16930 if (current == NULL) {
16934 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16945 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16946 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16952 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16953 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16958 pm_interpolated_string_node_append(parser, container, current);
16959 current = UP(container);
16969#define PM_PARSE_PATTERN_SINGLE 0
16970#define PM_PARSE_PATTERN_TOP 1
16971#define PM_PARSE_PATTERN_MULTI 2
16984 if (peek_at(parser, parser->start + location->
start) ==
'_')
return;
16986 if (!pm_constant_id_set_insert(parser->arena, captures, capture)) {
16987 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16998 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
17000 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17001 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
17007 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
17015 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
17016 opening = parser->previous;
17017 accept1(parser, PM_TOKEN_NEWLINE);
17019 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17020 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17021 accept1(parser, PM_TOKEN_NEWLINE);
17022 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17025 closing = parser->previous;
17027 parser_lex(parser);
17028 opening = parser->previous;
17029 accept1(parser, PM_TOKEN_NEWLINE);
17031 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17032 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17033 accept1(parser, PM_TOKEN_NEWLINE);
17034 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17037 closing = parser->previous;
17043 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
17050 switch (PM_NODE_TYPE(inner)) {
17051 case PM_ARRAY_PATTERN_NODE: {
17055 PM_NODE_START_SET_NODE(pattern_node, node);
17056 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17059 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17060 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17062 return UP(pattern_node);
17067 case PM_FIND_PATTERN_NODE: {
17071 PM_NODE_START_SET_NODE(pattern_node, node);
17072 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17075 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17076 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17078 return UP(pattern_node);
17083 case PM_HASH_PATTERN_NODE: {
17087 PM_NODE_START_SET_NODE(pattern_node, node);
17088 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17091 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17092 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17094 return UP(pattern_node);
17106 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17107 pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
17108 return UP(pattern_node);
17116 assert(parser->previous.
type == PM_TOKEN_USTAR);
17123 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17124 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17127 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17128 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17131 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17132 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17133 name = UP(pm_local_variable_target_node_create(
17137 (uint32_t) (depth == -1 ? 0 : depth)
17142 return pm_splat_node_create(parser, &
operator, name);
17150 assert(parser->current.type == PM_TOKEN_USTAR_STAR);
17151 parser_lex(parser);
17156 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17157 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
17160 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17161 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17164 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17165 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17168 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17169 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17170 value = UP(pm_local_variable_target_node_create(
17174 (uint32_t) (depth == -1 ? 0 : depth)
17178 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
17186pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17187 ptrdiff_t length = end - start;
17188 if (length == 0)
return false;
17191 size_t width = char_is_identifier_start(parser, start, end - start);
17192 if (width == 0)
return false;
17195 if (parser->encoding_changed) {
17196 if (parser->encoding->isupper_char(start, length))
return false;
17198 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17203 const uint8_t *cursor = start + width;
17204 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17205 return cursor == end;
17215 const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
17216 const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
17218 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
17221 if (pm_slice_is_valid_local(parser, start, end)) {
17222 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17224 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
17226 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
17227 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
17232 pm_parser_local_add(parser, constant_id, start, end, 0);
17235 parse_pattern_capture(parser, captures, constant_id, value_loc);
17240 (uint32_t) (depth == -1 ? 0 : depth)
17243 return UP(pm_implicit_node_create(parser, UP(target)));
17252 if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, keys, node,
true) != NULL) {
17253 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17266 switch (PM_NODE_TYPE(first_node)) {
17267 case PM_ASSOC_SPLAT_NODE:
17268 case PM_NO_KEYWORDS_PARAMETER_NODE:
17271 case PM_INTERPOLATED_SYMBOL_NODE:
17272 case PM_SYMBOL_NODE: {
17273 if (pm_symbol_node_label_p(parser, first_node)) {
17274 if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
17275 pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17277 parse_pattern_hash_key(parser, &keys, first_node);
17287 if (!token_begins_pattern_p(parser->current.type)) {
17288 if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
17289 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17291 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
17296 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17299 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17300 pm_node_list_append(parser->arena, &assocs, assoc);
17309 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;
17310 pm_parser_err_node(parser, first_node, diag_id);
17312 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
17313 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17315 pm_node_list_append(parser->arena, &assocs, assoc);
17321 while (accept1(parser, PM_TOKEN_COMMA)) {
17327 if (!token_begins_pattern_p(parser->current.type)) {
17329 if (rest != NULL) {
17330 pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17336 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17337 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17339 if (rest == NULL) {
17342 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17343 pm_node_list_append(parser->arena, &assocs, assoc);
17348 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17349 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17351 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17352 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17353 }
else if (!pm_symbol_node_label_p(parser, key)) {
17354 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17356 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
17357 key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17359 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17361 pm_token_t label = { .
type = PM_TOKEN_LABEL, .start = parser->previous.
end, .end = parser->previous.
end };
17362 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
17365 parse_pattern_hash_key(parser, &keys, key);
17373 if (!token_begins_pattern_p(parser->current.type)) {
17374 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
17375 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17377 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
17380 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17383 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
17385 if (rest != NULL) {
17386 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17389 pm_node_list_append(parser->arena, &assocs, assoc);
17396 pm_static_literals_free(&keys);
17405 switch (parser->current.type) {
17406 case PM_TOKEN_IDENTIFIER:
17407 case PM_TOKEN_METHOD_NAME: {
17408 parser_lex(parser);
17409 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17412 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17413 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17416 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17417 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17418 return UP(pm_local_variable_target_node_create(
17422 (uint32_t) (depth == -1 ? 0 : depth)
17425 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17427 parser_lex(parser);
17429 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17432 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
17437 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17439 accept1(parser, PM_TOKEN_NEWLINE);
17440 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17443 switch (PM_NODE_TYPE(inner)) {
17444 case PM_ARRAY_PATTERN_NODE: {
17447 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17448 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17450 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17451 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17453 return UP(pattern_node);
17458 case PM_FIND_PATTERN_NODE: {
17461 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17462 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17464 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17465 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17467 return UP(pattern_node);
17477 pm_array_pattern_node_requireds_append(parser->arena, node, inner);
17480 case PM_TOKEN_BRACE_LEFT_HASH: {
17481 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17482 parser->pattern_matching_newlines =
false;
17486 parser_lex(parser);
17488 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17491 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
17495 switch (parser->current.type) {
17496 case PM_TOKEN_LABEL:
17497 parser_lex(parser);
17498 first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
17500 case PM_TOKEN_USTAR_STAR:
17501 first_node = parse_pattern_keyword_rest(parser, captures);
17503 case PM_TOKEN_STRING_BEGIN:
17504 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));
17507 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
17508 parser_lex(parser);
17510 first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
17515 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17517 accept1(parser, PM_TOKEN_NEWLINE);
17518 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
17521 PM_NODE_START_SET_TOKEN(parser, node, &opening);
17522 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
17528 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17531 case PM_TOKEN_UDOT_DOT:
17532 case PM_TOKEN_UDOT_DOT_DOT: {
17534 parser_lex(parser);
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, NULL, &
operator, right));
17544 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17545 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17546 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17550 case PM_CASE_PRIMITIVE: {
17551 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));
17554 if (pm_symbol_node_label_p(parser, node))
return node;
17557 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17558 pm_parser_err_node(parser, node, diag_id);
17559 return UP(pm_error_recovery_node_create_unexpected(parser, node));
17563 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17569 switch (parser->current.type) {
17570 case PM_CASE_PRIMITIVE: {
17571 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));
17572 return UP(pm_range_node_create(parser, node, &
operator, right));
17575 return UP(pm_range_node_create(parser, node, &
operator, NULL));
17581 case PM_TOKEN_CARET: {
17582 parser_lex(parser);
17587 switch (parser->current.type) {
17588 case PM_TOKEN_IDENTIFIER: {
17589 parser_lex(parser);
17590 pm_node_t *variable = UP(parse_variable(parser));
17592 if (variable == NULL) {
17593 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
17594 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
17597 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17599 case PM_TOKEN_INSTANCE_VARIABLE: {
17600 parser_lex(parser);
17601 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
17603 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17605 case PM_TOKEN_CLASS_VARIABLE: {
17606 parser_lex(parser);
17607 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
17609 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17611 case PM_TOKEN_GLOBAL_VARIABLE: {
17612 parser_lex(parser);
17613 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
17615 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17617 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
17618 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17619 parser->pattern_matching_newlines =
false;
17622 parser_lex(parser);
17624 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));
17625 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17627 accept1(parser, PM_TOKEN_NEWLINE);
17628 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
17629 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->previous));
17634 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17635 pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17636 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17640 case PM_TOKEN_UCOLON_COLON: {
17642 parser_lex(parser);
17644 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17647 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
17649 case PM_TOKEN_CONSTANT: {
17651 parser_lex(parser);
17653 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
17654 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17657 pm_parser_err_current(parser, diag_id);
17658 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17670parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
17673 switch (PM_NODE_TYPE(node)) {
17674 case PM_LOCAL_VARIABLE_TARGET_NODE:
17677 if (peek_at(parser, parser->start + PM_NODE_START(node)) !=
'_') {
17678 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17681 case PM_ARRAY_PATTERN_NODE:
17682 case PM_ASSOC_NODE:
17683 case PM_ASSOC_SPLAT_NODE:
17684 case PM_CAPTURE_PATTERN_NODE:
17685 case PM_FIND_PATTERN_NODE:
17686 case PM_HASH_PATTERN_NODE:
17687 case PM_IMPLICIT_NODE:
17688 case PM_PARENTHESES_NODE:
17689 case PM_SPLAT_NODE:
17703 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
17713 bool alternation =
false;
17715 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
17716 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->size) {
17717 parse_pattern_alternation_error(parser, node);
17720 switch (parser->current.type) {
17721 case PM_TOKEN_IDENTIFIER:
17722 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17723 case PM_TOKEN_BRACE_LEFT_HASH:
17724 case PM_TOKEN_CARET:
17725 case PM_TOKEN_CONSTANT:
17726 case PM_TOKEN_UCOLON_COLON:
17727 case PM_TOKEN_UDOT_DOT:
17728 case PM_TOKEN_UDOT_DOT_DOT:
17729 case PM_CASE_PRIMITIVE: {
17730 if (!alternation) {
17731 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17734 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17736 if (captures->size) parse_pattern_alternation_error(parser, right);
17737 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17742 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
17743 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17746 parser_lex(parser);
17748 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17749 accept1(parser, PM_TOKEN_NEWLINE);
17750 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17751 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
17753 if (!alternation) {
17756 if (captures->size) parse_pattern_alternation_error(parser, right);
17757 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17763 pm_parser_err_current(parser, diag_id);
17764 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17766 if (!alternation) {
17769 if (captures->size) parse_pattern_alternation_error(parser, right);
17770 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
17780 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17782 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17784 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17787 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17788 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17791 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17792 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17797 (uint32_t) (depth == -1 ? 0 : depth)
17800 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17813 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
17814 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
17815 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17820 bool leading_rest =
false;
17821 bool trailing_rest =
false;
17823 switch (parser->current.type) {
17824 case PM_TOKEN_LABEL: {
17825 parser_lex(parser);
17826 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17827 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17829 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17830 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17835 case PM_TOKEN_USTAR_STAR: {
17836 node = parse_pattern_keyword_rest(parser, captures);
17837 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17839 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17840 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17845 case PM_TOKEN_STRING_BEGIN: {
17848 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17850 if (pm_symbol_node_label_p(parser, node)) {
17851 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17853 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17854 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17860 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17863 case PM_TOKEN_USTAR: {
17864 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17865 parser_lex(parser);
17866 node = UP(parse_pattern_rest(parser, captures));
17867 leading_rest =
true;
17873 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17879 if (pm_symbol_node_label_p(parser, node)) {
17880 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17883 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17888 pm_node_list_append(parser->arena, &nodes, node);
17891 while (accept1(parser, PM_TOKEN_COMMA)) {
17897 if (!token_begins_pattern_p(parser->current.type)) {
17902 if (trailing_rest) {
17903 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17906 node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
17907 pm_node_list_append(parser->arena, &nodes, node);
17908 trailing_rest =
true;
17912 if (accept1(parser, PM_TOKEN_USTAR)) {
17913 node = UP(parse_pattern_rest(parser, captures));
17918 if (trailing_rest) {
17919 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17922 trailing_rest =
true;
17924 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17927 pm_node_list_append(parser->arena, &nodes, node);
17934 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17935 node = UP(pm_find_pattern_node_create(parser, &nodes));
17937 if (nodes.
size == 2) {
17938 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17941 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17943 if (leading_rest && trailing_rest) {
17944 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17949 }
else if (leading_rest) {
17952 node = UP(pm_array_pattern_node_rest_create(parser, node));
17964parse_negative_numeric(
pm_node_t *node) {
17965 switch (PM_NODE_TYPE(node)) {
17966 case PM_INTEGER_NODE: {
17973 case PM_FLOAT_NODE: {
17980 case PM_RATIONAL_NODE: {
17987 case PM_IMAGINARY_NODE:
17993 assert(
false &&
"unreachable");
18004pm_parser_err_prefix(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
18006 case PM_ERR_HASH_KEY: {
18007 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.
type));
18010 case PM_ERR_HASH_VALUE:
18011 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
18012 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
18015 case PM_ERR_UNARY_RECEIVER: {
18016 const char *human = (parser->current.type == PM_TOKEN_EOF ?
"end-of-input" : pm_token_str(parser->current.type));
18017 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.
start[0]);
18020 case PM_ERR_UNARY_DISALLOWED:
18021 case PM_ERR_EXPECT_ARGUMENT: {
18022 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
18026 pm_parser_err_previous(parser, diag_id);
18036#define CONTEXT_NONE 0
18037#define CONTEXT_THROUGH_ENSURE 1
18038#define CONTEXT_THROUGH_ELSE 2
18041 int context = CONTEXT_NONE;
18043 while (context_node != NULL) {
18044 switch (context_node->context) {
18045 case PM_CONTEXT_BEGIN_RESCUE:
18046 case PM_CONTEXT_BLOCK_RESCUE:
18047 case PM_CONTEXT_CLASS_RESCUE:
18048 case PM_CONTEXT_DEF_RESCUE:
18049 case PM_CONTEXT_LAMBDA_RESCUE:
18050 case PM_CONTEXT_MODULE_RESCUE:
18051 case PM_CONTEXT_SCLASS_RESCUE:
18052 case PM_CONTEXT_DEFINED:
18053 case PM_CONTEXT_RESCUE_MODIFIER:
18056 case PM_CONTEXT_CLASS:
18057 case PM_CONTEXT_DEF:
18058 case PM_CONTEXT_DEF_PARAMS:
18059 case PM_CONTEXT_MAIN:
18060 case PM_CONTEXT_MODULE:
18061 case PM_CONTEXT_PREEXE:
18062 case PM_CONTEXT_SCLASS:
18065 if (context == CONTEXT_NONE) {
18066 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
18067 }
else if (context == CONTEXT_THROUGH_ENSURE) {
18068 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
18069 }
else if (context == CONTEXT_THROUGH_ELSE) {
18070 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
18073 case PM_CONTEXT_BEGIN_ELSE:
18074 case PM_CONTEXT_BLOCK_ELSE:
18075 case PM_CONTEXT_CLASS_ELSE:
18076 case PM_CONTEXT_DEF_ELSE:
18077 case PM_CONTEXT_LAMBDA_ELSE:
18078 case PM_CONTEXT_MODULE_ELSE:
18079 case PM_CONTEXT_SCLASS_ELSE:
18082 context = CONTEXT_THROUGH_ELSE;
18084 case PM_CONTEXT_BEGIN_ENSURE:
18085 case PM_CONTEXT_BLOCK_ENSURE:
18086 case PM_CONTEXT_CLASS_ENSURE:
18087 case PM_CONTEXT_DEF_ENSURE:
18088 case PM_CONTEXT_LAMBDA_ENSURE:
18089 case PM_CONTEXT_MODULE_ENSURE:
18090 case PM_CONTEXT_SCLASS_ENSURE:
18093 context = CONTEXT_THROUGH_ENSURE;
18095 case PM_CONTEXT_NONE:
18096 case PM_CONTEXT_MAXIMUM:
18098 assert(
false &&
"unreachable");
18100 case PM_CONTEXT_BEGIN:
18101 case PM_CONTEXT_BLOCK_BRACES:
18102 case PM_CONTEXT_BLOCK_KEYWORDS:
18103 case PM_CONTEXT_BLOCK_PARAMETERS:
18104 case PM_CONTEXT_CASE_IN:
18105 case PM_CONTEXT_CASE_WHEN:
18106 case PM_CONTEXT_DEFAULT_PARAMS:
18107 case PM_CONTEXT_ELSE:
18108 case PM_CONTEXT_ELSIF:
18109 case PM_CONTEXT_EMBEXPR:
18110 case PM_CONTEXT_FOR_INDEX:
18111 case PM_CONTEXT_FOR:
18112 case PM_CONTEXT_IF:
18113 case PM_CONTEXT_LAMBDA_BRACES:
18114 case PM_CONTEXT_LAMBDA_DO_END:
18115 case PM_CONTEXT_LOOP_PREDICATE:
18116 case PM_CONTEXT_MULTI_TARGET:
18117 case PM_CONTEXT_PARENS:
18118 case PM_CONTEXT_POSTEXE:
18119 case PM_CONTEXT_PREDICATE:
18120 case PM_CONTEXT_TERNARY:
18121 case PM_CONTEXT_UNLESS:
18122 case PM_CONTEXT_UNTIL:
18123 case PM_CONTEXT_WHILE:
18129 context_node = context_node->prev;
18133#undef CONTEXT_ENSURE
18144 while (context_node != NULL) {
18145 switch (context_node->context) {
18146 case PM_CONTEXT_DEF:
18147 case PM_CONTEXT_DEF_PARAMS:
18148 case PM_CONTEXT_DEFINED:
18149 case PM_CONTEXT_DEF_ENSURE:
18150 case PM_CONTEXT_DEF_RESCUE:
18151 case PM_CONTEXT_DEF_ELSE:
18155 case PM_CONTEXT_CLASS:
18156 case PM_CONTEXT_CLASS_ENSURE:
18157 case PM_CONTEXT_CLASS_RESCUE:
18158 case PM_CONTEXT_CLASS_ELSE:
18159 case PM_CONTEXT_MAIN:
18160 case PM_CONTEXT_MODULE:
18161 case PM_CONTEXT_MODULE_ENSURE:
18162 case PM_CONTEXT_MODULE_RESCUE:
18163 case PM_CONTEXT_MODULE_ELSE:
18164 case PM_CONTEXT_SCLASS:
18165 case PM_CONTEXT_SCLASS_RESCUE:
18166 case PM_CONTEXT_SCLASS_ENSURE:
18167 case PM_CONTEXT_SCLASS_ELSE:
18170 pm_parser_err_node(parser, UP(node), PM_ERR_INVALID_YIELD);
18172 case PM_CONTEXT_NONE:
18173 case PM_CONTEXT_MAXIMUM:
18175 assert(
false &&
"unreachable");
18177 case PM_CONTEXT_BEGIN:
18178 case PM_CONTEXT_BEGIN_ELSE:
18179 case PM_CONTEXT_BEGIN_ENSURE:
18180 case PM_CONTEXT_BEGIN_RESCUE:
18181 case PM_CONTEXT_BLOCK_BRACES:
18182 case PM_CONTEXT_BLOCK_KEYWORDS:
18183 case PM_CONTEXT_BLOCK_ELSE:
18184 case PM_CONTEXT_BLOCK_ENSURE:
18185 case PM_CONTEXT_BLOCK_PARAMETERS:
18186 case PM_CONTEXT_BLOCK_RESCUE:
18187 case PM_CONTEXT_CASE_IN:
18188 case PM_CONTEXT_CASE_WHEN:
18189 case PM_CONTEXT_DEFAULT_PARAMS:
18190 case PM_CONTEXT_ELSE:
18191 case PM_CONTEXT_ELSIF:
18192 case PM_CONTEXT_EMBEXPR:
18193 case PM_CONTEXT_FOR_INDEX:
18194 case PM_CONTEXT_FOR:
18195 case PM_CONTEXT_IF:
18196 case PM_CONTEXT_LAMBDA_BRACES:
18197 case PM_CONTEXT_LAMBDA_DO_END:
18198 case PM_CONTEXT_LAMBDA_ELSE:
18199 case PM_CONTEXT_LAMBDA_ENSURE:
18200 case PM_CONTEXT_LAMBDA_RESCUE:
18201 case PM_CONTEXT_LOOP_PREDICATE:
18202 case PM_CONTEXT_MULTI_TARGET:
18203 case PM_CONTEXT_PARENS:
18204 case PM_CONTEXT_POSTEXE:
18205 case PM_CONTEXT_PREDICATE:
18206 case PM_CONTEXT_PREEXE:
18207 case PM_CONTEXT_RESCUE_MODIFIER:
18208 case PM_CONTEXT_TERNARY:
18209 case PM_CONTEXT_UNLESS:
18210 case PM_CONTEXT_UNTIL:
18211 case PM_CONTEXT_WHILE:
18217 context_node = context_node->prev;
18226parse_case(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18227 size_t opening_newline_index = token_newline_index(parser);
18228 parser_lex(parser);
18234 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18236 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18237 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18239 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18241 }
else if (!token_begins_expression_p(parser->current.type)) {
18244 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));
18245 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18248 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18249 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18250 parser_lex(parser);
18251 pop_block_exits(parser, previous_block_exits);
18252 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18253 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->previous));
18260 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18261 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
18267 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18268 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18269 parser_lex(parser);
18272 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18275 if (accept1(parser, PM_TOKEN_USTAR)) {
18277 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));
18279 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18280 pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
18282 if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE))
break;
18284 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));
18285 pm_when_node_conditions_append(parser->arena, when_node, condition);
18289 if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE))
break;
18293 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18294 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18295 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE) && parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
18296 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18299 pm_when_clause_static_literals_add(parser, &literals, condition);
18301 }
while (accept1(parser, PM_TOKEN_COMMA));
18303 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18304 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18305 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18308 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18309 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18312 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18313 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18314 if (statements != NULL) {
18315 pm_when_node_statements_set(when_node, statements);
18319 pm_case_node_condition_append(parser->arena, case_node, UP(when_node));
18325 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18328 pm_static_literals_free(&literals);
18329 node = UP(case_node);
18331 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
18335 if (predicate == NULL) {
18336 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18341 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18342 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18344 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
18345 parser->pattern_matching_newlines =
true;
18347 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18348 parser->command_start =
false;
18349 parser_lex(parser);
18354 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));
18356 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
18361 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18363 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));
18364 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18365 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18367 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));
18368 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18375 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18376 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18377 then_keyword = parser->previous;
18380 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18381 then_keyword = parser->previous;
18387 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18390 statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
18395 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
18396 pm_case_match_node_condition_append(parser->arena, case_node, condition);
18402 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18405 node = UP(case_node);
18408 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18409 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18413 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18414 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
18416 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
18419 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18420 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18426 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18427 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18429 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18430 pm_case_node_end_keyword_loc_set(parser, (
pm_case_node_t *) node, &parser->previous);
18432 pm_case_match_node_end_keyword_loc_set(parser, (
pm_case_match_node_t *) node, &parser->previous);
18435 pop_block_exits(parser, previous_block_exits);
18444parse_class(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18445 size_t opening_newline_index = token_newline_index(parser);
18446 parser_lex(parser);
18448 pm_token_t class_keyword = parser->previous;
18449 pm_do_loop_stack_push(parser,
false);
18452 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18454 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18456 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));
18458 pm_parser_scope_push(parser,
true);
18459 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18460 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
18464 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18465 pm_accepts_block_stack_push(parser,
true);
18466 statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18467 pm_accepts_block_stack_pop(parser);
18470 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18471 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18472 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)));
18474 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18477 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18480 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18482 pm_parser_scope_pop(parser);
18483 pm_do_loop_stack_pop(parser);
18485 flush_block_exits(parser, previous_block_exits);
18486 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->previous));
18489 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));
18491 if (name.
type != PM_TOKEN_CONSTANT) {
18492 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18498 if (match1(parser, PM_TOKEN_LESS)) {
18499 inheritance_operator = parser->current;
18500 lex_state_set(parser, PM_LEX_STATE_BEG);
18502 parser->command_start =
true;
18503 parser_lex(parser);
18505 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));
18510 pm_parser_scope_push(parser,
true);
18512 if (inheritance_operator.
start != NULL) {
18513 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18515 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18519 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18520 pm_accepts_block_stack_push(parser,
true);
18521 statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18522 pm_accepts_block_stack_pop(parser);
18525 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18526 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18527 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)));
18529 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18532 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18534 if (context_def_p(parser)) {
18535 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18539 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18541 pm_parser_scope_pop(parser);
18542 pm_do_loop_stack_pop(parser);
18544 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18545 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18546 if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18547 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18551 pop_block_exits(parser, previous_block_exits);
18552 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
18559parse_def(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
18561 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18564 size_t opening_newline_index = token_newline_index(parser);
18572 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18573 parser_lex(parser);
18577 bool valid_name =
true;
18579 switch (parser->current.type) {
18580 case PM_CASE_OPERATOR:
18581 pm_parser_scope_push(parser,
true);
18582 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18583 parser_lex(parser);
18585 name = parser->previous;
18587 case PM_TOKEN_IDENTIFIER: {
18588 parser_lex(parser);
18590 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18591 receiver = parse_variable_call(parser);
18593 pm_parser_scope_push(parser,
true);
18594 lex_state_set(parser, PM_LEX_STATE_FNAME);
18595 parser_lex(parser);
18597 operator = parser->previous;
18598 name = parse_method_definition_name(parser);
18600 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
18601 pm_parser_scope_push(parser,
true);
18603 name = parser->previous;
18608 case PM_TOKEN_INSTANCE_VARIABLE:
18609 case PM_TOKEN_CLASS_VARIABLE:
18610 case PM_TOKEN_GLOBAL_VARIABLE:
18611 valid_name =
false;
18613 case PM_TOKEN_CONSTANT:
18614 case PM_TOKEN_KEYWORD_NIL:
18615 case PM_TOKEN_KEYWORD_SELF:
18616 case PM_TOKEN_KEYWORD_TRUE:
18617 case PM_TOKEN_KEYWORD_FALSE:
18618 case PM_TOKEN_KEYWORD___FILE__:
18619 case PM_TOKEN_KEYWORD___LINE__:
18620 case PM_TOKEN_KEYWORD___ENCODING__: {
18621 pm_parser_scope_push(parser,
true);
18622 parser_lex(parser);
18626 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18627 lex_state_set(parser, PM_LEX_STATE_FNAME);
18628 parser_lex(parser);
18629 operator = parser->previous;
18631 switch (identifier.
type) {
18632 case PM_TOKEN_CONSTANT:
18633 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18635 case PM_TOKEN_INSTANCE_VARIABLE:
18636 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18638 case PM_TOKEN_CLASS_VARIABLE:
18639 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18641 case PM_TOKEN_GLOBAL_VARIABLE:
18642 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18644 case PM_TOKEN_KEYWORD_NIL:
18645 receiver = UP(pm_nil_node_create(parser, &identifier));
18647 case PM_TOKEN_KEYWORD_SELF:
18648 receiver = UP(pm_self_node_create(parser, &identifier));
18650 case PM_TOKEN_KEYWORD_TRUE:
18651 receiver = UP(pm_true_node_create(parser, &identifier));
18653 case PM_TOKEN_KEYWORD_FALSE:
18654 receiver = UP(pm_false_node_create(parser, &identifier));
18656 case PM_TOKEN_KEYWORD___FILE__:
18657 receiver = UP(pm_source_file_node_create(parser, &identifier));
18659 case PM_TOKEN_KEYWORD___LINE__:
18660 receiver = UP(pm_source_line_node_create(parser, &identifier));
18662 case PM_TOKEN_KEYWORD___ENCODING__:
18663 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18669 name = parse_method_definition_name(parser);
18672 PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.
type));
18679 case PM_TOKEN_PARENTHESIS_LEFT: {
18683 context_pop(parser);
18684 parser_lex(parser);
18687 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));
18689 accept1(parser, PM_TOKEN_NEWLINE);
18690 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18693 lex_state_set(parser, PM_LEX_STATE_FNAME);
18694 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18696 operator = parser->previous;
18697 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18701 pm_parser_scope_push(parser,
true);
18702 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18703 name = parse_method_definition_name(parser);
18707 pm_parser_scope_push(parser,
true);
18708 name = parse_method_definition_name(parser);
18716 bool accept_endless_def =
true;
18717 switch (parser->current.type) {
18718 case PM_TOKEN_PARENTHESIS_LEFT: {
18719 parser_lex(parser);
18720 lparen = parser->previous;
18722 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18726 bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
18727 params = parse_parameters(
18729 PM_BINDING_POWER_DEFINED,
18731 allow_trailing_comma,
18735 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18736 (uint16_t) (depth + 1)
18740 lex_state_set(parser, PM_LEX_STATE_BEG);
18741 parser->command_start =
true;
18743 context_pop(parser);
18744 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18745 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
18746 parser->previous.
start = parser->previous.
end;
18747 parser->previous.
type = 0;
18750 rparen = parser->previous;
18753 case PM_CASE_PARAMETER: {
18756 if (parser->current.type == PM_TOKEN_LABEL) {
18757 lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
18760 params = parse_parameters(
18762 PM_BINDING_POWER_DEFINED,
18768 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18769 (uint16_t) (depth + 1)
18774 accept_endless_def =
false;
18776 context_pop(parser);
18781 context_pop(parser);
18790 if (accept1(parser, PM_TOKEN_EQUAL)) {
18791 if (token_is_setter_name(&name)) {
18792 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18794 if (!accept_endless_def) {
18795 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18798 parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
18799 parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
18801 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");
18803 equal = parser->previous;
18805 context_push(parser, PM_CONTEXT_DEF);
18806 pm_do_loop_stack_push(parser,
false);
18807 statements = UP(pm_statements_node_create(parser));
18809 uint8_t allow_flags;
18810 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
18811 allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
18815 allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18828 pm_accepts_block_stack_push(parser,
true);
18829 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));
18836 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18837 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18838 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18845 while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18846 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18848 pm_token_t rescue_keyword = parser->previous;
18852 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));
18853 context_pop(parser);
18855 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18858 pm_accepts_block_stack_pop(parser);
18863 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(parser, statement)) {
18864 PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18867 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18868 pm_do_loop_stack_pop(parser);
18869 context_pop(parser);
18871 if (lparen.
start == NULL) {
18872 lex_state_set(parser, PM_LEX_STATE_BEG);
18873 parser->command_start =
true;
18874 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18876 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18879 pm_accepts_block_stack_push(parser,
true);
18880 pm_do_loop_stack_push(parser,
false);
18882 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18883 pm_accepts_block_stack_push(parser,
true);
18884 statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18885 pm_accepts_block_stack_pop(parser);
18888 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18889 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18890 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)));
18892 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18895 pm_accepts_block_stack_pop(parser);
18896 pm_do_loop_stack_pop(parser);
18898 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18899 end_keyword = parser->previous;
18903 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18904 pm_parser_scope_pop(parser);
18909 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
18911 flush_block_exits(parser, previous_block_exits);
18913 return UP(pm_def_node_create(
18922 NTOK2PTR(
operator),
18926 NTOK2PTR(end_keyword)
18934parse_module(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18936 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18938 size_t opening_newline_index = token_newline_index(parser);
18939 parser_lex(parser);
18940 pm_token_t module_keyword = parser->previous;
18942 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));
18947 if (PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18948 pop_block_exits(parser, previous_block_exits);
18951 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
18954 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
18957 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18958 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
18964 name = parser->previous;
18965 if (name.
type != PM_TOKEN_CONSTANT) {
18966 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
18969 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)) {
18970 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18973 pm_parser_scope_push(parser,
true);
18974 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
18977 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18978 pm_accepts_block_stack_push(parser,
true);
18979 statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
18980 pm_accepts_block_stack_pop(parser);
18983 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18984 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18985 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)));
18987 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
18991 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18993 pm_parser_scope_pop(parser);
18994 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
18996 if (context_def_p(parser)) {
18997 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19000 pop_block_exits(parser, previous_block_exits);
19002 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
19010parse_parentheses(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19012 pm_node_flags_t paren_flags = 0;
19015 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19017 parser_lex(parser);
19019 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19020 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19021 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19028 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
19032 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT) && opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19033 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19036 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19037 pop_block_exits(parser, previous_block_exits);
19038 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
19043 context_push(parser, PM_CONTEXT_PARENS);
19044 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));
19045 context_pop(parser);
19050 bool terminator_found =
false;
19052 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19053 terminator_found =
true;
19054 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19055 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
19056 terminator_found =
true;
19059 if (terminator_found) {
19061 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19062 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19063 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19071 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19072 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19073 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19076 parser_lex(parser);
19077 pop_block_exits(parser, previous_block_exits);
19079 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19085 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
19088 multi_target = pm_multi_target_node_create(parser);
19089 pm_multi_target_node_targets_append(parser, multi_target, statement);
19092 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
19093 multi_target->
rparen_loc = TOK2LOC(parser, &parser->previous);
19094 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
19095 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
19098 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
19099 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19100 accept1(parser, PM_TOKEN_NEWLINE);
19102 result = UP(multi_target);
19105 if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
19107 }
else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match2(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_COMMA)) {
19111 }
else if (flags & PM_PARSE_ACCEPTS_STATEMENT) {
19115 if (pm_binding_powers[parser->current.type].binary && !match1(parser, PM_TOKEN_EQUAL)) {
19116 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19118 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
19121 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19122 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
19125 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19135 pm_statements_node_body_append(parser, statements, statement,
true);
19137 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19143 context_push(parser, PM_CONTEXT_PARENS);
19144 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19147 pm_statements_node_body_append(parser, statements, statement,
true);
19151 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
19152 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19157 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));
19158 pm_statements_node_body_append(parser, statements, node,
true);
19162 if (parser->recovering) {
19165 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering =
false;
19171 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE))
break;
19175 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19176 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
19177 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
19178 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19180 }
else if (!match1(parser, PM_TOKEN_EOF)) {
19183 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19187 context_pop(parser);
19188 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19197 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19199 pm_multi_target_node_targets_append(parser, multi_target, statement);
19201 statement = UP(multi_target);
19205 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
19206 const uint8_t *offset = parser->start + PM_NODE_END(statement);
19207 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
19208 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
19210 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
19213 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
19217 pop_block_exits(parser, previous_block_exits);
19218 pm_void_statements_check(parser, statements,
true);
19219 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19228parse_splat(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19232 if (token_begins_expression_p(parser->current.type)) {
19233 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19236 return UP(pm_splat_node_create(parser, &
operator, name));
19244 pm_hash_key_static_literals_add(parser, &hash_keys, key);
19247 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
19248 operator = parser->previous;
19251 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));
19252 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
19253 pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
19255 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19256 parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
19259 pm_static_literals_free(&hash_keys);
19264parse_array(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19265 pm_array_node_t *array = pm_array_node_create(parser, &parser->current);
19266 parser_lex(parser);
19268 bool parsed_bare_hash =
false;
19269 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
19270 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
19274 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19280 if (accept1(parser, PM_TOKEN_COMMA)) {
19283 if (accepted_newline) {
19284 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
19289 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
19290 parser->previous.
start = parser->previous.
end;
19291 parser->previous.
type = 0;
19298 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
19302 if (accept1(parser, PM_TOKEN_USTAR)) {
19306 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
19307 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
19309 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));
19312 element = UP(pm_splat_node_create(parser, &
operator, expression));
19313 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
19314 if (parsed_bare_hash) {
19315 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
19318 element = UP(pm_keyword_hash_node_create(parser));
19321 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)) {
19322 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19325 pm_static_literals_free(&hash_keys);
19326 parsed_bare_hash =
true;
19328 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));
19330 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
19331 if (parsed_bare_hash) {
19332 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
19335 element = UP(parse_array_keyword_hash(parser, element, flags, depth));
19336 parsed_bare_hash =
true;
19340 pm_array_node_elements_append(parser->arena, array, element);
19341 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
19344 accept1(parser, PM_TOKEN_NEWLINE);
19346 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19347 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
19348 parser->previous.
start = parser->previous.
end;
19349 parser->previous.
type = 0;
19352 pm_array_node_close_set(parser, array, &parser->previous);
19360 parser_lex(parser);
19362 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
19364 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
19365 pm_static_literals_free(&hash_keys);
19367 accept1(parser, PM_TOKEN_NEWLINE);
19370 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
19371 pm_hash_node_closing_loc_set(parser, node, &parser->previous);
19376parse_heredoc(
pm_parser_t *parser, uint16_t depth) {
19377 assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
19380 size_t common_whitespace = (size_t) -1;
19381 parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
19383 parser_lex(parser);
19389 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19392 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19393 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
19395 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19396 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19398 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19401 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
19402 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
19409 node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19410 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19415 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
19419 cast->
closing_loc = TOK2LOC(parser, &parser->current);
19422 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19424 cast->
base.
type = PM_X_STRING_NODE;
19427 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19428 parse_heredoc_dedent_string(parser->arena, &cast->
unescaped, common_whitespace);
19432 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19438 pm_node_list_append(parser->arena, &parts, part);
19440 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19441 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19442 pm_node_list_append(parser->arena, &parts, part);
19448 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19450 cast->
parts = parts;
19452 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19453 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
19460 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19461 pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
19469 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19471 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19477 parse_heredoc_dedent(parser, nodes, common_whitespace);
19485 pm_lex_mode_t *whitespace_mode = parser->lex_modes.current;
19487 if (whitespace_mode->mode == PM_LEX_HEREDOC && whitespace_mode->as.heredoc.common_whitespace == &common_whitespace) {
19488 whitespace_mode->as.heredoc.common_whitespace = NULL;
19490 whitespace_mode = whitespace_mode->prev;
19491 }
while (whitespace_mode != NULL);
19493 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19494 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19501parse_begin(
pm_parser_t *parser, uint16_t depth) {
19503 size_t opening_newline_index = token_newline_index(parser);
19504 parser_lex(parser);
19506 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19509 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19512 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19513 pm_accepts_block_stack_push(parser,
true);
19514 begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19515 pm_accepts_block_stack_pop(parser);
19516 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19519 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19520 parse_rescues(parser, opening_newline_index, &begin_keyword, node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19521 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
19523 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->previous);
19524 pm_begin_node_end_keyword_set(parser, node, &parser->previous);
19525 pop_block_exits(parser, previous_block_exits);
19530parse_defined(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19532 parser_lex(parser);
19538 context_push(parser, PM_CONTEXT_DEFINED);
19539 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19541 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
19542 lparen = parser->previous;
19544 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19545 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
19548 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));
19550 if (!parser->recovering) {
19551 accept1(parser, PM_TOKEN_NEWLINE);
19552 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19553 rparen = parser->previous;
19557 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19560 context_pop(parser);
19561 return pm_defined_node_create(parser, NTOK2PTR(lparen), expression, NTOK2PTR(rparen), &keyword);
19565parse_for(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19567 size_t opening_newline_index = token_newline_index(parser);
19568 parser_lex(parser);
19571 context_push(parser, PM_CONTEXT_FOR_INDEX);
19574 if (accept1(parser, PM_TOKEN_USTAR)) {
19575 index = parse_splat(parser, flags, depth);
19576 }
else if (token_begins_expression_p(parser->current.type)) {
19577 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19579 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19580 index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
19584 if (match1(parser, PM_TOKEN_COMMA)) {
19585 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19587 index = parse_target(parser, index,
false,
false);
19590 context_pop(parser);
19591 pm_do_loop_stack_push(parser,
true);
19593 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19596 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));
19597 pm_do_loop_stack_pop(parser);
19600 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19601 do_keyword = parser->previous;
19603 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19604 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
19609 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19610 statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19613 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19614 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19616 return pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous);
19620parse_lambda(
pm_parser_t *parser, uint16_t depth) {
19621 int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
19622 parser->lambda_enclosure_nesting = parser->enclosure_nesting;
19625 size_t opening_newline_index = token_newline_index(parser);
19626 parser_lex(parser);
19628 pm_parser_scope_push(parser,
false);
19631 switch (parser->current.type) {
19632 case PM_TOKEN_PARENTHESIS_LEFT: {
19634 parser_lex(parser);
19636 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19637 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
19639 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
19642 accept1(parser, PM_TOKEN_NEWLINE);
19643 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19645 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
19648 case PM_CASE_PARAMETER: {
19649 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
19653 block_parameters = NULL;
19661 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
19662 opening = parser->previous;
19664 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
19665 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
19668 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
19675 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
19676 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
19683 pm_accepts_block_stack_push(parser,
true);
19684 expect1(parser, PM_TOKEN_KEYWORD_DO_LAMBDA, PM_ERR_LAMBDA_OPEN);
19685 opening = parser->previous;
19691 parser->lambda_enclosure_nesting = -1;
19693 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19694 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
19697 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19698 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
19699 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)));
19701 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
19704 pm_accepts_block_stack_pop(parser);
19708 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
19709 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
19713 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
19714 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->previous);
19716 pm_parser_scope_pop(parser);
19717 return pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->previous, parameters, body);
19721parse_regexp(
pm_parser_t *parser, uint16_t depth) {
19723 parser_lex(parser);
19725 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19730 .
type = PM_TOKEN_STRING_CONTENT,
19731 .start = parser->previous.
end,
19732 .end = parser->previous.
end
19735 parser_lex(parser);
19738 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
19744 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19751 parser_lex(parser);
19756 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19763 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19764 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
19772 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19774 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
19775 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
19779 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19782 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
19787 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19793 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19794 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19795 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
19800 if (match1(parser, PM_TOKEN_EOF)) {
19801 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19802 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19804 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19807 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19808 return UP(interpolated);
19812parse_alias(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19813 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
19814 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
19818 parser_lex(parser);
19820 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
19821 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
19823 switch (PM_NODE_TYPE(new_name)) {
19824 case PM_BACK_REFERENCE_READ_NODE:
19825 case PM_NUMBERED_REFERENCE_READ_NODE:
19826 case PM_GLOBAL_VARIABLE_READ_NODE: {
19827 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)) {
19828 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
19829 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
19831 }
else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
19832 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19833 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19836 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
19838 case PM_SYMBOL_NODE:
19839 case PM_INTERPOLATED_SYMBOL_NODE: {
19840 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)) {
19841 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19842 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19847 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
19852parse_until(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19854 size_t opening_newline_index = token_newline_index(parser);
19856 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
19857 pm_do_loop_stack_push(parser,
true);
19859 parser_lex(parser);
19860 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));
19862 pm_do_loop_stack_pop(parser);
19863 context_pop(parser);
19866 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19867 do_keyword = parser->previous;
19869 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19873 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19874 pm_accepts_block_stack_push(parser,
true);
19875 statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19876 pm_accepts_block_stack_pop(parser);
19877 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19880 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19881 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
19883 return pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0);
19887parse_while(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19889 size_t opening_newline_index = token_newline_index(parser);
19891 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
19892 pm_do_loop_stack_push(parser,
true);
19894 parser_lex(parser);
19895 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));
19897 pm_do_loop_stack_pop(parser);
19898 context_pop(parser);
19901 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19902 do_keyword = parser->previous;
19904 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19908 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19909 pm_accepts_block_stack_push(parser,
true);
19910 statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19911 pm_accepts_block_stack_pop(parser);
19912 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19915 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19916 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
19918 return pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0);
19922parse_xstring(
pm_parser_t *parser, uint16_t depth) {
19924 parser_lex(parser);
19930 if (match1(parser, PM_TOKEN_STRING_END)) {
19935 .
type = PM_TOKEN_STRING_CONTENT,
19936 .start = parser->previous.
end,
19937 .end = parser->previous.
end
19940 parser_lex(parser);
19941 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
19946 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19953 parser_lex(parser);
19955 if (match1(parser, PM_TOKEN_STRING_END)) {
19956 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
19957 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
19958 parser_lex(parser);
19964 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19966 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
19967 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
19969 pm_interpolated_xstring_node_append(parser->arena, node, part);
19974 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19978 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19979 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19980 pm_interpolated_xstring_node_append(parser->arena, node, part);
19985 if (match1(parser, PM_TOKEN_EOF)) {
19986 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
19987 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19989 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
19991 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
19997parse_multi_target(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t binding_power, uint16_t depth) {
19998 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
20001 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20007parse_identifier(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20009 parser_lex(parser);
20011 pm_node_t *node = parse_variable_call(parser);
20013 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
20021 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
20024 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
20033 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
20035 PM_NODE_LENGTH_SET_LOCATION(call, end);
20043 ((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))) ||
20044 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
20045 match1(parser, PM_TOKEN_BRACE_LEFT)
20048 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20049 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
20051 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20055 pm_node_unreference(parser, node);
20061 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
20063 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
20064 pm_node_unreference(parser, node);
20067 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20075 return parse_multi_target(parser, node, binding_power, depth);
20079parse_uninterpolated_symbol_array(
pm_parser_t *parser) {
20081 parser_lex(parser);
20086 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20087 accept1(parser, PM_TOKEN_WORDS_SEP);
20088 if (match1(parser, PM_TOKEN_STRING_END))
break;
20092 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20094 if (current == NULL) {
20095 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20096 parser_lex(parser);
20097 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20098 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20099 parser_lex(parser);
20101 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20104 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20105 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20106 parser_lex(parser);
20109 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20110 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20113 current = UP(interpolated);
20115 assert(
false &&
"unreachable");
20120 pm_array_node_elements_append(parser->arena, array, current);
20123 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20128 if (match1(parser, PM_TOKEN_EOF)) {
20129 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20130 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20132 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20134 pm_array_node_close_set(parser, array, &closing);
20140parse_interpolated_symbol_array(
pm_parser_t *parser, uint16_t depth) {
20141 parser_lex(parser);
20149 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20150 switch (parser->current.type) {
20151 case PM_TOKEN_WORDS_SEP: {
20154 parser->explicit_encoding = NULL;
20156 if (current == NULL) {
20163 pm_array_node_elements_append(parser->arena, array, current);
20167 parser_lex(parser);
20170 case PM_TOKEN_STRING_CONTENT: {
20171 if (current == NULL) {
20176 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20177 parser_lex(parser);
20178 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20182 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20183 parser_lex(parser);
20186 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20193 .
type = PM_TOKEN_STRING_CONTENT,
20198 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20199 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20200 parser_lex(parser);
20203 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20204 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20206 current = UP(interpolated);
20208 assert(
false &&
"unreachable");
20213 case PM_TOKEN_EMBVAR: {
20214 bool start_location_set =
false;
20215 if (current == NULL) {
20219 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
20220 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20227 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
20228 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
20229 PM_NODE_START_SET_NODE(interpolated, current);
20230 start_location_set =
true;
20231 current = UP(interpolated);
20238 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20240 if (!start_location_set) {
20241 PM_NODE_START_SET_NODE(current, part);
20245 case PM_TOKEN_EMBEXPR_BEGIN: {
20246 bool start_location_set =
false;
20247 if (current == NULL) {
20251 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
20252 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20259 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
20260 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
20261 PM_NODE_START_SET_NODE(interpolated, current);
20262 start_location_set =
true;
20263 current = UP(interpolated);
20264 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20268 assert(
false &&
"unreachable");
20271 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20273 if (!start_location_set) {
20274 PM_NODE_START_SET_NODE(current, part);
20279 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
20280 parser_lex(parser);
20287 pm_array_node_elements_append(parser->arena, array, current);
20291 if (match1(parser, PM_TOKEN_EOF)) {
20292 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20293 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20295 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
20297 pm_array_node_close_set(parser, array, &closing);
20303parse_uninterpolated_string_array(
pm_parser_t *parser) {
20305 parser_lex(parser);
20310 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20311 accept1(parser, PM_TOKEN_WORDS_SEP);
20312 if (match1(parser, PM_TOKEN_STRING_END))
break;
20316 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20317 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20320 if (current == NULL) {
20322 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20324 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20326 pm_interpolated_string_node_append(parser, interpolated, current);
20327 pm_interpolated_string_node_append(parser, interpolated,
string);
20328 current = UP(interpolated);
20330 assert(
false &&
"unreachable");
20332 parser_lex(parser);
20336 pm_array_node_elements_append(parser->arena, array, current);
20339 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20344 if (match1(parser, PM_TOKEN_EOF)) {
20345 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20346 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20348 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20351 pm_array_node_close_set(parser, array, &closing);
20356parse_interpolated_string_array(
pm_parser_t *parser, uint16_t depth) {
20358 parser_lex(parser);
20363 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20364 switch (parser->current.type) {
20365 case PM_TOKEN_WORDS_SEP: {
20368 parser->explicit_encoding = NULL;
20370 if (current == NULL) {
20377 pm_array_node_elements_append(parser->arena, array, current);
20381 parser_lex(parser);
20384 case PM_TOKEN_STRING_CONTENT: {
20385 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20386 pm_node_flag_set(
string, parse_unescaped_encoding(parser, parser->explicit_encoding));
20387 parser_lex(parser);
20389 if (current == NULL) {
20395 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20400 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20406 pm_interpolated_string_node_append(parser, interpolated, current);
20407 pm_interpolated_string_node_append(parser, interpolated,
string);
20408 current = UP(interpolated);
20410 assert(
false &&
"unreachable");
20415 case PM_TOKEN_EMBVAR: {
20416 if (current == NULL) {
20420 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
20421 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20427 pm_interpolated_string_node_append(parser, interpolated, current);
20428 current = UP(interpolated);
20435 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20439 case PM_TOKEN_EMBEXPR_BEGIN: {
20440 if (current == NULL) {
20444 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
20445 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20451 pm_interpolated_string_node_append(parser, interpolated, current);
20452 current = UP(interpolated);
20453 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20457 assert(
false &&
"unreachable");
20460 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20465 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
20466 parser_lex(parser);
20473 pm_array_node_elements_append(parser->arena, array, current);
20477 if (match1(parser, PM_TOKEN_EOF)) {
20478 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20479 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20481 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
20484 pm_array_node_close_set(parser, array, &closing);
20489parse_jump(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20490 parser_lex(parser);
20495 if (token_begins_expression_p(parser->current.type) || match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)) {
20496 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
20498 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
20500 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
20503 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
20504 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.
type));
20513 if (parser->previous.
type == PM_TOKEN_COMMA && match1(parser, PM_TOKEN_EOF)) {
20514 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
20521 if (arguments.
block != NULL) {
20522 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20523 pm_node_unreference(parser, arguments.
block);
20524 arguments.
block = NULL;
20528 switch (keyword.
type) {
20529 case PM_TOKEN_KEYWORD_BREAK: {
20531 if (!parser->partial_script) ensure_valid_jump(parser, node);
20534 case PM_TOKEN_KEYWORD_NEXT: {
20536 if (!parser->partial_script) ensure_valid_jump(parser, node);
20539 case PM_TOKEN_KEYWORD_RETURN: {
20541 ensure_valid_return(parser, node);
20545 assert(
false &&
"unreachable");
20546 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20551parse_not(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20553 parser_lex(parser);
20564 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
20565 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
20566 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
20568 accept1(parser, PM_TOKEN_NEWLINE);
20569 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
20572 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
20575 accept1(parser, PM_TOKEN_NEWLINE);
20577 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20580 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20581 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20583 arguments.
opening_loc = TOK2LOC(parser, &lparen);
20584 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));
20586 if (!parser->recovering) {
20587 accept1(parser, PM_TOKEN_NEWLINE);
20588 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20589 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
20593 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));
20596 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
20600parse_preexe(
pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
20602 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20604 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20605 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
20609 parser_lex(parser);
20611 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
20613 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
20615 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
20616 pm_context_t context = parser->current_context->context;
20617 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
20618 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
20621 flush_block_exits(parser, previous_block_exits);
20622 return pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
20626parse_postexe(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20627 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20628 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
20632 parser_lex(parser);
20634 if (context_def_p(parser)) {
20635 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
20638 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
20640 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
20642 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
20643 return pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
20647parse_undef(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20648 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20649 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
20652 parser_lex(parser);
20653 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
20654 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20656 if (!PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20657 pm_undef_node_append(parser->arena, undef, name);
20659 while (match1(parser, PM_TOKEN_COMMA)) {
20660 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
20661 parser_lex(parser);
20663 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20664 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20668 pm_undef_node_append(parser->arena, undef, name);
20676parse_yield(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20678 parser_lex(parser);
20681 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
20686 if (arguments.
block != NULL) {
20687 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20688 pm_node_unreference(parser, arguments.
block);
20689 arguments.
block = NULL;
20693 if (!parser->parsing_eval && !parser->partial_script) ensure_valid_yield(parser, node);
20700 pm_node_t *node = UP(pm_string_node_create_current_string(
20703 .type = PM_TOKEN_STRING_BEGIN,
20704 .start = parser->current.start,
20705 .end = parser->current.start + 1
20708 .type = PM_TOKEN_STRING_CONTENT,
20709 .start = parser->current.start + 1,
20710 .end = parser->current.end
20715 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
20719 parser_lex(parser);
20723 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
20724 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
20731parse_constant(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20733 parser_lex(parser);
20738 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
20739 ((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))) ||
20740 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
20741 match1(parser, PM_TOKEN_BRACE_LEFT)
20744 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20745 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
20748 return parse_multi_target(parser, UP(pm_constant_read_node_create(parser, &parser->previous)), binding_power, depth);
20752parse_constant_path_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
20754 parser_lex(parser);
20756 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
20757 return parse_multi_target(parser, UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous)), binding_power, depth);
20761parse_unary_plus(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20762 if (binding_power > PM_BINDING_POWER_UNARY) {
20763 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20765 parser_lex(parser);
20768 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));
20769 return pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20773parse_unary_minus(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20774 if (binding_power > PM_BINDING_POWER_UNARY) {
20775 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20777 parser_lex(parser);
20780 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));
20781 return pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20785parse_unary_minus_number(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20787 parser_lex(parser);
20789 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));
20791 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20792 pm_token_t exponent_operator = parser->previous;
20793 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));
20794 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20795 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20797 switch (PM_NODE_TYPE(node)) {
20798 case PM_INTEGER_NODE:
20799 case PM_FLOAT_NODE:
20800 case PM_RATIONAL_NODE:
20801 case PM_IMAGINARY_NODE:
20802 parse_negative_numeric(node);
20805 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20814parse_unary_star(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
20815 parser_lex(parser);
20820 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20821 pm_parser_err_prefix(parser, diag_id);
20822 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20825 pm_node_t *splat = parse_splat(parser, flags, depth);
20827 if (match1(parser, PM_TOKEN_COMMA)) {
20828 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20830 return parse_target_validate(parser, splat,
true);
20835parse_super(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20837 parser_lex(parser);
20840 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20845 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
20847 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
20850 return UP(pm_super_node_create(parser, &keyword, &arguments));
20854parse_range(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20856 parser_lex(parser);
20858 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));
20863 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
20864 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
20867 return pm_range_node_create(parser, NULL, &
operator, right);
20871parse_bang(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20872 if (binding_power > PM_BINDING_POWER_UNARY) {
20873 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20876 parser_lex(parser);
20879 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));
20880 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20881 return pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20885parse_tilde(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20886 if (binding_power > PM_BINDING_POWER_UNARY) {
20887 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20890 parser_lex(parser);
20893 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));
20894 return pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20901parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
20902 switch (parser->current.type) {
20903 case PM_TOKEN_BRACKET_LEFT_ARRAY:
20904 return UP(parse_array(parser, flags, depth));
20905 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
20906 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
20907 return parse_parentheses(parser, binding_power, flags, depth);
20908 case PM_TOKEN_BRACE_LEFT_HASH:
20909 return UP(parse_hash(parser, depth));
20910 case PM_TOKEN_CHARACTER_LITERAL:
20911 return parse_char(parser, depth);
20912 case PM_TOKEN_CONSTANT:
20913 return parse_constant(parser, binding_power, flags, depth);
20914 case PM_TOKEN_UCOLON_COLON:
20915 return parse_constant_path_prefix(parser, binding_power, depth);
20916 case PM_TOKEN_UDOT_DOT:
20917 case PM_TOKEN_UDOT_DOT_DOT:
20918 return UP(parse_range(parser, flags, depth));
20919 case PM_TOKEN_FLOAT:
20920 parser_lex(parser);
20921 return UP(pm_float_node_create(parser, &parser->previous));
20922 case PM_TOKEN_FLOAT_IMAGINARY:
20923 parser_lex(parser);
20924 return UP(pm_float_node_imaginary_create(parser, &parser->previous));
20925 case PM_TOKEN_FLOAT_RATIONAL:
20926 parser_lex(parser);
20927 return UP(pm_float_node_rational_create(parser, &parser->previous));
20928 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
20929 parser_lex(parser);
20930 return UP(pm_float_node_rational_imaginary_create(parser, &parser->previous));
20931 case PM_TOKEN_IDENTIFIER:
20932 case PM_TOKEN_METHOD_NAME:
20933 return parse_identifier(parser, binding_power, flags, depth);
20934 case PM_TOKEN_HEREDOC_START:
20935 return parse_heredoc(parser, depth);
20936 case PM_TOKEN_CLASS_VARIABLE:
20937 parser_lex(parser);
20938 return parse_multi_target(parser, UP(pm_class_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
20939 case PM_TOKEN_NUMBERED_REFERENCE:
20940 parser_lex(parser);
20941 return parse_multi_target(parser, UP(pm_numbered_reference_read_node_create(parser, &parser->previous)), binding_power, depth);
20942 case PM_TOKEN_GLOBAL_VARIABLE:
20943 parser_lex(parser);
20944 return parse_multi_target(parser, UP(pm_global_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
20945 case PM_TOKEN_BACK_REFERENCE:
20946 parser_lex(parser);
20947 return parse_multi_target(parser, UP(pm_back_reference_read_node_create(parser, &parser->previous)), binding_power, depth);
20948 case PM_TOKEN_INSTANCE_VARIABLE:
20949 parser_lex(parser);
20950 return parse_multi_target(parser, UP(pm_instance_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
20951 case PM_TOKEN_INTEGER: {
20952 pm_node_flags_t base = parser->integer.base;
20953 parser_lex(parser);
20954 return UP(pm_integer_node_create(parser, base, &parser->previous));
20956 case PM_TOKEN_INTEGER_IMAGINARY: {
20957 pm_node_flags_t base = parser->integer.base;
20958 parser_lex(parser);
20959 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
20961 case PM_TOKEN_INTEGER_RATIONAL: {
20962 pm_node_flags_t base = parser->integer.base;
20963 parser_lex(parser);
20964 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
20966 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
20967 pm_node_flags_t base = parser->integer.base;
20968 parser_lex(parser);
20969 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
20971 case PM_TOKEN_KEYWORD___ENCODING__:
20972 parser_lex(parser);
20973 return UP(pm_source_encoding_node_create(parser, &parser->previous));
20974 case PM_TOKEN_KEYWORD___FILE__:
20975 parser_lex(parser);
20976 return UP(pm_source_file_node_create(parser, &parser->previous));
20977 case PM_TOKEN_KEYWORD___LINE__:
20978 parser_lex(parser);
20979 return UP(pm_source_line_node_create(parser, &parser->previous));
20980 case PM_TOKEN_KEYWORD_ALIAS:
20981 return parse_alias(parser, binding_power, flags, depth);
20982 case PM_TOKEN_KEYWORD_CASE:
20983 return parse_case(parser, flags, depth);
20984 case PM_TOKEN_KEYWORD_BEGIN:
20985 return UP(parse_begin(parser, depth));
20986 case PM_TOKEN_KEYWORD_BEGIN_UPCASE:
20987 return UP(parse_preexe(parser, binding_power, depth));
20988 case PM_TOKEN_KEYWORD_BREAK:
20989 case PM_TOKEN_KEYWORD_NEXT:
20990 case PM_TOKEN_KEYWORD_RETURN:
20991 return parse_jump(parser, flags, depth);
20992 case PM_TOKEN_KEYWORD_SUPER:
20993 return parse_super(parser, flags, depth);
20994 case PM_TOKEN_KEYWORD_YIELD:
20995 return UP(parse_yield(parser, flags, depth));
20996 case PM_TOKEN_KEYWORD_CLASS:
20997 return parse_class(parser, flags, depth);
20998 case PM_TOKEN_KEYWORD_DEF:
20999 return parse_def(parser, binding_power, flags, depth);
21000 case PM_TOKEN_KEYWORD_DEFINED:
21001 return UP(parse_defined(parser, flags, depth));
21002 case PM_TOKEN_KEYWORD_END_UPCASE:
21003 return UP(parse_postexe(parser, binding_power, flags, depth));
21004 case PM_TOKEN_KEYWORD_FALSE:
21005 parser_lex(parser);
21006 return UP(pm_false_node_create(parser, &parser->previous));
21007 case PM_TOKEN_KEYWORD_FOR:
21008 return UP(parse_for(parser, flags, depth));
21009 case PM_TOKEN_KEYWORD_IF:
21010 if (parser_end_of_line_p(parser)) {
21011 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
21014 size_t opening_newline_index = token_newline_index(parser);
21015 bool if_after_else = parser->previous.
type == PM_TOKEN_KEYWORD_ELSE;
21016 parser_lex(parser);
21018 return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
21019 case PM_TOKEN_KEYWORD_UNDEF:
21020 return UP(parse_undef(parser, binding_power, flags, depth));
21021 case PM_TOKEN_KEYWORD_NOT:
21022 return parse_not(parser, binding_power, flags, depth);
21023 case PM_TOKEN_KEYWORD_UNLESS: {
21024 size_t opening_newline_index = token_newline_index(parser);
21025 parser_lex(parser);
21027 return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
21029 case PM_TOKEN_KEYWORD_MODULE:
21030 return parse_module(parser, flags, depth);
21031 case PM_TOKEN_KEYWORD_NIL:
21032 parser_lex(parser);
21033 return UP(pm_nil_node_create(parser, &parser->previous));
21034 case PM_TOKEN_KEYWORD_REDO: {
21035 parser_lex(parser);
21037 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
21038 if (!parser->partial_script) ensure_valid_jump(parser, node);
21042 case PM_TOKEN_KEYWORD_RETRY: {
21043 parser_lex(parser);
21045 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
21046 ensure_valid_retry(parser, node);
21050 case PM_TOKEN_KEYWORD_SELF:
21051 parser_lex(parser);
21052 return UP(pm_self_node_create(parser, &parser->previous));
21053 case PM_TOKEN_KEYWORD_TRUE:
21054 parser_lex(parser);
21055 return UP(pm_true_node_create(parser, &parser->previous));
21056 case PM_TOKEN_KEYWORD_UNTIL:
21057 return UP(parse_until(parser, flags, depth));
21058 case PM_TOKEN_KEYWORD_WHILE:
21059 return UP(parse_while(parser, flags, depth));
21060 case PM_TOKEN_PERCENT_LOWER_I:
21061 return UP(parse_uninterpolated_symbol_array(parser));
21062 case PM_TOKEN_PERCENT_UPPER_I:
21063 return UP(parse_interpolated_symbol_array(parser, depth));
21064 case PM_TOKEN_PERCENT_LOWER_W:
21065 return UP(parse_uninterpolated_string_array(parser));
21066 case PM_TOKEN_PERCENT_UPPER_W:
21067 return UP(parse_interpolated_string_array(parser, depth));
21068 case PM_TOKEN_REGEXP_BEGIN:
21069 return parse_regexp(parser, depth);
21070 case PM_TOKEN_XSTRING_BEGIN:
21071 case PM_TOKEN_PERCENT_LOWER_X:
21072 return parse_xstring(parser, depth);
21073 case PM_TOKEN_USTAR:
21074 return parse_unary_star(parser, binding_power, flags, diag_id, depth);
21075 case PM_TOKEN_BANG:
21076 return UP(parse_bang(parser, binding_power, flags, depth));
21077 case PM_TOKEN_TILDE:
21078 return UP(parse_tilde(parser, binding_power, flags, depth));
21079 case PM_TOKEN_UMINUS:
21080 return UP(parse_unary_minus(parser, binding_power, flags, depth));
21081 case PM_TOKEN_UMINUS_NUM:
21082 return UP(parse_unary_minus_number(parser, flags, depth));
21083 case PM_TOKEN_MINUS_GREATER:
21084 return UP(parse_lambda(parser, depth));
21085 case PM_TOKEN_UPLUS:
21086 return UP(parse_unary_plus(parser, binding_power, flags, depth));
21087 case PM_TOKEN_STRING_BEGIN:
21088 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
21089 case PM_TOKEN_SYMBOL_BEGIN:
21090 return parse_symbol(parser, PM_LEX_STATE_END, (uint16_t) (depth + 1));
21092 pm_context_t recoverable = context_recoverable(parser, &parser->current);
21094 if (recoverable != PM_CONTEXT_NONE) {
21095 parser->recovering =
true;
21100 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
21101 pm_parser_err_prefix(parser, diag_id);
21107 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
21108 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
21112 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
21114 pm_parser_err_prefix(parser, diag_id);
21117 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
21123parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth);
21133parse_rescue_modifier_terminator(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
21134 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
21135 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21136 parser_lex(parser);
21137 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));
21151parse_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) {
21152 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));
21158 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(parser, value) || pm_block_call_p(value))) {
21159 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21160 parser_lex(parser);
21161 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));
21166 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21167 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21170 parser_lex(parser);
21175 bool statement_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21176 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21178 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21179 context_pop(parser);
21184 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21185 parse_rescue_modifier_terminator(parser, flags, depth);
21188 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21200 switch (PM_NODE_TYPE(node)) {
21201 case PM_BEGIN_NODE: {
21206 case PM_LOCAL_VARIABLE_WRITE_NODE: {
21208 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
21211 case PM_PARENTHESES_NODE: {
21213 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
21216 case PM_STATEMENTS_NODE: {
21221 parse_assignment_value_local(parser, statement);
21243parse_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) {
21244 bool statement_level = (previous_binding_power == PM_BINDING_POWER_STATEMENT) || (flags & PM_PARSE_ACCEPTS_STATEMENT);
21246 bool permitted =
true;
21247 if (!statement_level && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
21252 uint8_t command_call_flag = (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT)
21253 ? (uint8_t) (flags & PM_PARSE_ACCEPTS_COMMAND_CALL)
21254 : ((previous_binding_power < PM_BINDING_POWER_MODIFIER || statement_level) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0);
21256 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));
21257 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
21259 parse_assignment_value_local(parser, value);
21260 bool single_value =
true;
21265 if (statement_level && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
21266 single_value =
false;
21269 pm_array_node_elements_append(parser->arena, array, value);
21272 while (accept1(parser, PM_TOKEN_COMMA)) {
21273 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
21275 pm_array_node_elements_append(parser->arena, array, element);
21276 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
21278 parse_assignment_value_local(parser, element);
21286 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))) {
21287 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21288 parser_lex(parser);
21289 parse_expression(parser, pm_binding_powers[parser->previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21294 bool multiple_assignment = (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1));
21295 if ((single_value || multiple_assignment) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21296 bool command_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21305 if (multiple_assignment && command_value)
return value;
21307 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21310 parser_lex(parser);
21316 bool statement_value = multiple_assignment || command_value;
21317 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21319 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21320 context_pop(parser);
21325 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21326 parse_rescue_modifier_terminator(parser, flags, depth);
21329 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21348parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth) {
21353 if (match1(parser, PM_TOKEN_USTAR)) {
21355 parser_lex(parser);
21356 value = parse_splat(parser, flags, depth);
21363 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));
21364 multiple = match1(parser, PM_TOKEN_COMMA) || PM_NODE_TYPE_P(value, PM_MULTI_TARGET_NODE);
21368 pm_node_t *target = parse_targets_validate(parser, value, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21375 if (!match1(parser, PM_TOKEN_EQUAL)) {
21376 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
21381 parser_lex(parser);
21383 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));
21384 value = parse_write(parser, target, &
operator, values);
21391 if (!PM_NODE_TYPE_P(value, PM_MATCH_REQUIRED_NODE) && !PM_NODE_TYPE_P(value, PM_MATCH_PREDICATE_NODE)) {
21392 parse_rescue_modifier_terminator(parser, flags, depth);
21400 return parse_expression(parser, PM_BINDING_POWER_DEFINED, flags, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21413 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
21414 pm_node_unreference(parser, UP(call_node->
arguments));
21418 if (call_node->
block != NULL) {
21419 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
21420 pm_node_unreference(parser, UP(call_node->
block));
21421 call_node->
block = NULL;
21426pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21429 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21430 uint8_t value = escape_hexadecimal_digit(*cursor);
21433 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21434 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21438 pm_buffer_append_byte(unescaped, value);
21440 pm_buffer_append_string(unescaped,
"\\x", 2);
21447pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21448 uint8_t value = (uint8_t) (*cursor -
'0');
21451 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21452 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21455 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21456 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21461 pm_buffer_append_byte(unescaped, value);
21467 const uint8_t *start = cursor - 1;
21470 if (cursor >= end) {
21471 pm_buffer_append_string(unescaped,
"\\u", 2);
21475 if (*cursor !=
'{') {
21476 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21477 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21479 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21480 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21483 return cursor + length;
21488 while (cursor < end && *cursor ==
' ') cursor++;
21490 if (cursor >= end)
break;
21491 if (*cursor ==
'}') {
21496 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21500 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21502 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21510pm_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) {
21511 const uint8_t *end = source + length;
21512 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21515 if (++cursor >= end) {
21516 pm_buffer_append_byte(unescaped,
'\\');
21522 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21524 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21525 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21528 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
21531 pm_buffer_append_byte(unescaped,
'\\');
21535 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->encoding_changed, parser->encoding);
21536 if (next_cursor == NULL)
break;
21538 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21539 cursor = next_cursor;
21542 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21574 const uint8_t *source = pm_string_source(capture);
21575 size_t length = pm_string_length(capture);
21586 const uint8_t *cursor = pm_memchr(source,
'\\', length, parser->encoding_changed, parser->encoding);
21587 if (PRISM_UNLIKELY(cursor != NULL)) {
21588 pm_named_capture_escape(parser, &unescaped, source, length, cursor, name_data->
shared ? NULL : &call->receiver->location);
21595 if (pm_buffer_length(&unescaped) == 0)
return;
21597 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21598 length = pm_buffer_length(&unescaped);
21601 const uint8_t *start;
21602 const uint8_t *end;
21607 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21608 pm_buffer_cleanup(&unescaped);
21612 if (name_data->
shared) {
21616 end = source + length;
21617 name = pm_parser_constant_id_raw(parser, start, end);
21621 start = parser->start + PM_NODE_START(call->
receiver);
21622 end = parser->start + PM_NODE_END(call->
receiver);
21624 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
21625 memcpy(memory, source, length);
21626 name = pm_parser_constant_id_owned(parser, memory, length);
21633 if (name != 0 && pm_constant_id_set_insert(parser->arena, names, name)) {
21636 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21639 if (pm_local_is_keyword((
const char *) source, length)) {
21640 pm_buffer_cleanup(&unescaped);
21646 pm_parser_local_add(parser, name, start, end, 0);
21651 if (name_data->
match == NULL) {
21652 name_data->
match = pm_match_write_node_create(parser, call);
21657 pm_token_t token = { .type = 0, .start = start, .end = end };
21659 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &token_loc, name, depth == -1 ? 0 : (uint32_t) depth));
21660 pm_node_list_append(parser->arena, &name_data->
match->
targets, target);
21663 pm_buffer_cleanup(&unescaped);
21680 pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content), extended_mode, parse_regular_expression_named_capture, &name_data);
21682 if (name_data.
match != NULL) {
21683 return UP(name_data.
match);
21691 context_push(parser, PM_CONTEXT_TERNARY);
21693 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21696 parser_lex(parser);
21698 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));
21700 if (parser->recovering) {
21708 pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
21710 context_pop(parser);
21711 pop_block_exits(parser, previous_block_exits);
21712 return pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21715 accept1(parser, PM_TOKEN_NEWLINE);
21716 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21719 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));
21721 context_pop(parser);
21722 pop_block_exits(parser, previous_block_exits);
21723 return pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21727parse_constant_path_infix(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
21729 parser_lex(parser);
21731 switch (parser->current.type) {
21732 case PM_TOKEN_CONSTANT: {
21733 parser_lex(parser);
21737 (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21738 ((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)))
21749 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21750 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21754 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21757 return parse_multi_target(parser, path, previous_binding_power, depth);
21759 case PM_CASE_OPERATOR:
21760 case PM_CASE_KEYWORD:
21761 case PM_TOKEN_IDENTIFIER:
21762 case PM_TOKEN_METHOD_NAME: {
21763 parser_lex(parser);
21769 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21771 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21772 return parse_multi_target(parser, UP(call), previous_binding_power, depth);
21774 case PM_TOKEN_PARENTHESIS_LEFT: {
21778 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21780 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21783 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21784 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21789parse_match(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
21798 parser_lex(parser);
21800 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));
21803 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &
operator, argument, 0);
21808 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21815 bool interpolated =
false;
21816 size_t total_length = 0;
21820 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21821 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21823 interpolated =
true;
21828 if (!interpolated && total_length > 0) {
21829 void *memory =
xmalloc(total_length);
21830 if (!memory) abort();
21832 uint8_t *cursor = memory;
21835 size_t length = pm_string_length(unescaped);
21837 memcpy(cursor, pm_string_source(unescaped), length);
21842 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21844 result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21845 pm_string_cleanup(&owned);
21847 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21858 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
21860 if (name_data.
match != NULL) {
21861 result = UP(name_data.
match);
21869parse_equal(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
21872 switch (PM_NODE_TYPE(node)) {
21873 case PM_CALL_NODE: {
21879 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21880 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
21884 case PM_CASE_WRITABLE: {
21888 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21889 pm_parser_local_add_location(parser, &node->
location, 0);
21892 parser_lex(parser);
21893 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));
21895 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
21896 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21899 return parse_write(parser, node, &
operator, value);
21901 case PM_SPLAT_NODE: {
21903 pm_multi_target_node_targets_append(parser, multi_target, node);
21905 parser_lex(parser);
21906 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));
21907 return parse_write(parser, UP(multi_target), &
operator, value);
21909 case PM_SOURCE_ENCODING_NODE:
21910 case PM_FALSE_NODE:
21911 case PM_SOURCE_FILE_NODE:
21912 case PM_SOURCE_LINE_NODE:
21915 case PM_TRUE_NODE: {
21918 parser_lex(parser);
21919 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21920 return parse_unwriteable_write(parser, node, &
operator, value);
21926 parser_lex(parser);
21927 pm_parser_err_token(parser, &
operator, PM_ERR_EXPRESSION_NOT_WRITABLE);
21933parse_and_equal(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
21936 switch (PM_NODE_TYPE(node)) {
21937 case PM_BACK_REFERENCE_READ_NODE:
21938 case PM_NUMBERED_REFERENCE_READ_NODE:
21939 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21941 case PM_GLOBAL_VARIABLE_READ_NODE: {
21942 parser_lex(parser);
21944 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21945 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &
operator, value));
21949 case PM_CLASS_VARIABLE_READ_NODE: {
21950 parser_lex(parser);
21952 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21957 case PM_CONSTANT_PATH_NODE: {
21958 parser_lex(parser);
21960 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21963 return parse_shareable_constant_write(parser, write);
21965 case PM_CONSTANT_READ_NODE: {
21966 parser_lex(parser);
21968 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21971 if (context_def_p(parser)) {
21972 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21975 return parse_shareable_constant_write(parser, write);
21977 case PM_INSTANCE_VARIABLE_READ_NODE: {
21978 parser_lex(parser);
21980 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21985 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21987 parser_lex(parser);
21989 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21990 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &
operator, value, name, 0));
21992 pm_node_unreference(parser, node);
21995 case PM_LOCAL_VARIABLE_READ_NODE: {
21996 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21998 pm_node_unreference(parser, node);
22002 parser_lex(parser);
22004 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22005 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &
operator, value, cast->
name, cast->
depth));
22009 case PM_CALL_NODE: {
22015 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22018 parser_lex(parser);
22020 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22021 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22028 parser_lex(parser);
22033 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22034 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22035 return UP(pm_index_and_write_node_create(parser, cast, &
operator, value));
22039 if (pm_call_node_writable_p(parser, cast)) {
22040 parse_write_name(parser, &cast->
name);
22042 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22045 parse_call_operator_write(parser, cast, &
operator);
22046 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22047 return UP(pm_call_and_write_node_create(parser, cast, &
operator, value));
22049 case PM_MULTI_WRITE_NODE: {
22050 parser_lex(parser);
22052 pm_parser_err_token(parser, &
operator, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
22056 parser_lex(parser);
22061 pm_parser_err_token(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
22067parse_or_equal(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
22070 switch (PM_NODE_TYPE(node)) {
22071 case PM_BACK_REFERENCE_READ_NODE:
22072 case PM_NUMBERED_REFERENCE_READ_NODE:
22073 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
22075 case PM_GLOBAL_VARIABLE_READ_NODE: {
22076 parser_lex(parser);
22078 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22079 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &
operator, value));
22083 case PM_CLASS_VARIABLE_READ_NODE: {
22084 parser_lex(parser);
22086 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22091 case PM_CONSTANT_PATH_NODE: {
22092 parser_lex(parser);
22094 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22097 return parse_shareable_constant_write(parser, write);
22099 case PM_CONSTANT_READ_NODE: {
22100 parser_lex(parser);
22102 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22105 if (context_def_p(parser)) {
22106 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
22109 return parse_shareable_constant_write(parser, write);
22111 case PM_INSTANCE_VARIABLE_READ_NODE: {
22112 parser_lex(parser);
22114 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22119 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
22121 parser_lex(parser);
22123 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22124 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &
operator, value, name, 0));
22126 pm_node_unreference(parser, node);
22129 case PM_LOCAL_VARIABLE_READ_NODE: {
22130 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
22131 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
22132 pm_node_unreference(parser, node);
22136 parser_lex(parser);
22138 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22139 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &
operator, value, cast->
name, cast->
depth));
22143 case PM_CALL_NODE: {
22149 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22152 parser_lex(parser);
22154 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22155 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22162 parser_lex(parser);
22167 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22168 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22169 return UP(pm_index_or_write_node_create(parser, cast, &
operator, value));
22173 if (pm_call_node_writable_p(parser, cast)) {
22174 parse_write_name(parser, &cast->
name);
22176 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22179 parse_call_operator_write(parser, cast, &
operator);
22180 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22181 return UP(pm_call_or_write_node_create(parser, cast, &
operator, value));
22183 case PM_MULTI_WRITE_NODE: {
22184 parser_lex(parser);
22185 pm_parser_err_token(parser, &
operator, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
22189 parser_lex(parser);
22194 pm_parser_err_token(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
22200parse_operator_equal(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
22203 switch (PM_NODE_TYPE(node)) {
22204 case PM_BACK_REFERENCE_READ_NODE:
22205 case PM_NUMBERED_REFERENCE_READ_NODE:
22206 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
22208 case PM_GLOBAL_VARIABLE_READ_NODE: {
22209 parser_lex(parser);
22211 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22212 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &
operator, value));
22216 case PM_CLASS_VARIABLE_READ_NODE: {
22217 parser_lex(parser);
22219 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22224 case PM_CONSTANT_PATH_NODE: {
22225 parser_lex(parser);
22227 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22230 return parse_shareable_constant_write(parser, write);
22232 case PM_CONSTANT_READ_NODE: {
22233 parser_lex(parser);
22235 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22238 if (context_def_p(parser)) {
22239 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
22242 return parse_shareable_constant_write(parser, write);
22244 case PM_INSTANCE_VARIABLE_READ_NODE: {
22245 parser_lex(parser);
22247 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22252 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
22254 parser_lex(parser);
22256 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22257 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &
operator, value, name, 0));
22259 pm_node_unreference(parser, node);
22262 case PM_LOCAL_VARIABLE_READ_NODE: {
22263 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
22264 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
22265 pm_node_unreference(parser, node);
22269 parser_lex(parser);
22271 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22272 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &
operator, value, cast->
name, cast->
depth));
22276 case PM_CALL_NODE: {
22277 parser_lex(parser);
22283 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22286 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22287 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22295 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22296 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22297 return UP(pm_index_operator_write_node_create(parser, cast, &
operator, value));
22301 if (pm_call_node_writable_p(parser, cast)) {
22302 parse_write_name(parser, &cast->
name);
22304 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22307 parse_call_operator_write(parser, cast, &
operator);
22308 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22309 return UP(pm_call_operator_write_node_create(parser, cast, &
operator, value));
22311 case PM_MULTI_WRITE_NODE: {
22312 parser_lex(parser);
22313 pm_parser_err_token(parser, &
operator, PM_ERR_OPERATOR_MULTI_ASSIGN);
22317 parser_lex(parser);
22322 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
22328parse_call(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
22330 parser_lex(parser);
22335 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
22336 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22337 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
22340 switch (PM_NODE_TYPE(node)) {
22341 case PM_RESCUE_MODIFIER_NODE: {
22344 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22348 case PM_AND_NODE: {
22350 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22351 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22357 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22358 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22368 switch (parser->current.type) {
22369 case PM_CASE_OPERATOR:
22370 case PM_CASE_KEYWORD:
22371 case PM_TOKEN_CONSTANT:
22372 case PM_TOKEN_IDENTIFIER:
22373 case PM_TOKEN_METHOD_NAME: {
22374 parser_lex(parser);
22375 message = parser->previous;
22379 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
22380 message = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
22384 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22385 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
22388 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
22391 match1(parser, PM_TOKEN_COMMA)
22393 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22400parse_aref(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
22401 parser_lex(parser);
22404 arguments.
opening_loc = TOK2LOC(parser, &parser->previous);
22406 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22407 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
22408 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22411 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
22415 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22416 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22417 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22424 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22425 block = parse_block(parser, (uint16_t) (depth + 1));
22426 pm_arguments_validate_block(parser, &arguments, block);
22427 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22428 block = parse_block(parser, (uint16_t) (depth + 1));
22431 if (block != NULL) {
22432 if (arguments.
block != NULL) {
22433 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
22435 arguments.
arguments = pm_arguments_node_create(parser);
22437 pm_arguments_node_arguments_append(parser->arena, arguments.
arguments, arguments.
block);
22440 arguments.
block = UP(block);
22443 return UP(pm_call_node_aref_create(parser, node, &arguments));
22447parse_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) {
22450 switch (token.type) {
22451 case PM_TOKEN_EQUAL:
22452 return parse_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22453 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL:
22454 return parse_and_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22455 case PM_TOKEN_PIPE_PIPE_EQUAL:
22456 return parse_or_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22457 case PM_TOKEN_AMPERSAND_EQUAL:
22458 case PM_TOKEN_CARET_EQUAL:
22459 case PM_TOKEN_GREATER_GREATER_EQUAL:
22460 case PM_TOKEN_LESS_LESS_EQUAL:
22461 case PM_TOKEN_MINUS_EQUAL:
22462 case PM_TOKEN_PERCENT_EQUAL:
22463 case PM_TOKEN_PIPE_EQUAL:
22464 case PM_TOKEN_PLUS_EQUAL:
22465 case PM_TOKEN_SLASH_EQUAL:
22466 case PM_TOKEN_STAR_EQUAL:
22467 case PM_TOKEN_STAR_STAR_EQUAL:
22468 return parse_operator_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22469 case PM_TOKEN_AMPERSAND_AMPERSAND:
22470 case PM_TOKEN_KEYWORD_AND: {
22471 parser_lex(parser);
22473 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));
22474 return UP(pm_and_node_create(parser, node, &token, right));
22476 case PM_TOKEN_KEYWORD_OR:
22477 case PM_TOKEN_PIPE_PIPE: {
22478 parser_lex(parser);
22480 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));
22481 return UP(pm_or_node_create(parser, node, &token, right));
22483 case PM_TOKEN_EQUAL_TILDE:
22484 return parse_match(parser, node, binding_power, flags, depth);
22485 case PM_TOKEN_UAMPERSAND:
22486 case PM_TOKEN_USTAR:
22487 case PM_TOKEN_USTAR_STAR:
22490 case PM_TOKEN_BANG_EQUAL:
22491 case PM_TOKEN_BANG_TILDE:
22492 case PM_TOKEN_EQUAL_EQUAL:
22493 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
22494 case PM_TOKEN_LESS_EQUAL_GREATER:
22495 case PM_TOKEN_CARET:
22496 case PM_TOKEN_PIPE:
22497 case PM_TOKEN_AMPERSAND:
22498 case PM_TOKEN_GREATER_GREATER:
22499 case PM_TOKEN_LESS_LESS:
22500 case PM_TOKEN_MINUS:
22501 case PM_TOKEN_PLUS:
22502 case PM_TOKEN_PERCENT:
22503 case PM_TOKEN_SLASH:
22504 case PM_TOKEN_STAR:
22505 case PM_TOKEN_STAR_STAR: {
22506 parser_lex(parser);
22508 switch (PM_NODE_TYPE(node)) {
22509 case PM_RESCUE_MODIFIER_NODE: {
22512 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22516 case PM_AND_NODE: {
22518 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22519 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22525 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22526 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22534 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));
22535 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
22537 case PM_TOKEN_GREATER:
22538 case PM_TOKEN_GREATER_EQUAL:
22539 case PM_TOKEN_LESS:
22540 case PM_TOKEN_LESS_EQUAL: {
22541 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
22542 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
22545 parser_lex(parser);
22546 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));
22547 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
22549 case PM_TOKEN_AMPERSAND_DOT:
22551 return parse_call(parser, node, previous_binding_power, flags, depth);
22552 case PM_TOKEN_DOT_DOT:
22553 case PM_TOKEN_DOT_DOT_DOT: {
22554 parser_lex(parser);
22557 if (token_begins_expression_p(parser->current.type)) {
22558 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22561 return UP(pm_range_node_create(parser, node, &token, right));
22563 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
22565 parser_lex(parser);
22567 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));
22568 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
22570 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
22572 parser_lex(parser);
22574 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));
22575 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
22577 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
22578 parser_lex(parser);
22580 pm_statements_node_body_append(parser, statements, node,
true);
22582 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));
22583 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));
22585 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
22586 parser_lex(parser);
22588 pm_statements_node_body_append(parser, statements, node,
true);
22590 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));
22591 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));
22593 case PM_TOKEN_QUESTION_MARK:
22594 return UP(parse_ternary(parser, node, flags, depth));
22595 case PM_TOKEN_COLON_COLON:
22596 return parse_constant_path_infix(parser, node, previous_binding_power, flags, depth);
22597 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22598 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
22599 parser_lex(parser);
22600 accept1(parser, PM_TOKEN_NEWLINE);
22602 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));
22603 context_pop(parser);
22605 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
22607 case PM_TOKEN_BRACKET_LEFT:
22608 return parse_aref(parser, node, previous_binding_power, flags, depth);
22609 case PM_TOKEN_KEYWORD_IN: {
22610 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22611 parser->pattern_matching_newlines =
true;
22614 parser->command_start =
false;
22615 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22616 parser_lex(parser);
22619 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));
22621 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22623 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
22625 case PM_TOKEN_EQUAL_GREATER: {
22626 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22627 parser->pattern_matching_newlines =
true;
22630 parser->command_start =
false;
22631 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22632 parser_lex(parser);
22635 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));
22637 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22639 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
22642 assert(
false &&
"unreachable");
22647#undef PM_PARSE_PATTERN_SINGLE
22648#undef PM_PARSE_PATTERN_TOP
22649#undef PM_PARSE_PATTERN_MULTI
22665 pm_binding_power_t left = pm_binding_powers[parser->current.type].
left;
22667 switch (PM_NODE_TYPE(node)) {
22668 case PM_MULTI_WRITE_NODE:
22669 case PM_RETURN_NODE:
22670 case PM_BREAK_NODE:
22672 return left > PM_BINDING_POWER_MODIFIER;
22673 case PM_CLASS_VARIABLE_WRITE_NODE:
22674 case PM_CONSTANT_PATH_WRITE_NODE:
22675 case PM_CONSTANT_WRITE_NODE:
22676 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22677 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22678 case PM_LOCAL_VARIABLE_WRITE_NODE:
22679 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
22680 case PM_CALL_NODE: {
22683 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
22684 return left > PM_BINDING_POWER_MODIFIER;
22690 if (pm_command_call_value_p(parser, node)) {
22691 return left > PM_BINDING_POWER_COMPOSITION;
22697 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22699 case PM_SUPER_NODE:
22700 case PM_YIELD_NODE:
22703 if (pm_command_call_value_p(parser, node)) {
22704 return left > PM_BINDING_POWER_COMPOSITION;
22709 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22714 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(parser, node);
22715 case PM_RESCUE_MODIFIER_NODE:
22719 if (left > PM_BINDING_POWER_MODIFIER) {
22722 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
22739parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
22740 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
22741 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22742 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
22745 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
22750 switch (PM_NODE_TYPE(node)) {
22751 case PM_ERROR_RECOVERY_NODE:
22753 case PM_PRE_EXECUTION_NODE:
22755 case PM_POST_EXECUTION_NODE:
22756 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22757 case PM_ALIAS_METHOD_NODE:
22758 case PM_UNDEF_NODE:
22759 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
22764 case PM_SUPER_NODE:
22765 case PM_YIELD_NODE:
22767 if (parse_expression_terminator(parser, node)) {
22771 case PM_SYMBOL_NODE:
22772 if (pm_symbol_node_label_p(parser, node)) {
22783 pm_token_type_t current_token_type;
22786 current_token_type = parser->current.type,
22787 current_binding_powers = pm_binding_powers[current_token_type],
22788 binding_power <= current_binding_powers.
left &&
22789 current_binding_powers.
binary
22791 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
22792 if (parse_expression_terminator(parser, node))
return node;
22796 if (current_binding_powers.
nonassoc) {
22804 if (next_binding_powers.
nonassoc && next_binding_powers.
left == current_binding_powers.
left) {
22805 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));
22816 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22817 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22818 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));
22822 if (PM_BINDING_POWER_TERM <= next_binding_powers.
left) {
22825 }
else if (current_binding_powers.
left <= next_binding_powers.
left) {
22830 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
22839 switch (node->
type) {
22840 case PM_CALL_NODE: {
22854 cast->
block == NULL &&
22864 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22867 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22872 case PM_CONSTANT_PATH_NODE:
22875 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22880 if (context_terminator(parser->current_context->context, &parser->current)) {
22883 !next_binding_powers.
binary ||
22884 binding_power > next_binding_powers.
left ||
22885 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
22901 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22902 if (statements == NULL) {
22903 statements = pm_statements_node_create(parser);
22907 pm_arguments_node_arguments_append(
22910 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
22913 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
22916 pm_parser_constant_id_constant(parser,
"print", 5)
22920 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22921 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22922 if (statements == NULL) {
22923 statements = pm_statements_node_create(parser);
22927 pm_arguments_node_arguments_append(
22930 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
22933 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22934 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
22938 pm_parser_constant_id_constant(parser,
"$F", 2),
22942 pm_statements_node_body_prepend(parser->arena, statements, UP(write));
22946 pm_arguments_node_arguments_append(
22949 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
22952 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22954 pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
22956 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
22958 UP(pm_true_node_synthesized_create(parser))
22961 pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
22962 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22966 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
22968 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
22972 statements = wrapped_statements;
22986 if (parser->current_scope == NULL) {
22987 pm_parser_scope_push(parser,
true);
22991 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22993 parser_lex(parser);
22996 if (statements != NULL && !parser->parsing_eval) {
23000 assert(statements->
body.
size > 0);
23001 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
23005 pm_locals_order(parser, &parser->current_scope->locals, &locals,
true);
23006 pm_parser_scope_pop(parser);
23011 statements = wrap_statements(parser, statements);
23013 flush_block_exits(parser, previous_block_exits);
23019 if (statements == NULL) {
23020 statements = pm_statements_node_create(parser);
23024 return UP(pm_program_node_create(parser, &locals, statements));
23041pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
23042 size_t little_length = strlen(little);
23044 for (
const char *max = big + big_length - little_length; big <= max; big++) {
23045 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
23052#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
23060pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
23061 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
23062 pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
23073 const char *switches = pm_strnstr(engine,
" -", length);
23074 if (switches == NULL)
return;
23077 options->shebang_callback(
23079 (
const uint8_t *) (switches + 1),
23080 length - ((
size_t) (switches - engine)) - 1,
23081 options->shebang_callback_data
23084 size_t encoding_length;
23085 if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
23086 const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
23087 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23090 parser->command_line = next_options.command_line;
23091 parser->frozen_string_literal = next_options.frozen_string_literal;
23099 assert(arena != NULL);
23100 assert(source != NULL);
23104 .metadata_arena = { 0 },
23106 .lex_state = PM_LEX_STATE_BEG,
23107 .enclosure_nesting = 0,
23108 .lambda_enclosure_nesting = -1,
23109 .brace_nesting = 0,
23110 .do_loop_stack = 0,
23111 .accepts_block_stack = 0,
23114 .stack = {{ .mode = PM_LEX_DEFAULT }},
23115 .current = &parser->lex_modes.stack[0],
23118 .end = source + size,
23119 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
23120 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
23121 .next_start = NULL,
23122 .heredoc_end = NULL,
23124 .comment_list = { 0 },
23125 .magic_comment_list = { 0 },
23126 .warning_list = { 0 },
23127 .error_list = { 0 },
23128 .current_scope = NULL,
23129 .current_context = NULL,
23130 .encoding = PM_ENCODING_UTF_8_ENTRY,
23131 .encoding_changed_callback = NULL,
23132 .encoding_comment_start = source,
23133 .lex_callback = { 0 },
23134 .filepath = PM_STRING_EMPTY,
23135 .constant_pool = { 0 },
23136 .line_offsets = { 0 },
23138 .current_string = PM_STRING_EMPTY,
23140 .explicit_encoding = NULL,
23142 .parsing_eval =
false,
23143 .partial_script =
false,
23144 .attach_comments =
false,
23145 .command_start =
true,
23146 .recovering =
false,
23147 .continuable =
true,
23148 .encoding_locked =
false,
23149 .encoding_changed =
false,
23150 .pattern_matching_newlines =
false,
23151 .in_keyword_arg =
false,
23152 .current_block_exits = NULL,
23153 .semantic_token_seen =
false,
23155 .warn_mismatched_indentation =
true
23163 if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
23164 if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
23171 uint32_t constant_size = ((uint32_t) size) / 120;
23172 pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
23177 size_t newline_size = size / 22;
23178 pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
23181 if (options != NULL) {
23183 if (pm_string_length(&options->filepath) > 0) {
23184 parser->filepath = options->filepath;
23188 parser->start_line = options->line;
23191 size_t encoding_length = pm_string_length(&options->encoding);
23192 if (encoding_length > 0) {
23193 const uint8_t *encoding_source = pm_string_source(&options->encoding);
23194 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23198 parser->encoding_locked = options->encoding_locked;
23201 parser->frozen_string_literal = options->frozen_string_literal;
23204 parser->command_line = options->command_line;
23207 parser->version = options->version;
23210 parser->partial_script = options->partial_script;
23213 parser->attach_comments = options->attach_comments;
23216 parser->parsing_eval = options->scopes_count > 0;
23217 if (parser->parsing_eval) parser->warn_mismatched_indentation =
false;
23219 for (
size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
23221 pm_parser_scope_push(parser, scope_index == 0);
23225 parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
23227 for (
size_t local_index = 0; local_index < scope->locals_count; local_index++) {
23228 const pm_string_t *local = pm_options_scope_local(scope, local_index);
23230 const uint8_t *source = pm_string_source(local);
23231 size_t length = pm_string_length(local);
23233 uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
23234 memcpy(allocated, source, length);
23235 pm_parser_local_add_owned(parser, allocated, length);
23242 if (parser->version == PM_OPTIONS_VERSION_UNSET) {
23243 parser->version = PM_OPTIONS_VERSION_LATEST;
23246 pm_accepts_block_stack_push(parser,
true);
23249 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
23250 parser->current.end += 3;
23251 parser->encoding_comment_start += 3;
23253 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
23254 parser->encoding = PM_ENCODING_UTF_8_ENTRY;
23255 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
23262 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
23279 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
23280 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
23282 if (length > 2 && parser->current.end[0] ==
'#' && parser->current.end[1] ==
'!') {
23283 const char *engine;
23285 if ((engine = pm_strnstr((
const char *) parser->start,
"ruby", length)) != NULL) {
23286 if (newline != NULL) {
23287 parser->encoding_comment_start = newline + 1;
23289 if (options == NULL || options->main_script) {
23290 pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
23294 if (options != NULL && options->main_script && options->shebang_callback != NULL) {
23295 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->start)));
23298 search_shebang =
false;
23299 }
else if (options != NULL && options->main_script && !parser->parsing_eval) {
23300 search_shebang =
true;
23306 if (search_shebang) {
23309 bool found_shebang =
false;
23313 const uint8_t *cursor = parser->start;
23317 const uint8_t *newline = next_newline(cursor, parser->end - cursor);
23319 while (newline != NULL) {
23320 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
23322 cursor = newline + 1;
23323 newline = next_newline(cursor, parser->end - cursor);
23325 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
23326 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
23327 const char *engine;
23328 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
23329 found_shebang =
true;
23331 if (newline != NULL) {
23332 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
23333 parser->encoding_comment_start = newline + 1;
23336 if (options != NULL && options->shebang_callback != NULL) {
23337 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
23345 if (found_shebang) {
23346 parser->previous = (
pm_token_t) { .
type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23347 parser->current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23349 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
23350 pm_line_offset_list_clear(&parser->line_offsets);
23357 parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
23370 if (parser == NULL) abort();
23372 pm_parser_init(arena, parser, source, size, options);
23381 pm_string_cleanup(&parser->filepath);
23382 pm_arena_cleanup(&parser->metadata_arena);
23384 while (parser->current_scope != NULL) {
23389 pm_parser_scope_pop(parser);
23392 while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
23393 lex_mode_pop(parser);
23402 pm_parser_cleanup(parser);
23412pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
23414 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
23415 case PM_ERR_BEGIN_UPCASE_BRACE:
23416 case PM_ERR_CLASS_VARIABLE_BARE:
23417 case PM_ERR_END_UPCASE_BRACE:
23418 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
23419 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
23420 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
23421 case PM_ERR_EXPRESSION_NOT_WRITABLE:
23422 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
23423 case PM_ERR_FLOAT_PARSE:
23424 case PM_ERR_GLOBAL_VARIABLE_BARE:
23425 case PM_ERR_HASH_KEY:
23426 case PM_ERR_HEREDOC_IDENTIFIER:
23427 case PM_ERR_INSTANCE_VARIABLE_BARE:
23428 case PM_ERR_INVALID_BLOCK_EXIT:
23429 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
23430 case PM_ERR_INVALID_FLOAT_EXPONENT:
23431 case PM_ERR_INVALID_NUMBER_BINARY:
23432 case PM_ERR_INVALID_NUMBER_DECIMAL:
23433 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
23434 case PM_ERR_INVALID_NUMBER_OCTAL:
23435 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
23436 case PM_ERR_NO_LOCAL_VARIABLE:
23437 case PM_ERR_PARAMETER_ORDER:
23438 case PM_ERR_STATEMENT_UNDEF:
23439 case PM_ERR_VOID_EXPRESSION:
23482 if (parser->error_list.size == 0) {
23483 parser->continuable =
false;
23487 if (!parser->continuable)
return;
23489 size_t source_length = (size_t) (parser->end - parser->start);
23492 bool has_non_stray_error =
false;
23494 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)) {
23495 has_non_stray_error =
true;
23503 size_t non_stray_min_start = SIZE_MAX;
23506 size_t error_start = (size_t) error->location.start;
23507 size_t error_end = error_start + (size_t) error->location.length;
23508 bool at_eof = error_end >= source_length;
23511 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
23512 parser->continuable =
false;
23517 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
23518 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
23519 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
23528 if (non_stray_min_start < error_start)
continue;
23535 if (at_eof && error_start > 0) {
23537 if (error->location.length == 1) {
23538 const uint8_t *
byte = parser->start + error_start;
23539 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
23540 parser->continuable =
false;
23550 if (has_non_stray_error)
continue;
23557 if (error->location.length == 1) {
23558 const uint8_t *
byte = parser->start + error_start;
23559 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
23563 parser->continuable =
false;
23573 pm_node_t *node = parse_program(parser);
23574 pm_parse_continuable(parser);
23575 if (parser->attach_comments) pm_comments_attach(parser, node);
23587 bool eof = pm_source_stream_read(source);
23592 while (!eof && tmp->error_list.size > 0) {
23593 eof = pm_source_stream_read(source);
23596 pm_arena_cleanup(arena);
23598 tmp =
pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
23606#undef PM_CASE_KEYWORD
23607#undef PM_CASE_OPERATOR
23608#undef PM_CASE_WRITABLE
23609#undef PM_STRING_EMPTY
23614#ifndef PRISM_EXCLUDE_SERIALIZATION
23618 pm_buffer_append_string(buffer,
"PRISM", 5);
23622 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23630 pm_serialize_header(buffer);
23631 pm_serialize_content(parser, node, buffer);
23632 pm_buffer_append_byte(buffer,
'\0');
23640pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23642 pm_options_read(&options, data);
23646 pm_parser_init(&arena, &parser, source, size, &options);
23650 pm_serialize_header(buffer);
23651 pm_serialize_content(&parser, node, buffer);
23652 pm_buffer_append_byte(buffer,
'\0');
23654 pm_parser_cleanup(&parser);
23655 pm_arena_cleanup(&arena);
23656 pm_options_cleanup(&options);
23668 pm_options_read(&options, data);
23670 pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
23671 pm_serialize_header(buffer);
23672 pm_serialize_content(parser, node, buffer);
23673 pm_buffer_append_byte(buffer,
'\0');
23676 pm_arena_cleanup(&arena);
23677 pm_options_cleanup(&options);
23691 pm_options_read(&options, data);
23695 pm_parser_init(&arena, &parser, source, size, &options);
23699 int8_t result = -1;
23700 if (parser.error_list.size > 0) {
23701 const char *encoding_name = parser.encoding->name;
23702 pm_buffer_append_string(buffer, encoding_name, strlen(encoding_name));
23703 pm_buffer_append_byte(buffer,
'\0');
23705 result = (int8_t) pm_errors_format(&parser, buffer, format_type);
23708 pm_parser_cleanup(&parser);
23709 pm_arena_cleanup(&arena);
23710 pm_options_cleanup(&options);
23719pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23721 pm_options_read(&options, data);
23725 pm_parser_init(&arena, &parser, source, size, &options);
23728 pm_serialize_header(buffer);
23729 pm_serialize_encoding(parser.encoding, buffer);
23730 pm_buffer_append_varsint(buffer, parser.start_line);
23731 pm_serialize_line_offset_list(&parser.line_offsets, buffer);
23732 pm_serialize_comment_list(&parser.comment_list, buffer);
23734 pm_parser_cleanup(&parser);
23735 pm_arena_cleanup(&arena);
23736 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_NODISCARD PRISM_EXPORTED_FUNCTION pm_parser_t * pm_parser_new(pm_arena_t *arena, const uint8_t *source, size_t size, const pm_options_t *options) PRISM_NONNULL(1)
Allocate and initialize a parser with the given start and end pointers.
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser) PRISM_NONNULL(1)
Free both the memory held by the given parser and the parser itself.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser) PRISM_NONNULL(1)
Initiate the parser with the given parser.
#define PM_NODE_LIST_FOREACH(list, index, node)
Loop through each node in the node list, writing each node to the given pm_node_t pointer.
The version of the Prism library.
#define PRISM_VERSION
The version of the Prism library as a constant string.
#define PRISM_VERSION_PATCH
The patch version of the Prism library as an int.
#define PRISM_VERSION_MINOR
The minor version of the Prism library as an int.
#define PRISM_VERSION_MAJOR
The major version of the Prism library as an int.
The functions related to serializing the AST to a binary format.
Functions for parsing streams.
PM_NODE_ALIGNAS struct pm_node * left
AndNode::left.
PM_NODE_ALIGNAS struct pm_node * right
AndNode::right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode::arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode::elements.
PM_NODE_ALIGNAS struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
PM_NODE_ALIGNAS struct pm_node * value
AssocNode::value.
PM_NODE_ALIGNAS struct pm_node * key
AssocNode::key.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
BeginNode::else_clause.
PM_NODE_ALIGNAS struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
PM_NODE_ALIGNAS struct pm_statements_node * statements
BeginNode::statements.
PM_NODE_ALIGNAS struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
pm_node_t base
The embedded base node.
This struct represents a set of binding powers used for a given token.
bool binary
Whether or not this token can be used as a binary operator.
pm_binding_power_t left
The left binding power.
bool nonassoc
Whether or not this token can be used as non-associative binary operator.
pm_binding_power_t right
The right binding power.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
pm_constant_id_t name
CallNode::name.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
CallNode::arguments.
pm_location_t equal_loc
CallNode::equal_loc.
pm_location_t call_operator_loc
CallNode::call_operator_loc.
pm_location_t message_loc
CallNode::message_loc.
PM_NODE_ALIGNAS struct pm_node * block
CallNode::block.
PM_NODE_ALIGNAS struct pm_node * receiver
CallNode::receiver.
struct pm_node_list conditions
CaseMatchNode::conditions.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
CaseMatchNode::else_clause.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
CaseNode::else_clause.
struct pm_node_list conditions
CaseNode::conditions.
pm_location_t equal_loc
DefNode::equal_loc.
PM_NODE_ALIGNAS struct pm_node * body
DefNode::body.
PM_NODE_ALIGNAS struct pm_statements_node * statements
ElseNode::statements.
PM_NODE_ALIGNAS struct pm_statements_node * statements
EnsureNode::statements.
pm_location_t opening_loc
FindPatternNode::opening_loc.
PM_NODE_ALIGNAS struct pm_node * constant
FindPatternNode::constant.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
GlobalVariableTargetNode.
struct pm_node_list elements
HashNode::elements.
PM_NODE_ALIGNAS struct pm_node * constant
HashPatternNode::constant.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_location_t closing_loc
HashPatternNode::closing_loc.
PM_NODE_ALIGNAS struct pm_statements_node * statements
IfNode::statements.
PM_NODE_ALIGNAS struct pm_node * subsequent
IfNode::subsequent.
PM_NODE_ALIGNAS struct pm_statements_node * statements
InNode::statements.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
int32_t line
The line number.
uint32_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
uint32_t depth
LocalVariableWriteNode::depth.
pm_constant_id_t name
LocalVariableWriteNode::name.
This struct represents a slice in the source code, defined by an offset and a length.
uint32_t start
The offset of the location from the start of the source.
uint32_t length
The length of the location.
struct pm_node_list targets
MatchWriteNode::targets.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_location_t location
This is the location of the node in the source.
PM_NODE_ALIGNAS struct pm_node * right
OrNode::right.
PM_NODE_ALIGNAS struct pm_node * left
OrNode::left.
PM_NODE_ALIGNAS struct pm_node * block
ParametersNode::block.
PM_NODE_ALIGNAS struct pm_node * rest
ParametersNode::rest.
PM_NODE_ALIGNAS struct pm_node * keyword_rest
ParametersNode::keyword_rest.
PM_NODE_ALIGNAS struct pm_node * body
ParenthesesNode::body.
PM_NODE_ALIGNAS struct pm_node * right
RangeNode::right.
PM_NODE_ALIGNAS struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
State for processing named capture groups found during regexp parsing.
bool shared
Whether the content being parsed points into the original source.
pm_constant_id_set_t names
The set of capture names found so far.
pm_call_node_t * call
The call node wrapping the regular expression node (for =~).
pm_match_write_node_t * match
The match write node being built, or NULL if no captures found yet.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_string_t unescaped
RegularExpressionNode::unescaped.
PM_NODE_ALIGNAS struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
PM_NODE_ALIGNAS struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
PM_NODE_ALIGNAS struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
pm_node_t base
The embedded base node.
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t content_loc
StringNode::content_loc.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
enum pm_string_t::@118 type
The type of the string.
size_t length
The length of the string in bytes of memory.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
SuperNode::arguments.
pm_location_t lparen_loc
SuperNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_node * block
SuperNode::block.
pm_location_t content_loc
SymbolNode::content_loc.
pm_string_t unescaped
SymbolNode::unescaped.
When we're lexing certain types (strings, symbols, lists, etc.) we have string content associated wit...
pm_buffer_t buffer
The buffer that we're using to keep track of the string content.
const uint8_t * cursor
The cursor into the source string that points to how far we have currently copied into the buffer.
This struct represents a token in the Ruby source.
const uint8_t * end
A pointer to the end location of the token in the source.
const uint8_t * start
A pointer to the start location of the token in the source.
pm_token_type_t type
The type of the token.
PM_NODE_ALIGNAS struct pm_statements_node * statements
UnlessNode::statements.
PM_NODE_ALIGNAS struct pm_else_node * else_clause
UnlessNode::else_clause.
PM_NODE_ALIGNAS struct pm_statements_node * statements
WhenNode::statements.
pm_location_t lparen_loc
YieldNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
YieldNode::arguments.
#define PRISM_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.