5#include "prism/internal/allocator.h"
6#include "prism/internal/arena.h"
7#include "prism/internal/bit.h"
8#include "prism/internal/buffer.h"
9#include "prism/internal/char.h"
10#include "prism/internal/comments.h"
11#include "prism/internal/constant_pool.h"
12#include "prism/internal/diagnostic.h"
13#include "prism/internal/encoding.h"
14#include "prism/internal/integer.h"
15#include "prism/internal/isinf.h"
16#include "prism/internal/line_offset_list.h"
17#include "prism/internal/list.h"
18#include "prism/internal/magic_comments.h"
19#include "prism/internal/memchr.h"
20#include "prism/internal/node.h"
21#include "prism/internal/options.h"
22#include "prism/internal/parser.h"
23#include "prism/internal/regexp.h"
24#include "prism/internal/serialize.h"
25#include "prism/internal/source.h"
26#include "prism/internal/static_literals.h"
27#include "prism/internal/stringy.h"
28#include "prism/internal/strncasecmp.h"
29#include "prism/internal/strpbrk.h"
30#include "prism/internal/tokens.h"
50#ifndef PRISM_DEPTH_MAXIMUM
51 #define PRISM_DEPTH_MAXIMUM 10000
58#define PM_CONCATENATE(left, right) left ## right
65#if defined(_Static_assert)
66# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message)
68# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
75#if defined(__GNUC__) || defined(__clang__)
77 #define PRISM_LIKELY(x) __builtin_expect(!!(x), 1)
80 #define PRISM_UNLIKELY(x) __builtin_expect(!!(x), 0)
83 #define PRISM_LIKELY(x) (x)
86 #define PRISM_UNLIKELY(x) (x)
101#define PM_TAB_WHITESPACE_SIZE 8
104#define MIN(a,b) (((a)<(b))?(a):(b))
105#define MAX(a,b) (((a)>(b))?(a):(b))
111#define U32(value_) ((uint32_t) (value_))
113#define FL PM_NODE_FLAGS
114#define UP PM_NODE_UPCAST
116#define PM_LOCATION_START(location_) ((location_)->start)
117#define PM_LOCATION_END(location_) ((location_)->start + (location_)->length)
119#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
120#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
121#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
122#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
124#define PM_NODE_START(node_) (UP(node_)->location.start)
125#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
126#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
127#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
129#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
130#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
132#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
133#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
134#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
135#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
136#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
146pm_location_init(uint32_t start, uint32_t length) {
151#define PM_LOCATION_INIT(start_, length_) pm_location_init((start_), (length_))
152#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
153#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
154#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
156#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
157#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
158#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
159#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
161#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
162#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
163#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
174lex_mode_incrementor(
const uint8_t start) {
191lex_mode_terminator(
const uint8_t start) {
213 lex_mode.prev = parser->lex_modes.current;
214 parser->lex_modes.index++;
216 if (parser->lex_modes.index > PM_LEX_STACK_SIZE - 1) {
218 if (parser->lex_modes.current == NULL)
return false;
220 *parser->lex_modes.current = lex_mode;
222 parser->lex_modes.stack[parser->lex_modes.index] = lex_mode;
223 parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
233lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
234 uint8_t incrementor = lex_mode_incrementor(delimiter);
235 uint8_t terminator = lex_mode_terminator(delimiter);
241 .interpolation = interpolation,
244 .incrementor = incrementor,
245 .terminator = terminator
251 uint8_t *breakpoints = lex_mode.as.list.breakpoints;
252 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
253 memcpy(breakpoints,
"\\ \t\f\r\v\n",
sizeof(
"\\ \t\f\r\v\n") - 1);
258 if (terminator !=
'\0') {
259 breakpoints[index++] = terminator;
265 breakpoints[index++] =
'#';
269 if (incrementor !=
'\0') {
270 breakpoints[index++] = incrementor;
273 parser->explicit_encoding = NULL;
274 return lex_mode_push(parser, lex_mode);
284 return lex_mode_push_list(parser,
false,
'\0');
291lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
293 .mode = PM_LEX_REGEXP,
296 .incrementor = incrementor,
297 .terminator = terminator
304 uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
305 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
306 memcpy(breakpoints,
"\r\n\\#",
sizeof(
"\r\n\\#") - 1);
310 if (terminator !=
'\0') {
311 breakpoints[index++] = terminator;
315 if (incrementor !=
'\0') {
316 breakpoints[index++] = incrementor;
319 parser->explicit_encoding = NULL;
320 return lex_mode_push(parser, lex_mode);
327lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
329 .mode = PM_LEX_STRING,
332 .interpolation = interpolation,
333 .label_allowed = label_allowed,
334 .incrementor = incrementor,
335 .terminator = terminator
341 uint8_t *breakpoints = lex_mode.as.string.breakpoints;
342 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
343 memcpy(breakpoints,
"\r\n\\",
sizeof(
"\r\n\\") - 1);
348 if (terminator !=
'\0') {
349 breakpoints[index++] = terminator;
355 breakpoints[index++] =
'#';
360 if (incrementor !=
'\0') {
361 breakpoints[index++] = incrementor;
364 parser->explicit_encoding = NULL;
365 return lex_mode_push(parser, lex_mode);
375 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
385 if (parser->lex_modes.index == 0) {
386 parser->lex_modes.current->mode = PM_LEX_DEFAULT;
387 }
else if (parser->lex_modes.index < PM_LEX_STACK_SIZE) {
388 parser->lex_modes.index--;
389 parser->lex_modes.current = &parser->lex_modes.stack[parser->lex_modes.index];
391 parser->lex_modes.index--;
393 xfree_sized(parser->lex_modes.current,
sizeof(
pm_lex_mode_t));
394 parser->lex_modes.current = prev;
402lex_state_p(
const pm_parser_t *parser, pm_lex_state_t state) {
403 return parser->lex_state & state;
407 PM_IGNORED_NEWLINE_NONE = 0,
408 PM_IGNORED_NEWLINE_ALL,
409 PM_IGNORED_NEWLINE_PATTERN
410} pm_ignored_newline_type_t;
414 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);
417 return PM_IGNORED_NEWLINE_ALL;
418 }
else if ((parser->lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
419 return PM_IGNORED_NEWLINE_PATTERN;
421 return PM_IGNORED_NEWLINE_NONE;
427 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));
432 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
436lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
437 if (parser->current.end >= parser->end) {
440 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
445 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
453 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
461lex_state_set(
pm_parser_t *parser, pm_lex_state_t state) {
462 parser->lex_state = state;
465#ifndef PM_DEBUG_LOGGING
470#define PM_DEBUG_LOGGING 0
476 fprintf(stderr,
"STATE: ");
479 if (parser->lex_state == PM_LEX_STATE_NONE) {
480 fprintf(stderr,
"NONE\n");
484#define CHECK_STATE(state) \
485 if (parser->lex_state & state) { \
486 if (!first) fprintf(stderr, "|"); \
487 fprintf(stderr, "%s", #state); \
491 CHECK_STATE(PM_LEX_STATE_BEG)
492 CHECK_STATE(PM_LEX_STATE_END)
493 CHECK_STATE(PM_LEX_STATE_ENDARG)
494 CHECK_STATE(PM_LEX_STATE_ENDFN)
495 CHECK_STATE(PM_LEX_STATE_ARG)
496 CHECK_STATE(PM_LEX_STATE_CMDARG)
497 CHECK_STATE(PM_LEX_STATE_MID)
498 CHECK_STATE(PM_LEX_STATE_FNAME)
499 CHECK_STATE(PM_LEX_STATE_DOT)
500 CHECK_STATE(PM_LEX_STATE_CLASS)
501 CHECK_STATE(PM_LEX_STATE_LABEL)
502 CHECK_STATE(PM_LEX_STATE_LABELED)
503 CHECK_STATE(PM_LEX_STATE_FITEM)
507 fprintf(stderr,
"\n");
511debug_lex_state_set(
pm_parser_t *parser, pm_lex_state_t state,
char const * caller_name,
int line_number) {
512 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
514 lex_state_set(parser, state);
515 fprintf(stderr,
"Now: ");
517 fprintf(stderr,
"\n");
520#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
528#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
531#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
534#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
537#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
540#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
543#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
546#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
556pm_parser_err(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
557 pm_diagnostic_list_append(&parser->metadata_arena, &parser->error_list, start, length, diag_id);
566 pm_parser_err(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
574pm_parser_err_current(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
575 pm_parser_err_token(parser, &parser->current, diag_id);
583pm_parser_err_previous(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
584 pm_parser_err_token(parser, &parser->previous, diag_id);
593 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
599#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
600 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
606#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
607 PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
613#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
614 PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
620#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
621 PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id, __VA_ARGS__)
627#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
628 PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
634pm_parser_warn(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
635 pm_diagnostic_list_append(&parser->metadata_arena, &parser->warning_list, start, length, diag_id);
644 pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
653 pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
660#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
661 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->warning_list, start_, length_, diag_id_, __VA_ARGS__)
667#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
668 PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id_, __VA_ARGS__)
674#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
675 PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
681#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
682 PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
690pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
691 PM_PARSER_ERR_FORMAT(
693 U32(ident_start - parser->start),
697 (
const char *) ident_start
709pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
711 if (scope == NULL)
return false;
714 .previous = parser->current_scope,
716 .parameters = PM_SCOPE_PARAMETERS_NONE,
717 .implicit_parameters = { 0 },
718 .shareable_constant = parser->current_scope == NULL ? PM_SCOPE_SHAREABLE_CONSTANT_NONE : parser->current_scope->shareable_constant,
722 parser->current_scope = scope;
735 if (scope->previous == NULL)
return true;
736 if (scope->closed)
return false;
737 }
while ((scope = scope->previous) != NULL);
739 assert(
false &&
"unreachable");
747pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
750 while (depth-- > 0) {
751 assert(scope != NULL);
752 scope = scope->previous;
759 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
760 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
761 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
762} pm_scope_forwarding_param_check_result_t;
764static pm_scope_forwarding_param_check_result_t
765pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
767 bool conflict =
false;
769 while (scope != NULL) {
770 if (scope->parameters & mask) {
773 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
775 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
782 if (scope->closed)
break;
783 scope = scope->previous;
786 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
791 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
792 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
795 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
796 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
798 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
799 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
806 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
807 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
810 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
811 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
813 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
814 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
821 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
822 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
825 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
830 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
831 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
838 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
839 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
842 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
843 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
845 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
846 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
855pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
856 return parser->current_scope->shareable_constant;
864pm_parser_scope_shareable_constant_set(
pm_parser_t *parser, pm_shareable_constant_value_t shareable_constant) {
868 scope->shareable_constant = shareable_constant;
869 }
while (!scope->closed && (scope = scope->previous) != NULL);
879#define PM_LOCALS_HASH_THRESHOLD 5
883 if (locals->capacity > 0) {
884 xfree_sized(locals->locals, locals->capacity *
sizeof(
pm_local_t));
894 uint32_t next_capacity = locals->capacity == 0 ? 4 : (locals->capacity * 2);
895 assert(next_capacity > locals->capacity);
898 if (next_locals == NULL) abort();
900 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
901 if (locals->size > 0) {
902 memcpy(next_locals, locals->locals, locals->size *
sizeof(
pm_local_t));
907 bool hash_needed = (locals->capacity <= PM_LOCALS_HASH_THRESHOLD);
908 uint32_t mask = next_capacity - 1;
910 for (uint32_t index = 0; index < locals->capacity; index++) {
913 if (local->name != PM_CONSTANT_ID_UNSET) {
914 if (hash_needed) local->hash = pm_constant_id_hash(local->name);
916 uint32_t hash = local->hash;
917 while (next_locals[hash & mask].name != PM_CONSTANT_ID_UNSET) hash++;
918 next_locals[hash & mask] = *local;
923 pm_locals_free(locals);
924 locals->locals = next_locals;
925 locals->capacity = next_capacity;
945 if (locals->size >= (locals->capacity / 4 * 3)) {
946 pm_locals_resize(locals);
949 locals->bloom |= (1u << (name & 31));
951 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
952 for (uint32_t index = 0; index < locals->capacity; index++) {
955 if (local->name == PM_CONSTANT_ID_UNSET) {
958 .location = { .start = start, .length = length },
959 .index = locals->size++,
964 }
else if (local->name == name) {
969 uint32_t mask = locals->capacity - 1;
970 uint32_t hash = pm_constant_id_hash(name);
971 uint32_t initial_hash = hash;
974 pm_local_t *local = &locals->locals[hash & mask];
976 if (local->name == PM_CONSTANT_ID_UNSET) {
979 .location = { .start = start, .length = length },
980 .index = locals->size++,
985 }
else if (local->name == name) {
990 }
while ((hash & mask) != initial_hash);
993 assert(
false &&
"unreachable");
1003 if (!(locals->bloom & (1u << (name & 31))))
return UINT32_MAX;
1005 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
1006 for (uint32_t index = 0; index < locals->size; index++) {
1008 if (local->name == name)
return index;
1011 uint32_t mask = locals->capacity - 1;
1012 uint32_t hash = pm_constant_id_hash(name);
1013 uint32_t initial_hash = hash & mask;
1016 pm_local_t *local = &locals->locals[hash & mask];
1018 if (local->name == PM_CONSTANT_ID_UNSET) {
1020 }
else if (local->name == name) {
1025 }
while ((hash & mask) != initial_hash);
1037 uint32_t index = pm_locals_find(locals, name);
1038 assert(index != UINT32_MAX);
1041 assert(local->reads < UINT32_MAX);
1052 uint32_t index = pm_locals_find(locals, name);
1053 assert(index != UINT32_MAX);
1056 assert(local->reads > 0);
1066 uint32_t index = pm_locals_find(locals, name);
1067 assert(index != UINT32_MAX);
1069 return locals->locals[index].reads;
1082 pm_constant_id_list_init_capacity(parser->arena, list, locals->size);
1087 uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
1091 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
1093 for (uint32_t index = 0; index < capacity; index++) {
1096 if (local->name != PM_CONSTANT_ID_UNSET) {
1097 pm_constant_id_list_insert(list, (
size_t) local->index, local->name);
1099 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))) {
1100 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->name);
1102 if (constant->length >= 1 && *constant->start !=
'_') {
1103 PM_PARSER_WARN_FORMAT(
1105 local->location.
start,
1107 PM_WARN_UNUSED_LOCAL_VARIABLE,
1108 (
int) constant->length,
1109 (
const char *) constant->start
1125pm_parser_constant_id_raw(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1128 if (start == parser->constant_cache.start && end == parser->constant_cache.end) {
1129 return parser->constant_cache.id;
1132 pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (
size_t) (end - start));
1134 parser->constant_cache.start = start;
1135 parser->constant_cache.end = end;
1136 parser->constant_cache.id = id;
1145pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1146 return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length);
1153pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1154 return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (
const uint8_t *) start, length);
1162 return pm_parser_constant_id_raw(parser, token->start, token->end);
1169#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1170 case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1181 while (node != NULL) {
1182 switch (PM_NODE_TYPE(node)) {
1183 case PM_CASE_VOID_VALUE:
1184 return void_node != NULL ? void_node : node;
1185 case PM_MATCH_PREDICATE_NODE:
1187 case PM_BEGIN_NODE: {
1193 if (vn != NULL)
return vn;
1198 if (vn != NULL)
return vn;
1204 if (cast->
else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1208 if (vn == NULL)
return NULL;
1209 if (void_node == NULL) void_node = vn;
1213 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1217 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1229 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1230 pm_node_t *vn = pm_check_value_expression(parser, node);
1231 if (vn != NULL)
return vn;
1242 case PM_CASE_NODE: {
1244 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1253 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1257 if (vn == NULL)
return NULL;
1258 if (void_node == NULL) void_node = vn;
1261 node = UP(cast->else_clause);
1264 case PM_CASE_MATCH_NODE: {
1266 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1275 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1279 if (vn == NULL)
return NULL;
1280 if (void_node == NULL) void_node = vn;
1283 node = UP(cast->else_clause);
1286 case PM_ENSURE_NODE: {
1291 case PM_PARENTHESES_NODE: {
1293 node = UP(cast->
body);
1296 case PM_STATEMENTS_NODE: {
1300 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1303 switch (PM_NODE_TYPE(body_part)) {
1304 case PM_CASE_VOID_VALUE:
1305 if (void_node == NULL) {
1306 void_node = body_part;
1326 if (void_node == NULL) {
1332 case PM_UNLESS_NODE: {
1341 if (void_node == NULL) {
1347 case PM_ELSE_NODE: {
1360 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1364 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->previous;
1366 pm_locals_read(&scope->locals, cast->
name);
1379 pm_node_t *void_node = pm_check_value_expression(parser, node);
1380 if (void_node != NULL) {
1381 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1390 const char *
type = NULL;
1393 switch (PM_NODE_TYPE(node)) {
1394 case PM_BACK_REFERENCE_READ_NODE:
1395 case PM_CLASS_VARIABLE_READ_NODE:
1396 case PM_GLOBAL_VARIABLE_READ_NODE:
1397 case PM_INSTANCE_VARIABLE_READ_NODE:
1398 case PM_LOCAL_VARIABLE_READ_NODE:
1399 case PM_NUMBERED_REFERENCE_READ_NODE:
1400 type =
"a variable";
1403 case PM_CALL_NODE: {
1407 const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool, cast->
name);
1408 switch (message->length) {
1410 switch (message->start[0]) {
1421 type = (
const char *) message->start;
1427 switch (message->start[1]) {
1429 if (message->start[0] ==
'<' || message->start[0] ==
'>' || message->start[0] ==
'!' || message->start[0] ==
'=') {
1430 type = (
const char *) message->start;
1435 if (message->start[0] ==
'+' || message->start[0] ==
'-') {
1436 type = (
const char *) message->start;
1441 if (message->start[0] ==
'*') {
1442 type = (
const char *) message->start;
1449 if (memcmp(message->start,
"<=>", 3) == 0) {
1458 case PM_CONSTANT_PATH_NODE:
1462 case PM_CONSTANT_READ_NODE:
1463 type =
"a constant";
1466 case PM_DEFINED_NODE:
1475 case PM_IMAGINARY_NODE:
1476 case PM_INTEGER_NODE:
1477 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1478 case PM_INTERPOLATED_STRING_NODE:
1479 case PM_RATIONAL_NODE:
1480 case PM_REGULAR_EXPRESSION_NODE:
1481 case PM_SOURCE_ENCODING_NODE:
1482 case PM_SOURCE_FILE_NODE:
1483 case PM_SOURCE_LINE_NODE:
1484 case PM_STRING_NODE:
1485 case PM_SYMBOL_NODE:
1493 case PM_RANGE_NODE: {
1496 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1519 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1530 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1531 for (
size_t index = 0; index < size; index++) {
1532 pm_void_statement_check(parser, node->
body.
nodes[index]);
1542 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1543 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1544 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1545} pm_conditional_predicate_type_t;
1551pm_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) {
1553 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1554 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1556 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1557 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1559 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1569pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1570 switch (PM_NODE_TYPE(node)) {
1571 case PM_ARRAY_NODE: {
1572 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1575 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1576 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1581 case PM_HASH_NODE: {
1582 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1585 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1587 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1590 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1597 case PM_IMAGINARY_NODE:
1598 case PM_INTEGER_NODE:
1600 case PM_RATIONAL_NODE:
1601 case PM_REGULAR_EXPRESSION_NODE:
1602 case PM_SOURCE_ENCODING_NODE:
1603 case PM_SOURCE_FILE_NODE:
1604 case PM_SOURCE_LINE_NODE:
1605 case PM_STRING_NODE:
1606 case PM_SYMBOL_NODE:
1620 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1621 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);
1639 switch (PM_NODE_TYPE(node)) {
1642 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1643 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1648 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1649 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1652 case PM_PARENTHESES_NODE: {
1655 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1657 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1662 case PM_BEGIN_NODE: {
1670 case PM_RANGE_NODE: {
1673 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1674 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1682 node->
type = PM_FLIP_FLOP_NODE;
1686 case PM_REGULAR_EXPRESSION_NODE:
1691 node->
type = PM_MATCH_LAST_LINE_NODE;
1693 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1694 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1698 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1703 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1705 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1706 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1710 case PM_INTEGER_NODE:
1711 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1712 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1713 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1716 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1719 case PM_STRING_NODE:
1720 case PM_SOURCE_FILE_NODE:
1721 case PM_INTERPOLATED_STRING_NODE:
1722 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1724 case PM_SYMBOL_NODE:
1725 case PM_INTERPOLATED_SYMBOL_NODE:
1726 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1728 case PM_SOURCE_LINE_NODE:
1729 case PM_SOURCE_ENCODING_NODE:
1731 case PM_RATIONAL_NODE:
1732 case PM_IMAGINARY_NODE:
1733 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1735 case PM_CLASS_VARIABLE_WRITE_NODE:
1738 case PM_CONSTANT_WRITE_NODE:
1741 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1744 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1747 case PM_LOCAL_VARIABLE_WRITE_NODE:
1750 case PM_MULTI_WRITE_NODE:
1786 if (arguments->
block != NULL) {
1787 uint32_t end = PM_NODE_END(arguments->
block);
1790 uint32_t arguments_end = PM_LOCATION_END(&arguments->
closing_loc);
1791 if (arguments_end > end) {
1834 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1848char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1849 if (n <= 0)
return 0;
1851 if (parser->encoding_changed) {
1854 if ((width = parser->encoding->alpha_char(b, n)) != 0) {
1856 }
else if (*b ==
'_') {
1858 }
else if (*b >= 0x80) {
1859 return parser->encoding->char_width(b, n);
1863 }
else if (*b < 0x80) {
1864 return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b ==
'_');
1866 return pm_encoding_utf_8_char_width(b, n);
1875char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1878 }
else if (*b < 0x80) {
1879 return (*b ==
'_') || (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0);
1881 return pm_encoding_utf_8_char_width(b, n);
1898#if defined(PRISM_HAS_NEON)
1899#include <arm_neon.h>
1902scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1903 const uint8_t *cursor = start;
1910 static const uint8_t low_lut_data[16] = {
1911 0x15, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
1912 0x1F, 0x1F, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0E
1914 static const uint8_t high_lut_data[16] = {
1915 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
1916 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1918 const uint8x16_t low_lut = vld1q_u8(low_lut_data);
1919 const uint8x16_t high_lut = vld1q_u8(high_lut_data);
1920 const uint8x16_t mask_0f = vdupq_n_u8(0x0F);
1922 while (cursor + 16 <= end) {
1923 uint8x16_t v = vld1q_u8(cursor);
1925 uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
1926 uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
1927 uint8x16_t ident = vandq_u8(lo_class, hi_class);
1930 if (vminvq_u8(ident) != 0) {
1936 uint8x16_t is_zero = vceqq_u8(ident, vdupq_n_u8(0));
1937 uint64_t lo = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 0);
1940 cursor += pm_ctzll(lo) / 8;
1942 uint64_t hi = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 1);
1943 cursor += 8 + pm_ctzll(hi) / 8;
1946 return (
size_t) (cursor - start);
1949 return (
size_t) (cursor - start);
1952#elif defined(PRISM_HAS_SSSE3)
1953#include <tmmintrin.h>
1956scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1957 const uint8_t *cursor = start;
1959 while (cursor + 16 <= end) {
1960 __m128i v = _mm_loadu_si128((
const __m128i *) cursor);
1961 __m128i zero = _mm_setzero_si128();
1968 __m128i lowered = _mm_or_si128(v, _mm_set1_epi8(0x20));
1969 __m128i letter = _mm_and_si128(
1970 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x61), lowered), zero),
1971 _mm_cmpeq_epi8(_mm_subs_epu8(lowered, _mm_set1_epi8(0x7A)), zero));
1973 __m128i digit = _mm_and_si128(
1974 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x30), v), zero),
1975 _mm_cmpeq_epi8(_mm_subs_epu8(v, _mm_set1_epi8(0x39)), zero));
1977 __m128i underscore = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5F));
1979 __m128i ident = _mm_or_si128(_mm_or_si128(letter, digit), underscore);
1980 int mask = _mm_movemask_epi8(ident);
1982 if (mask == 0xFFFF) {
1987 cursor += pm_ctzll((uint64_t) (~mask & 0xFFFF));
1988 return (
size_t) (cursor - start);
1991 return (
size_t) (cursor - start);
1998#elif defined(PRISM_HAS_SWAR)
2010scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
2011 static const uint64_t ones = 0x0101010101010101ULL;
2012 static const uint64_t highs = 0x8080808080808080ULL;
2013 const uint8_t *cursor = start;
2015 while (cursor + 8 <= end) {
2017 memcpy(&word, cursor, 8);
2020 if (word & highs)
break;
2022 uint64_t digit = ((word | highs) - ones * 0x30) & ((ones * 0x39 | highs) - word) & highs;
2029 uint64_t lowered = word | (ones * 0x20);
2030 uint64_t letter = ((lowered | highs) - ones * 0x61) & ((ones * 0x7A | highs) - lowered) & highs;
2035 uint64_t xor_us = word ^ (ones * 0x5F);
2036 uint64_t underscore = (xor_us - ones) & ~xor_us & highs;
2038 uint64_t ident = digit | letter | underscore;
2040 if (ident == highs) {
2047 uint64_t not_ident = ~ident & highs;
2048 cursor += pm_ctzll(not_ident) / 8;
2049 return (
size_t) (cursor - start);
2052 return (
size_t) (cursor - start);
2059#define scan_identifier_ascii(start, end) ((size_t) 0)
2069char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
2072 }
else if (parser->encoding_changed) {
2075 if ((width = parser->encoding->alnum_char(b, n)) != 0) {
2077 }
else if (*b ==
'_') {
2079 }
else if (*b >= 0x80) {
2080 return parser->encoding->char_width(b, n);
2085 return char_is_identifier_utf8(b, n);
2092#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
2093#define PUNCT(idx) ( \
2094 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
2095 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
2096 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
2097 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
2098 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
2101const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
2106static PRISM_INLINE bool
2107char_is_global_name_punctuation(const uint8_t b) {
2108 const unsigned int i = (const unsigned int) b;
2109 if (i <= 0x20 || 0x7e < i) return false;
2111 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
2114static PRISM_INLINE bool
2115token_is_setter_name(pm_token_t *token) {
2117 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
2118 ((token->type == PM_TOKEN_IDENTIFIER) &&
2119 (token->end - token->start >= 2) &&
2120 (token->end[-1] == '='))
2128pm_local_is_keyword(const char *source, size_t length) {
2129#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
2133 switch (source[0]) {
2134 case 'd': KEYWORD("do"); return false;
2135 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
2136 case 'o': KEYWORD("or"); return false;
2137 default: return false;
2140 switch (source[0]) {
2141 case 'a': KEYWORD("and"); return false;
2142 case 'd': KEYWORD("def"); return false;
2143 case 'e': KEYWORD("end"); return false;
2144 case 'f': KEYWORD("for"); return false;
2145 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
2146 default: return false;
2149 switch (source[0]) {
2150 case 'c': KEYWORD("case"); return false;
2151 case 'e': KEYWORD("else"); return false;
2152 case 'n': KEYWORD("next"); return false;
2153 case 'r': KEYWORD("redo"); return false;
2154 case 's': KEYWORD("self"); return false;
2155 case 't': KEYWORD("then"); KEYWORD("true"); return false;
2156 case 'w': KEYWORD("when"); return false;
2157 default: return false;
2160 switch (source[0]) {
2161 case 'a': KEYWORD("alias"); return false;
2162 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
2163 case 'c': KEYWORD("class"); return false;
2164 case 'e': KEYWORD("elsif"); return false;
2165 case 'f': KEYWORD("false"); return false;
2166 case 'r': KEYWORD("retry"); return false;
2167 case 's': KEYWORD("super"); return false;
2168 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
2169 case 'w': KEYWORD("while"); return false;
2170 case 'y': KEYWORD("yield"); return false;
2171 default: return false;
2174 switch (source[0]) {
2175 case 'e': KEYWORD("ensure"); return false;
2176 case 'm': KEYWORD("module"); return false;
2177 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
2178 case 'u': KEYWORD("unless"); return false;
2179 default: return false;
2182 KEYWORD("__LINE__");
2183 KEYWORD("__FILE__");
2186 KEYWORD("__ENCODING__");
2195/******************************************************************************/
2196/* Node flag handling functions */
2197/******************************************************************************/
2202static PRISM_INLINE void
2203pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
2204 node->flags |= flag;
2210static PRISM_INLINE void
2211pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
2212 node->flags &= (pm_node_flags_t) ~flag;
2218static PRISM_INLINE void
2219pm_node_flag_set_repeated_parameter(pm_node_t *node) {
2220 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
2221 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
2222 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
2223 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
2224 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
2225 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
2226 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
2227 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
2229 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
2232/******************************************************************************/
2233/* Node creation functions */
2234/******************************************************************************/
2241#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)
2246static PRISM_INLINE pm_node_flags_t
2247pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
2248 pm_node_flags_t flags = 0;
2250 if (closing->type == PM_TOKEN_REGEXP_END) {
2251 pm_buffer_t unknown_flags = { 0 };
2253 // The closing delimiter is normally a single byte, so the options
2254 // follow it. A `\r\n` newline delimiter is two bytes, however, so we
2255 // skip past it to avoid misreading the trailing `\n` as an option.
2256 const uint8_t *flag = closing->start + 1;
2257 if ((closing->end - closing->start) >= 2 && closing->start[0] == '\r' && closing->start[1] == '\n') {
2261 for (; flag < closing->end; flag++) {
2263 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
2264 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
2265 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
2266 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
2268 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
2269 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
2270 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
2271 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
2273 default: pm_buffer_append_byte(&unknown_flags, *flag);
2277 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
2278 if (unknown_flags_length != 0) {
2279 const char *word = unknown_flags_length >= 2 ? "options" : "option";
2280 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
2282 pm_buffer_cleanup(&unknown_flags);
2288#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
2290static pm_statements_node_t *
2291pm_statements_node_create(pm_parser_t *parser);
2294pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
2297pm_statements_node_body_length(pm_statements_node_t *node);
2303static PRISM_INLINE void
2304pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
2305 if (integer->values != NULL) {
2306 size_t byte_size = integer->length * sizeof(uint32_t);
2307 uint32_t *old_values = integer->values;
2308 integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
2316static pm_error_recovery_node_t *
2317pm_error_recovery_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
2318 return pm_error_recovery_node_new(
2322 ((pm_location_t) { .start = start, .length = length }),
2330static pm_error_recovery_node_t *
2331pm_error_recovery_node_create_unexpected(pm_parser_t *parser, pm_node_t *unexpected) {
2332 return pm_error_recovery_node_new(
2336 unexpected->location,
2344static pm_alias_global_variable_node_t *
2345pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2346 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2348 return pm_alias_global_variable_node_new(
2352 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2355 TOK2LOC(parser, keyword)
2362static pm_alias_method_node_t *
2363pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2364 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2366 return pm_alias_method_node_new(
2370 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2373 TOK2LOC(parser, keyword)
2380static pm_alternation_pattern_node_t *
2381pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2382 return pm_alternation_pattern_node_new(
2386 PM_LOCATION_INIT_NODES(left, right),
2389 TOK2LOC(parser, operator)
2396static pm_and_node_t *
2397pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2398 pm_assert_value_expression(parser, left);
2400 return pm_and_node_new(
2404 PM_LOCATION_INIT_NODES(left, right),
2407 TOK2LOC(parser, operator)
2414static pm_arguments_node_t *
2415pm_arguments_node_create(pm_parser_t *parser) {
2416 return pm_arguments_node_new(
2420 PM_LOCATION_INIT_UNSET,
2421 ((pm_node_list_t) { 0 })
2429pm_arguments_node_size(pm_arguments_node_t *node) {
2430 return node->arguments.size;
2437pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
2438 if (pm_arguments_node_size(node) == 0) {
2439 PM_NODE_START_SET_NODE(node, argument);
2442 if (PM_NODE_END(node) < PM_NODE_END(argument)) {
2443 PM_NODE_LENGTH_SET_NODE(node, argument);
2446 pm_node_list_append(arena, &node->arguments, argument);
2448 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2449 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2450 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2452 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2460static pm_array_node_t *
2461pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2462 if (opening == NULL) {
2463 return pm_array_node_new(
2466 PM_NODE_FLAG_STATIC_LITERAL,
2467 PM_LOCATION_INIT_UNSET,
2468 ((pm_node_list_t) { 0 }),
2469 ((pm_location_t) { 0 }),
2470 ((pm_location_t) { 0 })
2473 return pm_array_node_new(
2476 PM_NODE_FLAG_STATIC_LITERAL,
2477 PM_LOCATION_INIT_TOKEN(parser, opening),
2478 ((pm_node_list_t) { 0 }),
2479 TOK2LOC(parser, opening),
2480 TOK2LOC(parser, opening)
2488static PRISM_INLINE void
2489pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
2490 if (!node->elements.size && !node->opening_loc.length) {
2491 PM_NODE_START_SET_NODE(node, element);
2494 pm_node_list_append(arena, &node->elements, element);
2495 PM_NODE_LENGTH_SET_NODE(node, element);
2497 // If the element is not a static literal, then the array is not a static
2498 // literal. Turn that flag off.
2499 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)) {
2500 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2503 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2504 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2512pm_array_node_close_set(const pm_parser_t *parser, pm_array_node_t *node, const pm_token_t *closing) {
2513 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == 0);
2514 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2515 node->closing_loc = TOK2LOC(parser, closing);
2522static pm_array_pattern_node_t *
2523pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2524 pm_array_pattern_node_t *node = pm_array_pattern_node_new(
2528 PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2530 ((pm_node_list_t) { 0 }),
2532 ((pm_node_list_t) { 0 }),
2533 ((pm_location_t) { 0 }),
2534 ((pm_location_t) { 0 })
2537 // For now we're going to just copy over each pointer manually. This could be
2538 // much more efficient, as we could instead resize the node list.
2539 bool found_rest = false;
2542 PM_NODE_LIST_FOREACH(nodes, index, child) {
2543 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2546 } else if (found_rest) {
2547 pm_node_list_append(parser->arena, &node->posts, child);
2549 pm_node_list_append(parser->arena, &node->requireds, child);
2559static pm_array_pattern_node_t *
2560pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2561 return pm_array_pattern_node_new(
2565 PM_LOCATION_INIT_NODE(rest),
2567 ((pm_node_list_t) { 0 }),
2569 ((pm_node_list_t) { 0 }),
2570 ((pm_location_t) { 0 }),
2571 ((pm_location_t) { 0 })
2579static pm_array_pattern_node_t *
2580pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2581 return pm_array_pattern_node_new(
2585 PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
2587 ((pm_node_list_t) { 0 }),
2589 ((pm_node_list_t) { 0 }),
2590 TOK2LOC(parser, opening),
2591 TOK2LOC(parser, closing)
2599static pm_array_pattern_node_t *
2600pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2601 return pm_array_pattern_node_new(
2605 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2607 ((pm_node_list_t) { 0 }),
2609 ((pm_node_list_t) { 0 }),
2610 TOK2LOC(parser, opening),
2611 TOK2LOC(parser, closing)
2615static PRISM_INLINE void
2616pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
2617 pm_node_list_append(arena, &node->requireds, inner);
2623static pm_assoc_node_t *
2624pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2627 if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
2628 end = PM_NODE_END(value);
2629 } else if (operator != NULL) {
2630 end = PM_TOKEN_END(parser, operator);
2632 end = PM_NODE_END(key);
2635 // Hash string keys will be frozen, so we can mark them as frozen here so
2636 // that the compiler picks them up and also when we check for static literal
2637 // on the keys it gets factored in.
2638 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2639 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2642 // If the key and value of this assoc node are both static literals, then
2643 // we can mark this node as a static literal.
2644 pm_node_flags_t flags = 0;
2646 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2647 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)
2649 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2652 return pm_assoc_node_new(
2656 ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
2659 NTOK2LOC(parser, operator)
2666static pm_assoc_splat_node_t *
2667pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2668 assert(operator->type == PM_TOKEN_USTAR_STAR);
2670 return pm_assoc_splat_node_new(
2674 (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
2676 TOK2LOC(parser, operator)
2683static pm_back_reference_read_node_t *
2684pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2685 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2687 return pm_back_reference_read_node_new(
2691 PM_LOCATION_INIT_TOKEN(parser, name),
2692 pm_parser_constant_id_token(parser, name)
2699static pm_begin_node_t *
2700pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2701 uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
2702 uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
2704 return pm_begin_node_new(
2708 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2709 NTOK2LOC(parser, begin_keyword),
2714 ((pm_location_t) { 0 })
2722pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2723 if (node->begin_keyword_loc.length == 0) {
2724 PM_NODE_START_SET_NODE(node, rescue_clause);
2726 PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
2727 node->rescue_clause = rescue_clause;
2734pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2735 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2736 PM_NODE_START_SET_NODE(node, else_clause);
2738 PM_NODE_LENGTH_SET_NODE(node, else_clause);
2739 node->else_clause = else_clause;
2746pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2747 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2748 PM_NODE_START_SET_NODE(node, ensure_clause);
2750 PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
2751 node->ensure_clause = ensure_clause;
2758pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
2759 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
2760 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
2761 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
2767static pm_block_argument_node_t *
2768pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2769 assert(operator->type == PM_TOKEN_UAMPERSAND);
2771 return pm_block_argument_node_new(
2775 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
2777 TOK2LOC(parser, operator)
2784static pm_block_node_t *
2785pm_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) {
2786 return pm_block_node_new(
2790 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2794 TOK2LOC(parser, opening),
2795 TOK2LOC(parser, closing)
2802static pm_block_parameter_node_t *
2803pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2804 assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2806 return pm_block_parameter_node_new(
2810 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
2811 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
2812 NTOK2LOC(parser, name),
2813 TOK2LOC(parser, operator)
2820static pm_block_parameters_node_t *
2821pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2823 if (opening != NULL) {
2824 start = PM_TOKEN_START(parser, opening);
2825 } else if (parameters != NULL) {
2826 start = PM_NODE_START(parameters);
2832 if (parameters != NULL) {
2833 end = PM_NODE_END(parameters);
2834 } else if (opening != NULL) {
2835 end = PM_TOKEN_END(parser, opening);
2840 return pm_block_parameters_node_new(
2844 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2846 ((pm_node_list_t) { 0 }),
2847 NTOK2LOC(parser, opening),
2848 ((pm_location_t) { 0 })
2856pm_block_parameters_node_closing_set(const pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_token_t *closing) {
2857 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == 0);
2858 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2859 node->closing_loc = TOK2LOC(parser, closing);
2865static pm_block_local_variable_node_t *
2866pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2867 return pm_block_local_variable_node_new(
2871 PM_LOCATION_INIT_TOKEN(parser, name),
2872 pm_parser_constant_id_token(parser, name)
2880pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2881 pm_node_list_append(arena, &node->locals, UP(local));
2883 if (PM_NODE_LENGTH(node) == 0) {
2884 PM_NODE_START_SET_NODE(node, local);
2887 PM_NODE_LENGTH_SET_NODE(node, local);
2893static pm_break_node_t *
2894pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2895 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2897 return pm_break_node_new(
2901 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
2903 TOK2LOC(parser, keyword)
2907// There are certain flags that we want to use internally but don't want to
2908// expose because they are not relevant beyond parsing. Therefore we'll define
2909// them here and not define them in config.yml/a header file.
2910static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2912static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2913static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2914static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2921static pm_call_node_t *
2922pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2923 return pm_call_node_new(
2927 PM_LOCATION_INIT_UNSET,
2929 ((pm_location_t) { 0 }),
2931 ((pm_location_t) { 0 }),
2932 ((pm_location_t) { 0 }),
2934 ((pm_location_t) { 0 }),
2935 ((pm_location_t) { 0 }),
2944static PRISM_INLINE pm_node_flags_t
2945pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2946 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2953static pm_call_node_t *
2954pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2955 pm_assert_value_expression(parser, receiver);
2957 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2958 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2959 flags |= PM_CALL_NODE_FLAGS_INDEX;
2962 pm_call_node_t *node = pm_call_node_create(parser, flags);
2964 PM_NODE_START_SET_NODE(node, receiver);
2966 const pm_location_t *end = pm_arguments_end(arguments);
2967 assert(end != NULL && "unreachable");
2968 PM_NODE_LENGTH_SET_LOCATION(node, end);
2970 node->receiver = receiver;
2971 node->message_loc.start = arguments->opening_loc.start;
2972 node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
2974 node->opening_loc = arguments->opening_loc;
2975 node->arguments = arguments->arguments;
2976 node->closing_loc = arguments->closing_loc;
2977 node->block = arguments->block;
2979 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2986static pm_call_node_t *
2987pm_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) {
2988 pm_assert_value_expression(parser, receiver);
2989 pm_assert_value_expression(parser, argument);
2991 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2993 PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
2994 PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
2996 node->receiver = receiver;
2997 node->message_loc = TOK2LOC(parser, operator);
2999 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
3000 pm_arguments_node_arguments_append(parser->arena, arguments, argument);
3001 node->arguments = arguments;
3003 node->name = pm_parser_constant_id_token(parser, operator);
3007static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
3012static pm_call_node_t *
3013pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
3014 pm_assert_value_expression(parser, receiver);
3016 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3018 PM_NODE_START_SET_NODE(node, receiver);
3019 const pm_location_t *end = pm_arguments_end(arguments);
3021 PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
3023 PM_NODE_LENGTH_SET_LOCATION(node, end);
3026 node->receiver = receiver;
3027 node->call_operator_loc = TOK2LOC(parser, operator);
3028 node->message_loc = TOK2LOC(parser, message);
3029 node->opening_loc = arguments->opening_loc;
3030 node->arguments = arguments->arguments;
3031 node->closing_loc = arguments->closing_loc;
3032 node->block = arguments->block;
3034 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3035 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3042 node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
3049static pm_call_node_t *
3050pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
3051 pm_call_node_t *node = pm_call_node_create(parser, 0);
3052 node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
3054 node->receiver = receiver;
3055 node->arguments = arguments;
3057 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
3065static pm_call_node_t *
3066pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
3067 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3069 PM_NODE_START_SET_TOKEN(parser, node, message);
3070 const pm_location_t *end = pm_arguments_end(arguments);
3071 assert(end != NULL && "unreachable");
3072 PM_NODE_LENGTH_SET_LOCATION(node, end);
3074 node->message_loc = TOK2LOC(parser, message);
3075 node->opening_loc = arguments->opening_loc;
3076 node->arguments = arguments->arguments;
3077 node->closing_loc = arguments->closing_loc;
3078 node->block = arguments->block;
3080 node->name = pm_parser_constant_id_token(parser, message);
3088static pm_call_node_t *
3089pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
3090 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3092 node->base.location = (pm_location_t) { 0 };
3093 node->arguments = arguments;
3102static pm_call_node_t *
3103pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
3104 pm_assert_value_expression(parser, receiver);
3105 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
3107 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
3109 PM_NODE_START_SET_TOKEN(parser, node, message);
3110 if (arguments->closing_loc.length > 0) {
3111 PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
3113 assert(receiver != NULL);
3114 PM_NODE_LENGTH_SET_NODE(node, receiver);
3117 node->receiver = receiver;
3118 node->message_loc = TOK2LOC(parser, message);
3119 node->opening_loc = arguments->opening_loc;
3120 node->arguments = arguments->arguments;
3121 node->closing_loc = arguments->closing_loc;
3123 node->name = pm_parser_constant_id_constant(parser, "!", 1);
3130static pm_call_node_t *
3131pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
3132 pm_assert_value_expression(parser, receiver);
3134 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3136 PM_NODE_START_SET_NODE(node, receiver);
3137 const pm_location_t *end = pm_arguments_end(arguments);
3138 assert(end != NULL && "unreachable");
3139 PM_NODE_LENGTH_SET_LOCATION(node, end);
3141 node->receiver = receiver;
3142 node->call_operator_loc = TOK2LOC(parser, operator);
3143 node->opening_loc = arguments->opening_loc;
3144 node->arguments = arguments->arguments;
3145 node->closing_loc = arguments->closing_loc;
3146 node->block = arguments->block;
3148 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3149 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3152 node->name = pm_parser_constant_id_constant(parser, "call", 4);
3159static pm_call_node_t *
3160pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
3161 pm_assert_value_expression(parser, receiver);
3163 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3165 PM_NODE_START_SET_TOKEN(parser, node, operator);
3166 PM_NODE_LENGTH_SET_NODE(node, receiver);
3168 node->receiver = receiver;
3169 node->message_loc = TOK2LOC(parser, operator);
3171 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
3179static pm_call_node_t *
3180pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
3181 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3183 node->base.location = TOK2LOC(parser, message);
3184 node->message_loc = TOK2LOC(parser, message);
3186 node->name = pm_parser_constant_id_token(parser, message);
3194static PRISM_INLINE bool
3195pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
3197 (node->message_loc.length > 0) &&
3198 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
3199 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
3200 char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
3201 (node->opening_loc.length == 0) &&
3202 (node->arguments == NULL) &&
3203 (node->block == NULL)
3211pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
3212 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
3214 if (write_constant->length > 0) {
3215 size_t length = write_constant->length - 1;
3217 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
3218 memcpy(memory, write_constant->start, length);
3220 *read_name = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, memory, length);
3222 // We can get here if the message was missing because of a syntax error.
3223 *read_name = pm_parser_constant_id_constant(parser, "", 0);
3230static pm_call_and_write_node_t *
3231pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3232 assert(target->block == NULL);
3233 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3235 pm_call_and_write_node_t *node = pm_call_and_write_node_new(
3239 PM_LOCATION_INIT_NODES(target, value),
3241 target->call_operator_loc,
3242 target->message_loc,
3245 TOK2LOC(parser, operator),
3249 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3251 // The target is no longer necessary because we've reused its children.
3252 // It is arena-allocated so no explicit free is needed.
3262pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
3263 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
3264 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
3266 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
3267 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
3268 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
3274 if (block != NULL) {
3275 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
3283static pm_index_and_write_node_t *
3284pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3285 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3287 pm_index_arguments_check(parser, target->arguments, target->block);
3289 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3291 pm_index_and_write_node_t *node = pm_index_and_write_node_new(
3295 PM_LOCATION_INIT_NODES(target, value),
3297 target->call_operator_loc,
3298 target->opening_loc,
3300 target->closing_loc,
3301 (pm_block_argument_node_t *) target->block,
3302 TOK2LOC(parser, operator),
3306 // The target is no longer necessary because we've reused its children.
3307 // It is arena-allocated so no explicit free is needed.
3315static pm_call_operator_write_node_t *
3316pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3317 assert(target->block == NULL);
3319 pm_call_operator_write_node_t *node = pm_call_operator_write_node_new(
3323 PM_LOCATION_INIT_NODES(target, value),
3325 target->call_operator_loc,
3326 target->message_loc,
3329 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3330 TOK2LOC(parser, operator),
3334 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3336 // The target is no longer necessary because we've reused its children.
3337 // It is arena-allocated so no explicit free is needed.
3345static pm_index_operator_write_node_t *
3346pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3347 pm_index_arguments_check(parser, target->arguments, target->block);
3349 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3351 pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
3355 PM_LOCATION_INIT_NODES(target, value),
3357 target->call_operator_loc,
3358 target->opening_loc,
3360 target->closing_loc,
3361 (pm_block_argument_node_t *) target->block,
3362 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3363 TOK2LOC(parser, operator),
3367 // The target is no longer necessary because we've reused its children.
3368 // It is arena-allocated so no explicit free is needed.
3376static pm_call_or_write_node_t *
3377pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3378 assert(target->block == NULL);
3379 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3381 pm_call_or_write_node_t *node = pm_call_or_write_node_new(
3385 PM_LOCATION_INIT_NODES(target, value),
3387 target->call_operator_loc,
3388 target->message_loc,
3391 TOK2LOC(parser, operator),
3395 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3397 // The target is no longer necessary because we've reused its children.
3398 // It is arena-allocated so no explicit free is needed.
3406static pm_index_or_write_node_t *
3407pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3408 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3410 pm_index_arguments_check(parser, target->arguments, target->block);
3412 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3414 pm_index_or_write_node_t *node = pm_index_or_write_node_new(
3418 PM_LOCATION_INIT_NODES(target, value),
3420 target->call_operator_loc,
3421 target->opening_loc,
3423 target->closing_loc,
3424 (pm_block_argument_node_t *) target->block,
3425 TOK2LOC(parser, operator),
3429 // The target is no longer necessary because we've reused its children.
3430 // It is arena-allocated so no explicit free is needed.
3439static pm_call_target_node_t *
3440pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3441 pm_call_target_node_t *node = pm_call_target_node_new(
3445 PM_LOCATION_INIT_NODE(target),
3447 target->call_operator_loc,
3452 /* It is possible to get here where we have parsed an invalid syntax tree
3453 * where the call operator was not present. In that case we will have a
3454 * problem because it is a required location. In this case we need to fill
3455 * it in with a fake location so that the syntax tree remains valid. */
3456 if (node->call_operator_loc.length == 0) {
3457 node->call_operator_loc = target->base.location;
3460 // The target is no longer necessary because we've reused its children.
3461 // It is arena-allocated so no explicit free is needed.
3470static pm_index_target_node_t *
3471pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3472 pm_index_arguments_check(parser, target->arguments, target->block);
3473 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3475 pm_index_target_node_t *node = pm_index_target_node_new(
3478 FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3479 PM_LOCATION_INIT_NODE(target),
3481 target->opening_loc,
3483 target->closing_loc,
3484 (pm_block_argument_node_t *) target->block
3487 // The target is no longer necessary because we've reused its children.
3488 // It is arena-allocated so no explicit free is needed.
3496static pm_capture_pattern_node_t *
3497pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3498 return pm_capture_pattern_node_new(
3502 PM_LOCATION_INIT_NODES(value, target),
3505 TOK2LOC(parser, operator)
3512static pm_case_node_t *
3513pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3514 return pm_case_node_new(
3518 PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
3520 ((pm_node_list_t) { 0 }),
3522 TOK2LOC(parser, case_keyword),
3523 NTOK2LOC(parser, end_keyword)
3531pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
3532 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3534 pm_node_list_append(arena, &node->conditions, condition);
3535 PM_NODE_LENGTH_SET_NODE(node, condition);
3542pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3543 node->else_clause = else_clause;
3544 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3551pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
3552 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3553 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3559static pm_case_match_node_t *
3560pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
3561 return pm_case_match_node_new(
3565 PM_LOCATION_INIT_TOKEN(parser, case_keyword),
3567 ((pm_node_list_t) { 0 }),
3569 TOK2LOC(parser, case_keyword),
3570 ((pm_location_t) { 0 })
3578pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
3579 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3581 pm_node_list_append(arena, &node->conditions, condition);
3582 PM_NODE_LENGTH_SET_NODE(node, condition);
3589pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3590 node->else_clause = else_clause;
3591 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3598pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3599 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3600 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3606static pm_class_node_t *
3607pm_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) {
3608 return pm_class_node_new(
3612 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
3614 TOK2LOC(parser, class_keyword),
3616 NTOK2LOC(parser, inheritance_operator),
3619 TOK2LOC(parser, end_keyword),
3620 pm_parser_constant_id_token(parser, name)
3627static pm_class_variable_and_write_node_t *
3628pm_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) {
3629 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3631 return pm_class_variable_and_write_node_new(
3635 PM_LOCATION_INIT_NODES(target, value),
3637 target->base.location,
3638 TOK2LOC(parser, operator),
3646static pm_class_variable_operator_write_node_t *
3647pm_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) {
3648 return pm_class_variable_operator_write_node_new(
3652 PM_LOCATION_INIT_NODES(target, value),
3654 target->base.location,
3655 TOK2LOC(parser, operator),
3657 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3664static pm_class_variable_or_write_node_t *
3665pm_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) {
3666 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3668 return pm_class_variable_or_write_node_new(
3672 PM_LOCATION_INIT_NODES(target, value),
3674 target->base.location,
3675 TOK2LOC(parser, operator),
3683static pm_class_variable_read_node_t *
3684pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3685 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3687 return pm_class_variable_read_node_new(
3691 PM_LOCATION_INIT_TOKEN(parser, token),
3692 pm_parser_constant_id_token(parser, token)
3702static PRISM_INLINE pm_node_flags_t
3703pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3704 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
3713static pm_class_variable_write_node_t *
3714pm_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) {
3715 return pm_class_variable_write_node_new(
3718 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3719 PM_LOCATION_INIT_NODES(read_node, value),
3721 read_node->base.location,
3723 TOK2LOC(parser, operator)
3730static pm_constant_path_and_write_node_t *
3731pm_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) {
3732 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3734 return pm_constant_path_and_write_node_new(
3738 PM_LOCATION_INIT_NODES(target, value),
3740 TOK2LOC(parser, operator),
3748static pm_constant_path_operator_write_node_t *
3749pm_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) {
3750 return pm_constant_path_operator_write_node_new(
3754 PM_LOCATION_INIT_NODES(target, value),
3756 TOK2LOC(parser, operator),
3758 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3765static pm_constant_path_or_write_node_t *
3766pm_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) {
3767 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3769 return pm_constant_path_or_write_node_new(
3773 PM_LOCATION_INIT_NODES(target, value),
3775 TOK2LOC(parser, operator),
3783static pm_constant_path_node_t *
3784pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3785 pm_assert_value_expression(parser, parent);
3787 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3788 if (name_token->type == PM_TOKEN_CONSTANT) {
3789 name = pm_parser_constant_id_token(parser, name_token);
3792 return pm_constant_path_node_new(
3796 (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
3799 TOK2LOC(parser, delimiter),
3800 TOK2LOC(parser, name_token)
3807static pm_constant_path_write_node_t *
3808pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3809 return pm_constant_path_write_node_new(
3812 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3813 PM_LOCATION_INIT_NODES(target, value),
3815 TOK2LOC(parser, operator),
3823static pm_constant_and_write_node_t *
3824pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3825 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3827 return pm_constant_and_write_node_new(
3831 PM_LOCATION_INIT_NODES(target, value),
3833 target->base.location,
3834 TOK2LOC(parser, operator),
3842static pm_constant_operator_write_node_t *
3843pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3844 return pm_constant_operator_write_node_new(
3848 PM_LOCATION_INIT_NODES(target, value),
3850 target->base.location,
3851 TOK2LOC(parser, operator),
3853 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3860static pm_constant_or_write_node_t *
3861pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3862 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3864 return pm_constant_or_write_node_new(
3868 PM_LOCATION_INIT_NODES(target, value),
3870 target->base.location,
3871 TOK2LOC(parser, operator),
3879static pm_constant_read_node_t *
3880pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3881 assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
3883 return pm_constant_read_node_new(
3887 PM_LOCATION_INIT_TOKEN(parser, name),
3888 pm_parser_constant_id_token(parser, name)
3895static pm_constant_write_node_t *
3896pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3897 return pm_constant_write_node_new(
3900 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3901 PM_LOCATION_INIT_NODES(target, value),
3903 target->base.location,
3905 TOK2LOC(parser, operator)
3913pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3914 switch (PM_NODE_TYPE(node)) {
3915 case PM_BEGIN_NODE: {
3916 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3917 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3920 case PM_PARENTHESES_NODE: {
3921 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3922 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3925 case PM_STATEMENTS_NODE: {
3926 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3927 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3932 case PM_IMAGINARY_NODE:
3933 case PM_INTEGER_NODE:
3934 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3935 case PM_INTERPOLATED_STRING_NODE:
3936 case PM_INTERPOLATED_SYMBOL_NODE:
3937 case PM_INTERPOLATED_X_STRING_NODE:
3938 case PM_RATIONAL_NODE:
3939 case PM_REGULAR_EXPRESSION_NODE:
3940 case PM_SOURCE_ENCODING_NODE:
3941 case PM_SOURCE_FILE_NODE:
3942 case PM_SOURCE_LINE_NODE:
3943 case PM_STRING_NODE:
3944 case PM_SYMBOL_NODE:
3945 case PM_X_STRING_NODE:
3946 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3956static pm_def_node_t *
3958 pm_parser_t *parser,
3959 pm_constant_id_t name,
3960 const pm_token_t *name_loc,
3961 pm_node_t *receiver,
3962 pm_parameters_node_t *parameters,
3964 pm_constant_id_list_t *locals,
3965 const pm_token_t *def_keyword,
3966 const pm_token_t *operator,
3967 const pm_token_t *lparen,
3968 const pm_token_t *rparen,
3969 const pm_token_t *equal,
3970 const pm_token_t *end_keyword
3972 if (receiver != NULL) {
3973 pm_def_node_receiver_check(parser, receiver);
3976 return pm_def_node_new(
3980 (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
3982 TOK2LOC(parser, name_loc),
3987 TOK2LOC(parser, def_keyword),
3988 NTOK2LOC(parser, operator),
3989 NTOK2LOC(parser, lparen),
3990 NTOK2LOC(parser, rparen),
3991 NTOK2LOC(parser, equal),
3992 NTOK2LOC(parser, end_keyword)
3999static pm_defined_node_t *
4000pm_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) {
4001 return pm_defined_node_new(
4005 (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
4006 NTOK2LOC(parser, lparen),
4008 NTOK2LOC(parser, rparen),
4009 TOK2LOC(parser, keyword)
4016static pm_else_node_t *
4017pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4018 return pm_else_node_new(
4022 ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
4023 TOK2LOC(parser, else_keyword),
4025 NTOK2LOC(parser, end_keyword)
4032static pm_embedded_statements_node_t *
4033pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
4034 return pm_embedded_statements_node_new(
4038 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4039 TOK2LOC(parser, opening),
4041 TOK2LOC(parser, closing)
4048static pm_embedded_variable_node_t *
4049pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
4050 return pm_embedded_variable_node_new(
4054 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
4055 TOK2LOC(parser, operator),
4063static pm_ensure_node_t *
4064pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4065 return pm_ensure_node_new(
4069 PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
4070 TOK2LOC(parser, ensure_keyword),
4072 TOK2LOC(parser, end_keyword)
4079static pm_false_node_t *
4080pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4081 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4083 return pm_false_node_new(
4086 PM_NODE_FLAG_STATIC_LITERAL,
4087 PM_LOCATION_INIT_TOKEN(parser, token)
4095static pm_find_pattern_node_t *
4096pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4097 assert(nodes->size >= 2);
4098 pm_node_t *left = nodes->nodes[0];
4099 pm_node_t *right = nodes->nodes[nodes->size - 1];
4101 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4102 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4104 pm_find_pattern_node_t *node = pm_find_pattern_node_new(
4108 PM_LOCATION_INIT_NODES(left, right),
4110 (pm_splat_node_t *) left,
4111 ((pm_node_list_t) { 0 }),
4112 (pm_splat_node_t *) right,
4113 ((pm_location_t) { 0 }),
4114 ((pm_location_t) { 0 })
4117 // For now we're going to just copy over each pointer manually. This could be
4118 // much more efficient, as we could instead resize the node list to only point
4120 for (size_t index = 1; index < nodes->size - 1; index++) {
4121 pm_node_list_append(parser->arena, &node->requireds, nodes->nodes[index]);
4132pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4133 ptrdiff_t diff = token->end - token->start;
4134 if (diff <= 0) return 0.0;
4136 // First, get a buffer of the content.
4137 size_t length = (size_t) diff;
4138 const size_t buffer_size = sizeof(char) * (length + 1);
4139 char *buffer = xmalloc(buffer_size);
4140 memcpy((void *) buffer, token->start, length);
4142 // Next, determine if we need to replace the decimal point because of
4143 // locale-specific options, and then normalize them if we have to.
4144 char decimal_point = *localeconv()->decimal_point;
4145 if (decimal_point != '.') {
4146 for (size_t index = 0; index < length; index++) {
4147 if (buffer[index] == '.') buffer[index] = decimal_point;
4151 // Next, handle underscores by removing them from the buffer.
4152 for (size_t index = 0; index < length; index++) {
4153 if (buffer[index] == '_') {
4154 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
4159 // Null-terminate the buffer so that strtod cannot read off the end.
4160 buffer[length] = '\0';
4162 // Now, call strtod to parse the value. Note that CRuby has their own
4163 // version of strtod which avoids locales. We're okay using the locale-aware
4164 // version because we've already validated through the parser that the token
4165 // is in a valid format.
4168 double value = strtod(buffer, &eptr);
4170 // This should never happen, because we've already checked that the token
4171 // is in a valid format. However it's good to be safe.
4172 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4173 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
4174 xfree_sized(buffer, buffer_size);
4178 // If errno is set, then it should only be ERANGE. At this point we need to
4179 // check if it's infinity (it should be).
4180 if (errno == ERANGE && PRISM_ISINF(value)) {
4182 const char *ellipsis;
4188 warn_width = (int) length;
4192 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);
4193 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4196 // Finally we can free the buffer and return the value.
4197 xfree_sized(buffer, buffer_size);
4204static pm_float_node_t *
4205pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4206 assert(token->type == PM_TOKEN_FLOAT);
4208 return pm_float_node_new(
4211 PM_NODE_FLAG_STATIC_LITERAL,
4212 PM_LOCATION_INIT_TOKEN(parser, token),
4213 pm_double_parse(parser, token)
4220static pm_imaginary_node_t *
4221pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4222 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4224 return pm_imaginary_node_new(
4227 PM_NODE_FLAG_STATIC_LITERAL,
4228 PM_LOCATION_INIT_TOKEN(parser, token),
4229 UP(pm_float_node_create(parser, &((pm_token_t) {
4230 .type = PM_TOKEN_FLOAT,
4231 .start = token->start,
4232 .end = token->end - 1
4240static pm_rational_node_t *
4241pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4242 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4244 pm_rational_node_t *node = pm_rational_node_new(
4247 PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4248 PM_LOCATION_INIT_TOKEN(parser, token),
4249 ((pm_integer_t) { 0 }),
4250 ((pm_integer_t) { 0 })
4253 const uint8_t *start = token->start;
4254 const uint8_t *end = token->end - 1; // r
4256 while (start < end && *start == '0') start++; // 0.1 -> .1
4257 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4259 size_t length = (size_t) (end - start);
4261 node->denominator.value = 1;
4265 const uint8_t *point = memchr(start, '.', length);
4266 assert(point && "should have a decimal point");
4268 uint8_t *digits = xmalloc(length);
4269 if (digits == NULL) {
4270 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
4274 memcpy(digits, start, (unsigned long) (point - start));
4275 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4276 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4278 size_t fract_length = 0;
4279 for (const uint8_t *fract = point; fract < end; ++fract) {
4280 if (*fract != '_') ++fract_length;
4283 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
4284 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
4285 xfree_sized(digits, length);
4287 pm_integers_reduce(&node->numerator, &node->denominator);
4288 pm_integer_arena_move(parser->arena, &node->numerator);
4289 pm_integer_arena_move(parser->arena, &node->denominator);
4297static pm_imaginary_node_t *
4298pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4299 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4301 return pm_imaginary_node_new(
4304 PM_NODE_FLAG_STATIC_LITERAL,
4305 PM_LOCATION_INIT_TOKEN(parser, token),
4306 UP(pm_float_node_rational_create(parser, &((pm_token_t) {
4307 .type = PM_TOKEN_FLOAT_RATIONAL,
4308 .start = token->start,
4309 .end = token->end - 1
4317static pm_for_node_t *
4319 pm_parser_t *parser,
4321 pm_node_t *collection,
4322 pm_statements_node_t *statements,
4323 const pm_token_t *for_keyword,
4324 const pm_token_t *in_keyword,
4325 const pm_token_t *do_keyword,
4326 const pm_token_t *end_keyword
4328 return pm_for_node_new(
4332 PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
4336 TOK2LOC(parser, for_keyword),
4337 TOK2LOC(parser, in_keyword),
4338 NTOK2LOC(parser, do_keyword),
4339 TOK2LOC(parser, end_keyword)
4346static pm_forwarding_arguments_node_t *
4347pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4348 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4350 return pm_forwarding_arguments_node_new(
4354 PM_LOCATION_INIT_TOKEN(parser, token)
4361static pm_forwarding_parameter_node_t *
4362pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4363 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4365 return pm_forwarding_parameter_node_new(
4369 PM_LOCATION_INIT_TOKEN(parser, token)
4376static pm_forwarding_super_node_t *
4377pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4378 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4379 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4381 pm_block_node_t *block = NULL;
4382 if (arguments->block != NULL) {
4383 block = (pm_block_node_t *) arguments->block;
4386 return pm_forwarding_super_node_new(
4390 (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
4391 PM_LOCATION_INIT_TOKEN(parser, token),
4400static pm_hash_pattern_node_t *
4401pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4402 return pm_hash_pattern_node_new(
4406 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4408 ((pm_node_list_t) { 0 }),
4410 TOK2LOC(parser, opening),
4411 TOK2LOC(parser, closing)
4418static pm_hash_pattern_node_t *
4419pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4423 if (elements->size > 0) {
4425 start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
4426 end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
4428 start = PM_NODE_START(elements->nodes[0]);
4429 end = PM_NODE_END(elements->nodes[elements->size - 1]);
4432 assert(rest != NULL);
4433 start = PM_NODE_START(rest);
4434 end = PM_NODE_END(rest);
4437 pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
4441 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4443 ((pm_node_list_t) { 0 }),
4445 ((pm_location_t) { 0 }),
4446 ((pm_location_t) { 0 })
4449 pm_node_list_concat(parser->arena, &node->elements, elements);
4456static pm_constant_id_t
4457pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4458 switch (PM_NODE_TYPE(target)) {
4459 case PM_GLOBAL_VARIABLE_READ_NODE:
4460 return ((pm_global_variable_read_node_t *) target)->name;
4461 case PM_BACK_REFERENCE_READ_NODE:
4462 return ((pm_back_reference_read_node_t *) target)->name;
4463 case PM_NUMBERED_REFERENCE_READ_NODE:
4464 // This will only ever happen in the event of a syntax error, but we
4465 // still need to provide something for the node.
4466 return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
4468 assert(false && "unreachable");
4469 return (pm_constant_id_t) -1;
4476static pm_global_variable_and_write_node_t *
4477pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4478 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4480 return pm_global_variable_and_write_node_new(
4484 PM_LOCATION_INIT_NODES(target, value),
4485 pm_global_variable_write_name(parser, target),
4487 TOK2LOC(parser, operator),
4495static pm_global_variable_operator_write_node_t *
4496pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4497 return pm_global_variable_operator_write_node_new(
4501 PM_LOCATION_INIT_NODES(target, value),
4502 pm_global_variable_write_name(parser, target),
4504 TOK2LOC(parser, operator),
4506 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4513static pm_global_variable_or_write_node_t *
4514pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4515 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4517 return pm_global_variable_or_write_node_new(
4521 PM_LOCATION_INIT_NODES(target, value),
4522 pm_global_variable_write_name(parser, target),
4524 TOK2LOC(parser, operator),
4532static pm_global_variable_read_node_t *
4533pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4534 return pm_global_variable_read_node_new(
4538 PM_LOCATION_INIT_TOKEN(parser, name),
4539 pm_parser_constant_id_token(parser, name)
4546static pm_global_variable_read_node_t *
4547pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4548 return pm_global_variable_read_node_new(
4552 PM_LOCATION_INIT_UNSET,
4560static pm_global_variable_write_node_t *
4561pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4562 return pm_global_variable_write_node_new(
4565 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4566 PM_LOCATION_INIT_NODES(target, value),
4567 pm_global_variable_write_name(parser, target),
4570 TOK2LOC(parser, operator)
4577static pm_global_variable_write_node_t *
4578pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4579 return pm_global_variable_write_node_new(
4583 PM_LOCATION_INIT_UNSET,
4585 ((pm_location_t) { 0 }),
4587 ((pm_location_t) { 0 })
4594static pm_hash_node_t *
4595pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4596 assert(opening != NULL);
4598 return pm_hash_node_new(
4601 PM_NODE_FLAG_STATIC_LITERAL,
4602 PM_LOCATION_INIT_TOKEN(parser, opening),
4603 TOK2LOC(parser, opening),
4604 ((pm_node_list_t) { 0 }),
4605 ((pm_location_t) { 0 })
4612static PRISM_INLINE void
4613pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
4614 pm_node_list_append(arena, &hash->elements, element);
4616 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4617 if (static_literal) {
4618 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4619 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);
4620 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4621 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4624 if (!static_literal) {
4625 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4629static PRISM_INLINE void
4630pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
4631 PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
4632 hash->closing_loc = TOK2LOC(parser, token);
4638static pm_if_node_t *
4639pm_if_node_create(pm_parser_t *parser,
4640 const pm_token_t *if_keyword,
4641 pm_node_t *predicate,
4642 const pm_token_t *then_keyword,
4643 pm_statements_node_t *statements,
4644 pm_node_t *subsequent,
4645 const pm_token_t *end_keyword
4647 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4649 uint32_t start = PM_TOKEN_START(parser, if_keyword);
4652 if (end_keyword != NULL) {
4653 end = PM_TOKEN_END(parser, end_keyword);
4654 } else if (subsequent != NULL) {
4655 end = PM_NODE_END(subsequent);
4656 } else if (pm_statements_node_body_length(statements) != 0) {
4657 end = PM_NODE_END(statements);
4659 end = PM_NODE_END(predicate);
4662 return pm_if_node_new(
4665 PM_NODE_FLAG_NEWLINE,
4666 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4667 TOK2LOC(parser, if_keyword),
4669 NTOK2LOC(parser, then_keyword),
4672 NTOK2LOC(parser, end_keyword)
4679static pm_if_node_t *
4680pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4681 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4683 pm_statements_node_t *statements = pm_statements_node_create(parser);
4684 pm_statements_node_body_append(parser, statements, statement, true);
4686 return pm_if_node_new(
4689 PM_NODE_FLAG_NEWLINE,
4690 PM_LOCATION_INIT_NODES(statement, predicate),
4691 TOK2LOC(parser, if_keyword),
4693 ((pm_location_t) { 0 }),
4696 ((pm_location_t) { 0 })
4703static pm_if_node_t *
4704pm_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) {
4705 pm_assert_value_expression(parser, predicate);
4706 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4708 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4709 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4711 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4712 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4714 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
4715 return pm_if_node_new(
4718 PM_NODE_FLAG_NEWLINE,
4719 PM_LOCATION_INIT_NODES(predicate, false_expression),
4720 ((pm_location_t) { 0 }),
4722 TOK2LOC(parser, qmark),
4725 ((pm_location_t) { 0 })
4729static PRISM_INLINE void
4730pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
4731 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4732 node->end_keyword_loc = TOK2LOC(parser, keyword);
4735static PRISM_INLINE void
4736pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
4737 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4738 node->end_keyword_loc = TOK2LOC(parser, keyword);
4744static pm_implicit_node_t *
4745pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4746 return pm_implicit_node_new(
4750 PM_LOCATION_INIT_NODE(value),
4758static pm_implicit_rest_node_t *
4759pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4760 assert(token->type == PM_TOKEN_COMMA);
4762 return pm_implicit_rest_node_new(
4766 PM_LOCATION_INIT_TOKEN(parser, token)
4773static pm_integer_node_t *
4774pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4775 assert(token->type == PM_TOKEN_INTEGER);
4777 pm_integer_node_t *node = pm_integer_node_new(
4780 base | PM_NODE_FLAG_STATIC_LITERAL,
4781 PM_LOCATION_INIT_TOKEN(parser, token),
4782 ((pm_integer_t) { 0 })
4785 if (parser->integer.lexed) {
4786 // The value was already computed during lexing.
4787 node->value.value = parser->integer.value;
4788 parser->integer.lexed = false;
4790 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4792 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4793 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4794 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4795 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4796 default: assert(false && "unreachable"); break;
4799 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4800 pm_integer_arena_move(parser->arena, &node->value);
4810static pm_imaginary_node_t *
4811pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4812 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4814 return pm_imaginary_node_new(
4817 PM_NODE_FLAG_STATIC_LITERAL,
4818 PM_LOCATION_INIT_TOKEN(parser, token),
4819 UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4820 .type = PM_TOKEN_INTEGER,
4821 .start = token->start,
4822 .end = token->end - 1
4831static pm_rational_node_t *
4832pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4833 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4835 pm_rational_node_t *node = pm_rational_node_new(
4838 base | PM_NODE_FLAG_STATIC_LITERAL,
4839 PM_LOCATION_INIT_TOKEN(parser, token),
4840 ((pm_integer_t) { 0 }),
4841 ((pm_integer_t) { .value = 1 })
4844 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4846 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4847 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4848 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4849 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4850 default: assert(false && "unreachable"); break;
4853 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4854 pm_integer_arena_move(parser->arena, &node->numerator);
4863static pm_imaginary_node_t *
4864pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4865 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4867 return pm_imaginary_node_new(
4870 PM_NODE_FLAG_STATIC_LITERAL,
4871 PM_LOCATION_INIT_TOKEN(parser, token),
4872 UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4873 .type = PM_TOKEN_INTEGER_RATIONAL,
4874 .start = token->start,
4875 .end = token->end - 1
4883static pm_in_node_t *
4884pm_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) {
4885 uint32_t start = PM_TOKEN_START(parser, in_keyword);
4888 if (statements != NULL) {
4889 end = PM_NODE_END(statements);
4890 } else if (then_keyword != NULL) {
4891 end = PM_TOKEN_END(parser, then_keyword);
4893 end = PM_NODE_END(pattern);
4896 return pm_in_node_new(
4900 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4903 TOK2LOC(parser, in_keyword),
4904 NTOK2LOC(parser, then_keyword)
4911static pm_instance_variable_and_write_node_t *
4912pm_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) {
4913 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4915 return pm_instance_variable_and_write_node_new(
4919 PM_LOCATION_INIT_NODES(target, value),
4921 target->base.location,
4922 TOK2LOC(parser, operator),
4930static pm_instance_variable_operator_write_node_t *
4931pm_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) {
4932 return pm_instance_variable_operator_write_node_new(
4936 PM_LOCATION_INIT_NODES(target, value),
4938 target->base.location,
4939 TOK2LOC(parser, operator),
4941 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4948static pm_instance_variable_or_write_node_t *
4949pm_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) {
4950 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4952 return pm_instance_variable_or_write_node_new(
4956 PM_LOCATION_INIT_NODES(target, value),
4958 target->base.location,
4959 TOK2LOC(parser, operator),
4967static pm_instance_variable_read_node_t *
4968pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4969 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4971 return pm_instance_variable_read_node_new(
4975 PM_LOCATION_INIT_TOKEN(parser, token),
4976 pm_parser_constant_id_token(parser, token)
4984static pm_instance_variable_write_node_t *
4985pm_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) {
4986 return pm_instance_variable_write_node_new(
4989 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4990 PM_LOCATION_INIT_NODES(read_node, value),
4992 read_node->base.location,
4994 TOK2LOC(parser, operator)
5004pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
5005 switch (PM_NODE_TYPE(part)) {
5006 case PM_STRING_NODE:
5007 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5009 case PM_EMBEDDED_STATEMENTS_NODE: {
5010 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5011 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5013 if (embedded == NULL) {
5014 // If there are no statements or more than one statement, then
5015 // we lose the static literal flag.
5016 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5017 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5018 // If the embedded statement is a string, then we can keep the
5019 // static literal flag and mark the string as frozen.
5020 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5021 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5022 // If the embedded statement is an interpolated string and it's
5023 // a static literal, then we can keep the static literal flag.
5025 // Otherwise we lose the static literal flag.
5026 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5031 case PM_EMBEDDED_VARIABLE_NODE:
5032 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5035 assert(false && "unexpected node type");
5039 pm_node_list_append(arena, parts, part);
5045static pm_interpolated_regular_expression_node_t *
5046pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5047 return pm_interpolated_regular_expression_node_new(
5050 PM_NODE_FLAG_STATIC_LITERAL,
5051 PM_LOCATION_INIT_TOKEN(parser, opening),
5052 TOK2LOC(parser, opening),
5053 ((pm_node_list_t) { 0 }),
5054 TOK2LOC(parser, opening)
5058static PRISM_INLINE void
5059pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5060 if (PM_NODE_START(node) > PM_NODE_START(part)) {
5061 PM_NODE_START_SET_NODE(node, part);
5063 if (PM_NODE_END(node) < PM_NODE_END(part)) {
5064 PM_NODE_LENGTH_SET_NODE(node, part);
5067 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5070static PRISM_INLINE void
5071pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5072 node->closing_loc = TOK2LOC(parser, closing);
5073 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5074 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
5100static PRISM_INLINE void
5101pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
5102 pm_arena_t *arena = parser->arena;
5103#define CLEAR_FLAGS(node) \
5104 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))
5106#define MUTABLE_FLAGS(node) \
5107 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5109 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5110 PM_NODE_START_SET_NODE(node, part);
5113 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5114 PM_NODE_LENGTH_SET_NODE(node, part);
5117 switch (PM_NODE_TYPE(part)) {
5118 case PM_STRING_NODE:
5119 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5120 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5121 // as long as this interpolation only consists of other string literals.
5122 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5123 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5125 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5127 case PM_INTERPOLATED_STRING_NODE:
5128 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5129 // If the string that we're concatenating is a static literal,
5130 // then we can keep the static literal flag for this string.
5132 // Otherwise, we lose the static literal flag here and we should
5133 // also clear the mutability flags.
5137 case PM_EMBEDDED_STATEMENTS_NODE: {
5138 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5139 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5141 if (embedded == NULL) {
5142 // If we're embedding multiple statements or no statements, then
5143 // the string is not longer a static literal.
5145 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5146 // If the embedded statement is a string, then we can make that
5147 // string as frozen and static literal, and not touch the static
5148 // literal status of this string.
5149 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5151 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5152 MUTABLE_FLAGS(node);
5154 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5155 // If the embedded statement is an interpolated string, but that
5156 // string is marked as static literal, then we can keep our
5157 // static literal status for this string.
5158 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5159 MUTABLE_FLAGS(node);
5162 // In all other cases, we lose the static literal flag here and
5169 case PM_EMBEDDED_VARIABLE_NODE:
5170 // Embedded variables clear static literal, which means we also
5171 // should clear the mutability flags.
5174 case PM_X_STRING_NODE:
5175 case PM_INTERPOLATED_X_STRING_NODE:
5176 case PM_SYMBOL_NODE:
5177 case PM_INTERPOLATED_SYMBOL_NODE:
5178 // These will only happen in error cases. But we want to handle it
5179 // here so that we don't fail the assertion.
5181 pm_node_list_append(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
5183 case PM_ERROR_RECOVERY_NODE:
5187 assert(false && "unexpected node type");
5191 pm_node_list_append(arena, &node->parts, part);
5200static pm_interpolated_string_node_t *
5201pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5202 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5204 switch (parser->frozen_string_literal) {
5205 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5206 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5208 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5209 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5213 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5214 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5216 pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
5220 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5221 NTOK2LOC(parser, opening),
5222 ((pm_node_list_t) { 0 }),
5223 NTOK2LOC(parser, closing)
5226 if (parts != NULL) {
5228 PM_NODE_LIST_FOREACH(parts, index, part) {
5229 pm_interpolated_string_node_append(parser, node, part);
5240pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5241 node->closing_loc = TOK2LOC(parser, closing);
5242 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5246pm_interpolated_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5247 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5248 PM_NODE_START_SET_NODE(node, part);
5251 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5253 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5254 PM_NODE_LENGTH_SET_NODE(node, part);
5259pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5260 node->closing_loc = TOK2LOC(parser, closing);
5261 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5267static pm_interpolated_symbol_node_t *
5268pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5269 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5270 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5272 pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
5275 PM_NODE_FLAG_STATIC_LITERAL,
5276 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5277 NTOK2LOC(parser, opening),
5278 ((pm_node_list_t) { 0 }),
5279 NTOK2LOC(parser, closing)
5282 if (parts != NULL) {
5284 PM_NODE_LIST_FOREACH(parts, index, part) {
5285 pm_interpolated_symbol_node_append(parser->arena, node, part);
5295static pm_interpolated_x_string_node_t *
5296pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5297 return pm_interpolated_x_string_node_new(
5301 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5302 TOK2LOC(parser, opening),
5303 ((pm_node_list_t) { 0 }),
5304 TOK2LOC(parser, closing)
5308static PRISM_INLINE void
5309pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5310 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5311 PM_NODE_LENGTH_SET_NODE(node, part);
5314static PRISM_INLINE void
5315pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5316 node->closing_loc = TOK2LOC(parser, closing);
5317 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5323static pm_it_local_variable_read_node_t *
5324pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5325 return pm_it_local_variable_read_node_new(
5329 PM_LOCATION_INIT_TOKEN(parser, name)
5336static pm_it_parameters_node_t *
5337pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5338 return pm_it_parameters_node_new(
5342 PM_LOCATION_INIT_TOKENS(parser, opening, closing)
5349static pm_keyword_hash_node_t *
5350pm_keyword_hash_node_create(pm_parser_t *parser) {
5351 return pm_keyword_hash_node_new(
5354 PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5355 PM_LOCATION_INIT_UNSET,
5356 ((pm_node_list_t) { 0 })
5364pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *hash, pm_node_t *element) {
5365 // If the element being added is not an AssocNode or does not have a symbol
5366 // key, then we want to turn the SYMBOL_KEYS flag off.
5367 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5368 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5371 pm_node_list_append(arena, &hash->elements, element);
5372 if (PM_NODE_LENGTH(hash) == 0) {
5373 PM_NODE_START_SET_NODE(hash, element);
5375 PM_NODE_LENGTH_SET_NODE(hash, element);
5381static pm_required_keyword_parameter_node_t *
5382pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5383 return pm_required_keyword_parameter_node_new(
5387 PM_LOCATION_INIT_TOKEN(parser, name),
5388 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5389 TOK2LOC(parser, name)
5396static pm_optional_keyword_parameter_node_t *
5397pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5398 return pm_optional_keyword_parameter_node_new(
5402 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5403 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5404 TOK2LOC(parser, name),
5412static pm_keyword_rest_parameter_node_t *
5413pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5414 return pm_keyword_rest_parameter_node_new(
5418 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
5419 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
5420 NTOK2LOC(parser, name),
5421 TOK2LOC(parser, operator)
5428static pm_lambda_node_t *
5429pm_lambda_node_create(
5430 pm_parser_t *parser,
5431 pm_constant_id_list_t *locals,
5432 const pm_token_t *operator,
5433 const pm_token_t *opening,
5434 const pm_token_t *closing,
5435 pm_node_t *parameters,
5438 return pm_lambda_node_new(
5442 PM_LOCATION_INIT_TOKENS(parser, operator, closing),
5444 TOK2LOC(parser, operator),
5445 TOK2LOC(parser, opening),
5446 TOK2LOC(parser, closing),
5455static pm_local_variable_and_write_node_t *
5456pm_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) {
5457 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));
5458 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5460 return pm_local_variable_and_write_node_new(
5464 PM_LOCATION_INIT_NODES(target, value),
5466 TOK2LOC(parser, operator),
5476static pm_local_variable_operator_write_node_t *
5477pm_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) {
5478 return pm_local_variable_operator_write_node_new(
5482 PM_LOCATION_INIT_NODES(target, value),
5484 TOK2LOC(parser, operator),
5487 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
5495static pm_local_variable_or_write_node_t *
5496pm_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) {
5497 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));
5498 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5500 return pm_local_variable_or_write_node_new(
5504 PM_LOCATION_INIT_NODES(target, value),
5506 TOK2LOC(parser, operator),
5516static pm_local_variable_read_node_t *
5517pm_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) {
5518 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5520 return pm_local_variable_read_node_new(
5524 PM_LOCATION_INIT_TOKEN(parser, name),
5533static pm_local_variable_read_node_t *
5534pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5535 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5536 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5543static pm_local_variable_read_node_t *
5544pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5545 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5546 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5552static pm_local_variable_write_node_t *
5553pm_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) {
5554 return pm_local_variable_write_node_new(
5557 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5558 ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
5563 TOK2LOC(parser, operator)
5570static PRISM_INLINE bool
5571pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5572 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5579static PRISM_INLINE bool
5580pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
5583 (parser->start[start] == '_') &&
5584 (parser->start[start + 1] != '0') &&
5585 pm_char_is_decimal_digit(parser->start[start + 1])
5593static PRISM_INLINE void
5594pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
5595 if (pm_token_is_numbered_parameter(parser, start, length)) {
5596 PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
5604static pm_local_variable_target_node_t *
5605pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5606 pm_refute_numbered_parameter(parser, location->start, location->length);
5608 return pm_local_variable_target_node_new(
5612 ((pm_location_t) { .start = location->start, .length = location->length }),
5621static pm_match_predicate_node_t *
5622pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5623 pm_assert_value_expression(parser, value);
5625 return pm_match_predicate_node_new(
5629 PM_LOCATION_INIT_NODES(value, pattern),
5632 TOK2LOC(parser, operator)
5639static pm_match_required_node_t *
5640pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5641 pm_assert_value_expression(parser, value);
5643 return pm_match_required_node_new(
5647 PM_LOCATION_INIT_NODES(value, pattern),
5650 TOK2LOC(parser, operator)
5657static pm_match_write_node_t *
5658pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5659 return pm_match_write_node_new(
5663 PM_LOCATION_INIT_NODE(call),
5665 ((pm_node_list_t) { 0 })
5672static pm_module_node_t *
5673pm_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) {
5674 pm_constant_id_list_t module_locals = { .ids = NULL, .size = 0, .capacity = 0 };
5675 if (locals != NULL) module_locals = *locals;
5677 return pm_module_node_new(
5681 PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
5683 TOK2LOC(parser, module_keyword),
5686 TOK2LOC(parser, end_keyword),
5687 pm_parser_constant_id_token(parser, name)
5694static pm_multi_target_node_t *
5695pm_multi_target_node_create(pm_parser_t *parser) {
5696 return pm_multi_target_node_new(
5700 PM_LOCATION_INIT_UNSET,
5701 ((pm_node_list_t) { 0 }),
5703 ((pm_node_list_t) { 0 }),
5704 ((pm_location_t) { 0 }),
5705 ((pm_location_t) { 0 })
5713pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5714 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5715 if (node->rest == NULL) {
5716 node->rest = target;
5718 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5719 pm_node_list_append(parser->arena, &node->rights, target);
5721 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5722 if (node->rest == NULL) {
5723 node->rest = target;
5725 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5726 pm_node_list_append(parser->arena, &node->rights, target);
5728 } else if (node->rest == NULL) {
5729 pm_node_list_append(parser->arena, &node->lefts, target);
5731 pm_node_list_append(parser->arena, &node->rights, target);
5734 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
5735 PM_NODE_START_SET_NODE(node, target);
5738 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
5739 PM_NODE_LENGTH_SET_NODE(node, target);
5747pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
5748 PM_NODE_START_SET_TOKEN(parser, node, lparen);
5749 PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
5750 node->lparen_loc = TOK2LOC(parser, lparen);
5757pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
5758 PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
5759 node->rparen_loc = TOK2LOC(parser, rparen);
5765static pm_multi_write_node_t *
5766pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5767 /* The target is no longer necessary because we have reused its children. It
5768 * is arena-allocated so no explicit free is needed. */
5769 return pm_multi_write_node_new(
5772 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5773 PM_LOCATION_INIT_NODES(target, value),
5779 TOK2LOC(parser, operator),
5787static pm_next_node_t *
5788pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5789 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5791 return pm_next_node_new(
5795 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
5797 TOK2LOC(parser, keyword)
5804static pm_nil_node_t *
5805pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5806 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5808 return pm_nil_node_new(
5811 PM_NODE_FLAG_STATIC_LITERAL,
5812 PM_LOCATION_INIT_TOKEN(parser, token)
5819static pm_no_block_parameter_node_t *
5820pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5821 assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5822 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5824 return pm_no_block_parameter_node_new(
5828 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5829 TOK2LOC(parser, operator),
5830 TOK2LOC(parser, keyword)
5837static pm_no_keywords_parameter_node_t *
5838pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5839 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5840 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5842 return pm_no_keywords_parameter_node_new(
5846 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5847 TOK2LOC(parser, operator),
5848 TOK2LOC(parser, keyword)
5855static pm_numbered_parameters_node_t *
5856pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
5857 return pm_numbered_parameters_node_new(
5861 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5870#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5879pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5880 const uint8_t *start = token->start + 1;
5881 const uint8_t *end = token->end;
5883 ptrdiff_t diff = end - start;
5885#if PTRDIFF_MAX > SIZE_MAX
5886 assert(diff < (ptrdiff_t) SIZE_MAX);
5888 size_t length = (size_t) diff;
5890 char *digits = xcalloc(length + 1, sizeof(char));
5891 memcpy(digits, start, length);
5892 digits[length] = '\0';
5896 unsigned long value = strtoul(digits, &endptr, 10);
5898 if ((digits == endptr) || (*endptr != '\0')) {
5899 pm_parser_err(parser, U32(start - parser->start), U32(length), PM_ERR_INVALID_NUMBER_DECIMAL);
5903 xfree_sized(digits, sizeof(char) * (length + 1));
5905 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5906 PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5910 return (uint32_t) value;
5918static pm_numbered_reference_read_node_t *
5919pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5920 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5922 return pm_numbered_reference_read_node_new(
5926 PM_LOCATION_INIT_TOKEN(parser, name),
5927 pm_numbered_reference_read_node_number(parser, name)
5934static pm_optional_parameter_node_t *
5935pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5936 return pm_optional_parameter_node_new(
5940 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5941 pm_parser_constant_id_token(parser, name),
5942 TOK2LOC(parser, name),
5943 TOK2LOC(parser, operator),
5951static pm_or_node_t *
5952pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5953 pm_assert_value_expression(parser, left);
5955 return pm_or_node_new(
5959 PM_LOCATION_INIT_NODES(left, right),
5962 TOK2LOC(parser, operator)
5969static pm_parameters_node_t *
5970pm_parameters_node_create(pm_parser_t *parser) {
5971 return pm_parameters_node_new(
5975 PM_LOCATION_INIT_UNSET,
5976 ((pm_node_list_t) { 0 }),
5977 ((pm_node_list_t) { 0 }),
5979 ((pm_node_list_t) { 0 }),
5980 ((pm_node_list_t) { 0 }),
5990pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5991 if ((params->base.location.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
5992 PM_NODE_START_SET_NODE(params, param);
5995 if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
5996 PM_NODE_LENGTH_SET_NODE(params, param);
6004pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6005 pm_parameters_node_location_set(params, param);
6006 pm_node_list_append(arena, ¶ms->requireds, param);
6013pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
6014 pm_parameters_node_location_set(params, UP(param));
6015 pm_node_list_append(arena, ¶ms->optionals, UP(param));
6022pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6023 pm_parameters_node_location_set(params, param);
6024 pm_node_list_append(arena, ¶ms->posts, param);
6031pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6032 pm_parameters_node_location_set(params, param);
6033 params->rest = param;
6040pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6041 pm_parameters_node_location_set(params, param);
6042 pm_node_list_append(arena, ¶ms->keywords, param);
6049pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6050 assert(params->keyword_rest == NULL);
6051 pm_parameters_node_location_set(params, param);
6052 params->keyword_rest = param;
6059pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
6060 assert(params->block == NULL);
6061 pm_parameters_node_location_set(params, param);
6062 params->block = param;
6068static pm_program_node_t *
6069pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6070 return pm_program_node_new(
6074 PM_LOCATION_INIT_NODE(statements),
6083static pm_parentheses_node_t *
6084pm_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) {
6085 return pm_parentheses_node_new(
6089 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6091 TOK2LOC(parser, opening),
6092 TOK2LOC(parser, closing)
6099static pm_pinned_expression_node_t *
6100pm_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) {
6101 return pm_pinned_expression_node_new(
6105 PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
6107 TOK2LOC(parser, operator),
6108 TOK2LOC(parser, lparen),
6109 TOK2LOC(parser, rparen)
6116static pm_pinned_variable_node_t *
6117pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6118 return pm_pinned_variable_node_new(
6122 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
6124 TOK2LOC(parser, operator)
6131static pm_post_execution_node_t *
6132pm_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) {
6133 return pm_post_execution_node_new(
6137 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6139 TOK2LOC(parser, keyword),
6140 TOK2LOC(parser, opening),
6141 TOK2LOC(parser, closing)
6148static pm_pre_execution_node_t *
6149pm_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) {
6150 return pm_pre_execution_node_new(
6154 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6156 TOK2LOC(parser, keyword),
6157 TOK2LOC(parser, opening),
6158 TOK2LOC(parser, closing)
6165static pm_range_node_t *
6166pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6167 pm_assert_value_expression(parser, left);
6168 pm_assert_value_expression(parser, right);
6169 pm_node_flags_t flags = 0;
6171 // Indicate that this node is an exclusive range if the operator is `...`.
6172 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6173 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6176 // Indicate that this node is a static literal (i.e., can be compiled with
6177 // a putobject in CRuby) if the left and right are implicit nil, explicit
6178 // nil, or integers.
6180 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6181 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6183 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6186 uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
6187 uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
6189 return pm_range_node_new(
6193 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6196 TOK2LOC(parser, operator)
6203static pm_redo_node_t *
6204pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6205 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6207 return pm_redo_node_new(
6211 PM_LOCATION_INIT_TOKEN(parser, token)
6219static pm_regular_expression_node_t *
6220pm_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) {
6221 return pm_regular_expression_node_new(
6224 pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6225 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6226 TOK2LOC(parser, opening),
6227 TOK2LOC(parser, content),
6228 TOK2LOC(parser, closing),
6236static PRISM_INLINE pm_regular_expression_node_t *
6237pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6238 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6244static pm_required_parameter_node_t *
6245pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6246 return pm_required_parameter_node_new(
6250 PM_LOCATION_INIT_TOKEN(parser, token),
6251 pm_parser_constant_id_token(parser, token)
6258static pm_rescue_modifier_node_t *
6259pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6260 return pm_rescue_modifier_node_new(
6264 PM_LOCATION_INIT_NODES(expression, rescue_expression),
6266 TOK2LOC(parser, keyword),
6274static pm_rescue_node_t *
6275pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6276 return pm_rescue_node_new(
6280 PM_LOCATION_INIT_TOKEN(parser, keyword),
6281 TOK2LOC(parser, keyword),
6282 ((pm_node_list_t) { 0 }),
6283 ((pm_location_t) { 0 }),
6285 ((pm_location_t) { 0 }),
6291static PRISM_INLINE void
6292pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
6293 node->operator_loc = TOK2LOC(parser, operator);
6300pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6301 node->reference = reference;
6302 PM_NODE_LENGTH_SET_NODE(node, reference);
6309pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6310 node->statements = statements;
6311 if (pm_statements_node_body_length(statements) > 0) {
6312 PM_NODE_LENGTH_SET_NODE(node, statements);
6320pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6321 node->subsequent = subsequent;
6322 PM_NODE_LENGTH_SET_NODE(node, subsequent);
6329pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
6330 pm_node_list_append(arena, &node->exceptions, exception);
6331 PM_NODE_LENGTH_SET_NODE(node, exception);
6337static pm_rest_parameter_node_t *
6338pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6339 return pm_rest_parameter_node_new(
6343 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
6344 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
6345 NTOK2LOC(parser, name),
6346 TOK2LOC(parser, operator)
6353static pm_retry_node_t *
6354pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6355 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6357 return pm_retry_node_new(
6361 PM_LOCATION_INIT_TOKEN(parser, token)
6368static pm_return_node_t *
6369pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6370 return pm_return_node_new(
6374 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
6375 TOK2LOC(parser, keyword),
6383static pm_self_node_t *
6384pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6385 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6387 return pm_self_node_new(
6391 PM_LOCATION_INIT_TOKEN(parser, token)
6398static pm_shareable_constant_node_t *
6399pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6400 return pm_shareable_constant_node_new(
6403 (pm_node_flags_t) value,
6404 PM_LOCATION_INIT_NODE(write),
6412static pm_singleton_class_node_t *
6413pm_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) {
6414 return pm_singleton_class_node_new(
6418 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
6420 TOK2LOC(parser, class_keyword),
6421 TOK2LOC(parser, operator),
6424 TOK2LOC(parser, end_keyword)
6431static pm_source_encoding_node_t *
6432pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6433 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6435 return pm_source_encoding_node_new(
6438 PM_NODE_FLAG_STATIC_LITERAL,
6439 PM_LOCATION_INIT_TOKEN(parser, token)
6446static pm_source_file_node_t*
6447pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6448 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6450 pm_node_flags_t flags = 0;
6452 switch (parser->frozen_string_literal) {
6453 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6454 flags |= PM_STRING_FLAGS_MUTABLE;
6456 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6457 flags |= PM_STRING_FLAGS_FROZEN;
6458 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
6459 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6464 return pm_source_file_node_new(
6468 PM_LOCATION_INIT_TOKEN(parser, file_keyword),
6476static pm_source_line_node_t *
6477pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6478 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6480 return pm_source_line_node_new(
6483 PM_NODE_FLAG_STATIC_LITERAL,
6484 PM_LOCATION_INIT_TOKEN(parser, token)
6491static pm_splat_node_t *
6492pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6493 return pm_splat_node_new(
6497 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
6498 TOK2LOC(parser, operator),
6506static pm_statements_node_t *
6507pm_statements_node_create(pm_parser_t *parser) {
6508 return pm_statements_node_new(
6512 PM_LOCATION_INIT_UNSET,
6513 ((pm_node_list_t) { 0 })
6521pm_statements_node_body_length(pm_statements_node_t *node) {
6522 return node && node->body.size;
6529static PRISM_INLINE void
6530pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6531 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6532 PM_NODE_START_SET_NODE(node, statement);
6535 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6536 PM_NODE_LENGTH_SET_NODE(node, statement);
6544pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6545 pm_statements_node_body_update(node, statement);
6547 if (node->body.size > 0) {
6548 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6550 switch (PM_NODE_TYPE(previous)) {
6555 case PM_RETURN_NODE:
6556 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6563 pm_node_list_append(parser->arena, &node->body, statement);
6564 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6571pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
6572 pm_statements_node_body_update(node, statement);
6573 pm_node_list_prepend(arena, &node->body, statement);
6574 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6580static PRISM_INLINE pm_string_node_t *
6581pm_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) {
6582 pm_node_flags_t flags = 0;
6584 switch (parser->frozen_string_literal) {
6585 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6586 flags = PM_STRING_FLAGS_MUTABLE;
6588 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6589 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6593 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6594 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6596 return pm_string_node_new(
6600 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6601 NTOK2LOC(parser, opening),
6602 TOK2LOC(parser, content),
6603 NTOK2LOC(parser, closing),
6611static pm_string_node_t *
6612pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6613 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6620static pm_string_node_t *
6621pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6622 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6623 parser->current_string = PM_STRING_EMPTY;
6630static pm_super_node_t *
6631pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6632 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6634 const pm_location_t *end = pm_arguments_end(arguments);
6635 assert(end != NULL && "unreachable");
6637 return pm_super_node_new(
6641 ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
6642 TOK2LOC(parser, keyword),
6643 arguments->opening_loc,
6644 arguments->arguments,
6645 arguments->closing_loc,
6655pm_ascii_only_p(const pm_string_t *contents) {
6656 const size_t length = pm_string_length(contents);
6657 const uint8_t *source = pm_string_source(contents);
6659 for (size_t index = 0; index < length; index++) {
6660 if (source[index] & 0x80) return false;
6670parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6671 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6672 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6675 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6688parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6689 const pm_encoding_t *encoding = parser->encoding;
6691 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6692 size_t width = encoding->char_width(cursor, end - cursor);
6695 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6712static PRISM_INLINE pm_node_flags_t
6713parse_symbol_encoding(pm_parser_t *parser, const pm_encoding_t *explicit_encoding, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6714 if (explicit_encoding != NULL) {
6715 // A Symbol may optionally have its encoding explicitly set. This will
6716 // happen if an escape sequence results in a non-ASCII code point.
6717 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6718 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6719 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6720 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6721 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6722 } else if (validate) {
6723 parse_symbol_encoding_validate_other(parser, location, contents);
6725 } else if (pm_ascii_only_p(contents)) {
6726 // Ruby stipulates that all source files must use an ASCII-compatible
6727 // encoding. Thus, all symbols appearing in source are eligible for
6728 // "downgrading" to US-ASCII.
6729 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6730 } else if (validate) {
6731 parse_symbol_encoding_validate_other(parser, location, contents);
6741static pm_symbol_node_t *
6742pm_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) {
6743 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6744 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6746 return pm_symbol_node_new(
6749 PM_NODE_FLAG_STATIC_LITERAL | flags,
6750 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6751 NTOK2LOC(parser, opening),
6752 NTOK2LOC(parser, value),
6753 NTOK2LOC(parser, closing),
6761static PRISM_INLINE pm_symbol_node_t *
6762pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6763 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6769static pm_symbol_node_t *
6770pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6771 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));
6772 parser->current_string = PM_STRING_EMPTY;
6779static pm_symbol_node_t *
6780pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6781 assert(token->type == PM_TOKEN_LABEL);
6783 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6784 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6785 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6787 assert((label.end - label.start) >= 0);
6788 pm_string_shared_init(&node->unescaped, label.start, label.end);
6789 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, parser->explicit_encoding, &label, &node->unescaped, false));
6797static pm_symbol_node_t *
6798pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6799 pm_symbol_node_t *node = pm_symbol_node_new(
6802 PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
6803 PM_LOCATION_INIT_UNSET,
6804 ((pm_location_t) { 0 }),
6805 ((pm_location_t) { 0 }),
6806 ((pm_location_t) { 0 }),
6807 ((pm_string_t) { 0 })
6810 pm_string_constant_init(&node->unescaped, content, strlen(content));
6818pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6819 const pm_location_t *location = NULL;
6821 switch (PM_NODE_TYPE(node)) {
6822 case PM_SYMBOL_NODE: {
6823 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6824 if (cast->closing_loc.length > 0) {
6825 location = &cast->closing_loc;
6829 case PM_INTERPOLATED_SYMBOL_NODE: {
6830 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6831 if (cast->closing_loc.length > 0) {
6832 location = &cast->closing_loc;
6840 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6846static pm_symbol_node_t *
6847pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6848 pm_symbol_node_t *new_node = pm_symbol_node_new(
6851 PM_NODE_FLAG_STATIC_LITERAL,
6852 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6853 TOK2LOC(parser, opening),
6855 TOK2LOC(parser, closing),
6859 pm_token_t content = {
6860 .type = PM_TOKEN_IDENTIFIER,
6861 .start = parser->start + node->content_loc.start,
6862 .end = parser->start + node->content_loc.start + node->content_loc.length
6865 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, parser->explicit_encoding, &content, &node->unescaped, true));
6867 /* The old node is arena-allocated so no explicit free is needed. */
6874static pm_string_node_t *
6875pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6876 pm_node_flags_t flags = 0;
6878 switch (parser->frozen_string_literal) {
6879 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6880 flags = PM_STRING_FLAGS_MUTABLE;
6882 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6883 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6887 pm_string_node_t *new_node = pm_string_node_new(
6891 PM_LOCATION_INIT_NODE(node),
6898 /* The old node is arena-allocated so no explicit free is needed. */
6905static pm_true_node_t *
6906pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6907 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6909 return pm_true_node_new(
6912 PM_NODE_FLAG_STATIC_LITERAL,
6913 PM_LOCATION_INIT_TOKEN(parser, token)
6920static pm_true_node_t *
6921pm_true_node_synthesized_create(pm_parser_t *parser) {
6922 return pm_true_node_new(
6925 PM_NODE_FLAG_STATIC_LITERAL,
6926 PM_LOCATION_INIT_UNSET
6933static pm_undef_node_t *
6934pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6935 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6937 return pm_undef_node_new(
6941 PM_LOCATION_INIT_TOKEN(parser, token),
6942 ((pm_node_list_t) { 0 }),
6943 TOK2LOC(parser, token)
6951pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6952 PM_NODE_LENGTH_SET_NODE(node, name);
6953 pm_node_list_append(arena, &node->names, name);
6959static pm_unless_node_t *
6960pm_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) {
6961 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6962 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6964 return pm_unless_node_new(
6967 PM_NODE_FLAG_NEWLINE,
6968 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
6969 TOK2LOC(parser, keyword),
6971 NTOK2LOC(parser, then_keyword),
6974 ((pm_location_t) { 0 })
6981static pm_unless_node_t *
6982pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6983 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6985 pm_statements_node_t *statements = pm_statements_node_create(parser);
6986 pm_statements_node_body_append(parser, statements, statement, true);
6988 return pm_unless_node_new(
6991 PM_NODE_FLAG_NEWLINE,
6992 PM_LOCATION_INIT_NODES(statement, predicate),
6993 TOK2LOC(parser, unless_keyword),
6995 ((pm_location_t) { 0 }),
6998 ((pm_location_t) { 0 })
7002static PRISM_INLINE void
7003pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
7004 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
7005 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
7014pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
7015 assert(parser->current_block_exits != NULL);
7017 // All of the block exits that we want to remove should be within the
7018 // statements, and since we are modifying the statements, we shouldn't have
7019 // to check the end location.
7020 uint32_t start = statements->base.location.start;
7022 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
7023 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7024 if (block_exit->location.start < start) break;
7026 // Implicitly remove from the list by lowering the size.
7027 parser->current_block_exits->size--;
7034static pm_until_node_t *
7035pm_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) {
7036 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7038 return pm_until_node_new(
7042 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7043 TOK2LOC(parser, keyword),
7044 NTOK2LOC(parser, do_keyword),
7045 TOK2LOC(parser, closing),
7054static pm_until_node_t *
7055pm_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) {
7056 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7057 pm_loop_modifier_block_exits(parser, statements);
7059 return pm_until_node_new(
7063 PM_LOCATION_INIT_NODES(statements, predicate),
7064 TOK2LOC(parser, keyword),
7065 ((pm_location_t) { 0 }),
7066 ((pm_location_t) { 0 }),
7075static pm_when_node_t *
7076pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7077 return pm_when_node_new(
7081 PM_LOCATION_INIT_TOKEN(parser, keyword),
7082 TOK2LOC(parser, keyword),
7083 ((pm_node_list_t) { 0 }),
7084 ((pm_location_t) { 0 }),
7093pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
7094 PM_NODE_LENGTH_SET_NODE(node, condition);
7095 pm_node_list_append(arena, &node->conditions, condition);
7101static PRISM_INLINE void
7102pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
7103 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
7104 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
7111pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7112 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
7113 PM_NODE_LENGTH_SET_NODE(node, statements);
7116 node->statements = statements;
7122static pm_while_node_t *
7123pm_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) {
7124 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7126 return pm_while_node_new(
7130 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7131 TOK2LOC(parser, keyword),
7132 NTOK2LOC(parser, do_keyword),
7133 TOK2LOC(parser, closing),
7142static pm_while_node_t *
7143pm_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) {
7144 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7145 pm_loop_modifier_block_exits(parser, statements);
7147 return pm_while_node_new(
7151 PM_LOCATION_INIT_NODES(statements, predicate),
7152 TOK2LOC(parser, keyword),
7153 ((pm_location_t) { 0 }),
7154 ((pm_location_t) { 0 }),
7163static pm_while_node_t *
7164pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7165 return pm_while_node_new(
7169 PM_LOCATION_INIT_UNSET,
7170 ((pm_location_t) { 0 }),
7171 ((pm_location_t) { 0 }),
7172 ((pm_location_t) { 0 }),
7182static pm_x_string_node_t *
7183pm_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) {
7184 return pm_x_string_node_new(
7187 PM_STRING_FLAGS_FROZEN,
7188 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
7189 TOK2LOC(parser, opening),
7190 TOK2LOC(parser, content),
7191 TOK2LOC(parser, closing),
7199static PRISM_INLINE pm_x_string_node_t *
7200pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7201 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7207static pm_yield_node_t *
7208pm_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) {
7209 uint32_t start = PM_TOKEN_START(parser, keyword);
7212 if (rparen_loc->length > 0) {
7213 end = PM_LOCATION_END(rparen_loc);
7214 } else if (arguments != NULL) {
7215 end = PM_NODE_END(arguments);
7216 } else if (lparen_loc->length > 0) {
7217 end = PM_LOCATION_END(lparen_loc);
7219 end = PM_TOKEN_END(parser, keyword);
7222 return pm_yield_node_new(
7226 ((pm_location_t) { .start = start, .length = U32(end - start) }),
7227 TOK2LOC(parser, keyword),
7239pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7240 pm_scope_t *scope = parser->current_scope;
7243 while (scope != NULL) {
7244 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7245 if (scope->closed) break;
7247 scope = scope->previous;
7259static PRISM_INLINE int
7260pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7261 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7267static PRISM_INLINE void
7268pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7269 pm_locals_write(&parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
7275static pm_constant_id_t
7276pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7277 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
7278 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7285static PRISM_INLINE pm_constant_id_t
7286pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
7287 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
7293static PRISM_INLINE pm_constant_id_t
7294pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7295 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
7301static pm_constant_id_t
7302pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7303 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7304 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7311static pm_constant_id_t
7312pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7313 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7314 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7326pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7327 // We want to check whether the parameter name is a numbered parameter or
7329 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7331 // Otherwise we'll fetch the constant id for the parameter name and check
7332 // whether it's already in the current scope.
7333 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7335 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7336 // Add an error if the parameter doesn't start with _ and has been seen before
7337 if ((name->start < name->end) && (*name->start != '_')) {
7338 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7349pm_parser_scope_pop(pm_parser_t *parser) {
7350 pm_scope_t *scope = parser->current_scope;
7351 parser->current_scope = scope->previous;
7352 pm_locals_free(&scope->locals);
7353 xfree_sized(scope, sizeof(pm_scope_t));
7356/******************************************************************************/
7358/******************************************************************************/
7363static PRISM_INLINE void
7364pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7365 *stack = (*stack << 1) | (value & 1);
7371static PRISM_INLINE void
7372pm_state_stack_pop(pm_state_stack_t *stack) {
7379static PRISM_INLINE bool
7380pm_state_stack_p(const pm_state_stack_t *stack) {
7384static PRISM_INLINE void
7385pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7386 // Use the negation of the value to prevent stack overflow.
7387 pm_state_stack_push(&parser->accepts_block_stack, !value);
7390static PRISM_INLINE void
7391pm_accepts_block_stack_pop(pm_parser_t *parser) {
7392 pm_state_stack_pop(&parser->accepts_block_stack);
7395static PRISM_INLINE bool
7396pm_accepts_block_stack_p(pm_parser_t *parser) {
7397 return !pm_state_stack_p(&parser->accepts_block_stack);
7400static PRISM_INLINE void
7401pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7402 pm_state_stack_push(&parser->do_loop_stack, value);
7405static PRISM_INLINE void
7406pm_do_loop_stack_pop(pm_parser_t *parser) {
7407 pm_state_stack_pop(&parser->do_loop_stack);
7410static PRISM_INLINE bool
7411pm_do_loop_stack_p(pm_parser_t *parser) {
7412 return pm_state_stack_p(&parser->do_loop_stack);
7439static PRISM_INLINE void
7440pm_enclosure_frame_push(pm_parser_t *parser) {
7441 pm_do_loop_stack_push(parser, false);
7442 pm_accepts_block_stack_push(parser, true);
7445static PRISM_INLINE void
7446pm_enclosure_frame_pop(pm_parser_t *parser) {
7447 pm_do_loop_stack_pop(parser);
7448 pm_accepts_block_stack_pop(parser);
7451/******************************************************************************/
7452/* Lexer check helpers */
7453/******************************************************************************/
7459static PRISM_INLINE uint8_t
7460peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7461 if (cursor < parser->end) {
7473static PRISM_INLINE uint8_t
7474peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7475 return peek_at(parser, parser->current.end + offset);
7482static PRISM_INLINE uint8_t
7483peek(const pm_parser_t *parser) {
7484 return peek_at(parser, parser->current.end);
7491static PRISM_INLINE bool
7492match(pm_parser_t *parser, uint8_t value) {
7493 if (peek(parser) == value) {
7494 parser->current.end++;
7504static PRISM_INLINE size_t
7505match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7506 if (peek_at(parser, cursor) == '\n') {
7509 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7520static PRISM_INLINE size_t
7521match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7522 return match_eol_at(parser, parser->current.end + offset);
7530static PRISM_INLINE size_t
7531match_eol(pm_parser_t *parser) {
7532 return match_eol_at(parser, parser->current.end);
7538static PRISM_INLINE const uint8_t *
7539next_newline(const uint8_t *cursor, ptrdiff_t length) {
7540 assert(length >= 0);
7542 // Note that it's okay for us to use memchr here to look for \n because none
7543 // of the encodings that we support have \n as a component of a multi-byte
7545 return memchr(cursor, '\n', (size_t) length);
7551static PRISM_INLINE bool
7552ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7553 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));
7561parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7562 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7564 if (encoding != NULL) {
7565 if (parser->encoding != encoding) {
7566 parser->encoding = encoding;
7567 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7570 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7582parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7583 const uint8_t *cursor = parser->current.start + 1;
7584 const uint8_t *end = parser->current.end;
7586 bool separator = false;
7588 if (end - cursor <= 6) return;
7589 switch (cursor[6]) {
7590 case 'C': case 'c': cursor += 6; continue;
7591 case 'O': case 'o': cursor += 5; continue;
7592 case 'D': case 'd': cursor += 4; continue;
7593 case 'I': case 'i': cursor += 3; continue;
7594 case 'N': case 'n': cursor += 2; continue;
7595 case 'G': case 'g': cursor += 1; continue;
7602 if (pm_char_is_whitespace(*cursor)) break;
7605 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7611 if (++cursor >= end) return;
7612 } while (pm_char_is_whitespace(*cursor));
7614 if (separator) break;
7615 if (*cursor != '=' && *cursor != ':') return;
7621 const uint8_t *value_start = cursor;
7622 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7624 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7625 // If we were unable to parse the encoding value, then we've got an
7626 // issue because we didn't understand the encoding that the user was
7627 // trying to use. In this case we'll keep using the default encoding but
7628 // add an error to the parser to indicate an unsuccessful parse.
7629 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7634 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7635 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7636 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7637} pm_magic_comment_boolean_value_t;
7643static pm_magic_comment_boolean_value_t
7644parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7645 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7646 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7647 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7648 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7650 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7654static PRISM_INLINE bool
7655pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7656 return b == '\'' || b == '"' || b == ':' || b == ';';
7665parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7669 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1,
'*', (
size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7670 if (cursor[-1] ==
'-' && cursor + 1 < end && cursor[1] ==
'-') {
7688parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7691 const uint8_t *start = parser->current.start + 1;
7692 const uint8_t *end = parser->current.end;
7693 if (end - start <= 7)
return false;
7695 const uint8_t *cursor;
7696 bool indicator =
false;
7698 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7701 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7713 if (pm_memchr(start,
':', (
size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
7719 start += pm_strspn_whitespace(start, end - start);
7723 while (cursor < end) {
7725 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7728 const uint8_t *key_start = cursor;
7729 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7731 const uint8_t *key_end = cursor;
7732 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7733 if (cursor == end)
break;
7735 if (*cursor ==
':') {
7738 if (!indicator)
return false;
7742 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7743 if (cursor == end)
break;
7745 const uint8_t *value_start;
7746 const uint8_t *value_end;
7748 if (*cursor ==
'"') {
7749 value_start = ++cursor;
7750 for (; cursor < end && *cursor !=
'"'; cursor++) {
7751 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7754 if (cursor < end && *cursor ==
'"') cursor++;
7756 value_start = cursor;
7757 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7762 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7764 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7765 if (cursor != end)
return false;
7771 const size_t key_length = (size_t) (key_end - key_start);
7772 const uint8_t *dash = pm_memchr(key_start,
'-', key_length, parser->encoding_changed, parser->encoding);
7775 pm_string_shared_init(&key, key_start, key_end);
7777 uint8_t *buffer =
xmalloc(key_length);
7778 if (buffer == NULL)
break;
7780 memcpy(buffer, key_start, key_length);
7781 buffer[dash - key_start] =
'_';
7783 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7784 buffer[dash - key_start] =
'_';
7787 pm_string_owned_init(&key, buffer, key_length);
7792 const uint8_t *key_source = pm_string_source(&key);
7793 uint32_t value_length = (uint32_t) (value_end - value_start);
7797 if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7799 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7800 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7802 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7806 if (key_length == 11) {
7807 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7808 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7809 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7810 PM_PARSER_WARN_TOKEN_FORMAT(
7813 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7815 (
const char *) key_source,
7817 (
const char *) value_start
7820 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7821 parser->warn_mismatched_indentation =
false;
7823 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7824 parser->warn_mismatched_indentation =
true;
7828 }
else if (key_length == 21) {
7829 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7832 if (semantic_token_seen) {
7833 pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7835 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7836 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7837 PM_PARSER_WARN_TOKEN_FORMAT(
7840 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7842 (
const char *) key_source,
7844 (
const char *) value_start
7847 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7850 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7856 }
else if (key_length == 24) {
7857 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7858 const uint8_t *cursor = parser->current.start;
7859 while ((cursor > parser->start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7861 if (!((cursor == parser->start) || (cursor[-1] ==
'\n'))) {
7862 pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7863 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7864 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7865 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7866 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7867 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7868 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7869 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7870 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7872 PM_PARSER_WARN_TOKEN_FORMAT(
7875 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7877 (
const char *) key_source,
7879 (
const char *) value_start
7887 pm_string_cleanup(&key);
7904static const uint32_t context_terminators[] = {
7905 [PM_CONTEXT_NONE] = 0,
7906 [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7907 [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7908 [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7909 [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7910 [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7911 [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7912 [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7913 [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7914 [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
7915 [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7916 [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7917 [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7918 [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7919 [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7920 [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7921 [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7922 [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7923 [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7924 [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7925 [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7926 [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
7927 [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
7928 [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7929 [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
7930 [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7931 [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
7932 [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
7933 [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
7934 [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7935 [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7936 [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7937 [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7938 [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7939 [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7940 [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
7941 [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
7942 [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7943 [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7944 [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7945 [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7946 [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
7947 [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7948 [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7949 [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7950 [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7951 [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
7952 [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7953 [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7954 [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7955 [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7956 [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
7957 [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7958 [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
7959 [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
7963context_terminator(pm_context_t context,
pm_token_t *token) {
7964 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7975 while (context_node != NULL) {
7976 if (context_terminator(context_node->context, token))
return context_node->context;
7977 context_node = context_node->prev;
7980 return PM_CONTEXT_NONE;
7983PM_STATIC_ASSERT(__LINE__, PM_CONTEXT_MAXIMUM <= 64,
"Expected every context to fit in the context mask.");
7986context_push(
pm_parser_t *parser, pm_context_t context) {
7988 if (context_node == NULL)
return false;
7994 .mask = (previous == NULL ? 0 : previous->mask) | ((uint64_t) 1 << context)
7997 parser->current_context = context_node;
8005 parser->current_context = prev;
8009context_p(
const pm_parser_t *parser, pm_context_t context) {
8010 return parser->current_context != NULL && (parser->current_context->mask & ((uint64_t) 1 << context)) != 0;
8017 while (context_node != NULL) {
8018 switch (context_node->context) {
8019 case PM_CONTEXT_DEF:
8020 case PM_CONTEXT_DEF_PARAMS:
8021 case PM_CONTEXT_DEF_ENSURE:
8022 case PM_CONTEXT_DEF_RESCUE:
8023 case PM_CONTEXT_DEF_ELSE:
8025 case PM_CONTEXT_CLASS:
8026 case PM_CONTEXT_CLASS_ENSURE:
8027 case PM_CONTEXT_CLASS_RESCUE:
8028 case PM_CONTEXT_CLASS_ELSE:
8029 case PM_CONTEXT_MODULE:
8030 case PM_CONTEXT_MODULE_ENSURE:
8031 case PM_CONTEXT_MODULE_RESCUE:
8032 case PM_CONTEXT_MODULE_ELSE:
8033 case PM_CONTEXT_SCLASS:
8034 case PM_CONTEXT_SCLASS_ENSURE:
8035 case PM_CONTEXT_SCLASS_RESCUE:
8036 case PM_CONTEXT_SCLASS_ELSE:
8039 context_node = context_node->prev;
8051context_human(pm_context_t context) {
8053 case PM_CONTEXT_NONE:
8054 case PM_CONTEXT_MAXIMUM:
8055 assert(
false &&
"unreachable");
8057 case PM_CONTEXT_BEGIN:
return "begin statement";
8058 case PM_CONTEXT_BLOCK_BRACES:
return "'{'..'}' block";
8059 case PM_CONTEXT_BLOCK_KEYWORDS:
return "'do'..'end' block";
8060 case PM_CONTEXT_BLOCK_PARAMETERS:
return "'|'..'|' block parameter";
8061 case PM_CONTEXT_CASE_WHEN:
return "'when' clause";
8062 case PM_CONTEXT_CASE_IN:
return "'in' clause";
8063 case PM_CONTEXT_CLASS:
return "class definition";
8064 case PM_CONTEXT_DEF:
return "method definition";
8065 case PM_CONTEXT_DEF_PARAMS:
return "method parameters";
8066 case PM_CONTEXT_DEFAULT_PARAMS:
return "parameter default value";
8067 case PM_CONTEXT_DEFINED:
return "'defined?' expression";
8068 case PM_CONTEXT_ELSE:
8069 case PM_CONTEXT_BEGIN_ELSE:
8070 case PM_CONTEXT_BLOCK_ELSE:
8071 case PM_CONTEXT_CLASS_ELSE:
8072 case PM_CONTEXT_DEF_ELSE:
8073 case PM_CONTEXT_LAMBDA_ELSE:
8074 case PM_CONTEXT_MODULE_ELSE:
8075 case PM_CONTEXT_SCLASS_ELSE:
return "'else' clause";
8076 case PM_CONTEXT_ELSIF:
return "'elsif' clause";
8077 case PM_CONTEXT_EMBEXPR:
return "embedded expression";
8078 case PM_CONTEXT_BEGIN_ENSURE:
8079 case PM_CONTEXT_BLOCK_ENSURE:
8080 case PM_CONTEXT_CLASS_ENSURE:
8081 case PM_CONTEXT_DEF_ENSURE:
8082 case PM_CONTEXT_LAMBDA_ENSURE:
8083 case PM_CONTEXT_MODULE_ENSURE:
8084 case PM_CONTEXT_SCLASS_ENSURE:
return "'ensure' clause";
8085 case PM_CONTEXT_FOR:
return "for loop";
8086 case PM_CONTEXT_FOR_INDEX:
return "for loop index";
8087 case PM_CONTEXT_IF:
return "if statement";
8088 case PM_CONTEXT_LAMBDA_BRACES:
return "'{'..'}' lambda block";
8089 case PM_CONTEXT_LAMBDA_DO_END:
return "'do'..'end' lambda block";
8090 case PM_CONTEXT_LOOP_PREDICATE:
return "loop predicate";
8091 case PM_CONTEXT_MAIN:
return "top level context";
8092 case PM_CONTEXT_MODULE:
return "module definition";
8093 case PM_CONTEXT_MULTI_TARGET:
return "multiple targets";
8094 case PM_CONTEXT_PARENS:
return "parentheses";
8095 case PM_CONTEXT_POSTEXE:
return "'END' block";
8096 case PM_CONTEXT_PREDICATE:
return "predicate";
8097 case PM_CONTEXT_PREEXE:
return "'BEGIN' block";
8098 case PM_CONTEXT_BEGIN_RESCUE:
8099 case PM_CONTEXT_BLOCK_RESCUE:
8100 case PM_CONTEXT_CLASS_RESCUE:
8101 case PM_CONTEXT_DEF_RESCUE:
8102 case PM_CONTEXT_LAMBDA_RESCUE:
8103 case PM_CONTEXT_MODULE_RESCUE:
8104 case PM_CONTEXT_RESCUE_MODIFIER:
8105 case PM_CONTEXT_SCLASS_RESCUE:
return "'rescue' clause";
8106 case PM_CONTEXT_SCLASS:
return "singleton class definition";
8107 case PM_CONTEXT_TERNARY:
return "ternary expression";
8108 case PM_CONTEXT_UNLESS:
return "unless statement";
8109 case PM_CONTEXT_UNTIL:
return "until statement";
8110 case PM_CONTEXT_WHILE:
return "while statement";
8113 assert(
false &&
"unreachable");
8122pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8123 if (invalid != NULL) {
8124 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8125 pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
8130pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8131 const uint8_t *invalid = NULL;
8132 size_t length = pm_strspn_binary_number(
string, parser->end -
string, &invalid);
8133 pm_strspn_number_validate(parser,
string, length, invalid);
8138pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8139 const uint8_t *invalid = NULL;
8140 size_t length = pm_strspn_octal_number(
string, parser->end -
string, &invalid);
8141 pm_strspn_number_validate(parser,
string, length, invalid);
8146pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8147 const uint8_t *invalid = NULL;
8148 size_t length = pm_strspn_decimal_number(
string, parser->end -
string, &invalid);
8149 pm_strspn_number_validate(parser,
string, length, invalid);
8154pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8155 const uint8_t *invalid = NULL;
8156 size_t length = pm_strspn_hexadecimal_number(
string, parser->end -
string, &invalid);
8157 pm_strspn_number_validate(parser,
string, length, invalid);
8161static pm_token_type_t
8162lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8163 pm_token_type_t
type = PM_TOKEN_INTEGER;
8167 if (peek(parser) ==
'.') {
8168 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8169 parser->current.end += 2;
8170 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8171 type = PM_TOKEN_FLOAT;
8181 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8182 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8183 parser->current.end += 2;
8185 if (pm_char_is_decimal_digit(peek(parser))) {
8186 parser->current.end++;
8187 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8189 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8191 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8192 parser->current.end++;
8193 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8199 type = PM_TOKEN_FLOAT;
8205static pm_token_type_t
8206lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8207 pm_token_type_t
type = PM_TOKEN_INTEGER;
8210 if (peek_offset(parser, -1) ==
'0') {
8211 switch (*parser->current.end) {
8215 parser->current.end++;
8216 if (pm_char_is_decimal_digit(peek(parser))) {
8217 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8220 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8228 parser->current.end++;
8229 if (pm_char_is_binary_digit(peek(parser))) {
8230 parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
8233 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8236 parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
8242 parser->current.end++;
8243 if (pm_char_is_octal_digit(peek(parser))) {
8244 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8247 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8250 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8263 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8264 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8270 parser->current.end++;
8271 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8272 parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
8275 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8278 parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8283 type = lex_optional_float_suffix(parser, seen_e);
8290 type = lex_optional_float_suffix(parser, seen_e);
8299 const uint8_t *cursor = parser->current.end;
8300 const uint8_t *end = parser->end;
8301 uint64_t value = (uint64_t) (cursor[-1] -
'0');
8303 bool has_underscore =
false;
8304 bool prev_underscore =
false;
8305 const uint8_t *invalid = NULL;
8307 while (cursor < end) {
8308 uint8_t c = *cursor;
8309 if (c >=
'0' && c <=
'9') {
8310 if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c -
'0');
8311 prev_underscore =
false;
8313 }
else if (c ==
'_') {
8314 has_underscore =
true;
8315 if (prev_underscore && invalid == NULL) invalid = cursor;
8316 prev_underscore =
true;
8323 if (has_underscore) {
8324 if (prev_underscore && invalid == NULL) invalid = cursor - 1;
8325 pm_strspn_number_validate(parser, parser->current.end, (
size_t) (cursor - parser->current.end), invalid);
8328 if (value <= UINT32_MAX) {
8329 parser->integer.value = (uint32_t) value;
8330 parser->integer.lexed =
true;
8333 parser->current.end = cursor;
8341 uint8_t next = peek(parser);
8342 if (next ==
'.' || next ==
'e' || next ==
'E') {
8343 type = lex_optional_float_suffix(parser, seen_e);
8347 if (
type != PM_TOKEN_INTEGER) {
8348 parser->integer.lexed =
false;
8357 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8358 const uint8_t *fraction_start = parser->current.end;
8359 const uint8_t *fraction_end = parser->current.end + 2;
8360 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
8361 pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
8367static pm_token_type_t
8369 pm_token_type_t
type = PM_TOKEN_INTEGER;
8370 parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8371 parser->integer.lexed =
false;
8373 if (parser->current.end < parser->end) {
8374 bool seen_e =
false;
8375 type = lex_numeric_prefix(parser, &seen_e);
8377 const uint8_t *end = parser->current.end;
8378 pm_token_type_t suffix_type =
type;
8380 if (
type == PM_TOKEN_INTEGER) {
8381 if (match(parser,
'r')) {
8382 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8384 if (match(parser,
'i')) {
8385 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8387 }
else if (match(parser,
'i')) {
8388 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8391 if (!seen_e && match(parser,
'r')) {
8392 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8394 if (match(parser,
'i')) {
8395 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8397 }
else if (match(parser,
'i')) {
8398 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8402 const uint8_t b = peek(parser);
8403 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8404 parser->current.end = end;
8413static pm_token_type_t
8415 if (parser->current.end >= parser->end) {
8416 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8417 return PM_TOKEN_GLOBAL_VARIABLE;
8422 bool allow_multiple =
true;
8424 switch (*parser->current.end) {
8441 parser->current.end++;
8442 return PM_TOKEN_GLOBAL_VARIABLE;
8448 parser->current.end++;
8449 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8452 parser->current.end++;
8455 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8457 parser->current.end += width;
8458 }
while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8461 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;
8462 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
8465 return PM_TOKEN_GLOBAL_VARIABLE;
8477 parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
8478 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8481 parser->current.end++;
8482 allow_multiple =
false;
8487 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8489 parser->current.end += width;
8490 }
while (allow_multiple && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8491 }
else if (pm_char_is_whitespace(peek(parser))) {
8494 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8498 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;
8499 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8500 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);
8503 return PM_TOKEN_GLOBAL_VARIABLE;
8521lex_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) {
8522 if (memcmp(current_start, value, vlen) == 0) {
8523 pm_lex_state_t last_state = parser->lex_state;
8525 if (parser->lex_state & PM_LEX_STATE_FNAME) {
8526 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8528 lex_state_set(parser, state);
8529 if (state == PM_LEX_STATE_BEG) {
8530 parser->command_start =
true;
8533 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8534 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8535 return modifier_type;
8542 return PM_TOKEN_EOF;
8545static pm_token_type_t
8546lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8549 const uint8_t *end = parser->end;
8550 const uint8_t *current_start = parser->current.start;
8551 const uint8_t *current_end = parser->current.end;
8552 bool encoding_changed = parser->encoding_changed;
8554 if (encoding_changed) {
8555 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8556 current_end += width;
8560 current_end += scan_identifier_ascii(current_end, end);
8563 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8564 current_end += width;
8567 parser->current.end = current_end;
8571 width = (size_t) (current_end - current_start);
8573 if (current_end < end) {
8574 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8580 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8581 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8585 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8586 (void) match(parser,
':');
8590 parser->explicit_encoding = NULL;
8591 return PM_TOKEN_LABEL;
8594 if (parser->lex_state != PM_LEX_STATE_DOT) {
8595 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8596 return PM_TOKEN_KEYWORD_DEFINED;
8600 return PM_TOKEN_METHOD_NAME;
8603 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,
'=')) {
8606 return PM_TOKEN_IDENTIFIER;
8610 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8611 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8615 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8616 (void) match(parser,
':');
8620 parser->explicit_encoding = NULL;
8621 return PM_TOKEN_LABEL;
8625 if (parser->lex_state != PM_LEX_STATE_DOT) {
8626 pm_token_type_t
type;
8630 pm_lex_state_t previous_lex_state = parser->lex_state;
8634 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8642 if (previous_lex_state & PM_LEX_STATE_FNAME) {
8643 return PM_TOKEN_KEYWORD_DO;
8645 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
8659 parser->lambda_enclosure_nesting = -1;
8660 return PM_TOKEN_KEYWORD_DO_LAMBDA;
8662 if (pm_do_loop_stack_p(parser)) {
8663 return PM_TOKEN_KEYWORD_DO_LOOP;
8665 if (!pm_accepts_block_stack_p(parser)) {
8666 return PM_TOKEN_KEYWORD_DO_BLOCK;
8668 return PM_TOKEN_KEYWORD_DO;
8671 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;
8672 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;
8673 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;
8676 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;
8677 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;
8678 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;
8679 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;
8680 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;
8681 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;
8682 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;
8685 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;
8686 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;
8687 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;
8688 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;
8689 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;
8690 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;
8691 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;
8692 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;
8695 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;
8696 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;
8697 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;
8698 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;
8699 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;
8700 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;
8701 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;
8702 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;
8703 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;
8704 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;
8705 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;
8706 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;
8707 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;
8710 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;
8711 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;
8712 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;
8713 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;
8714 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;
8717 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;
8718 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;
8721 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;
8726 if (encoding_changed) {
8727 return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8733 if (*current_start < 0x80) {
8734 return (*current_start >=
'A' && *current_start <=
'Z') ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8736 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8745 return (parser->current.start == parser->start) || (parser->current.start[-1] ==
'\n');
8762static pm_token_type_t
8763lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8766 if (pound + 1 >= parser->end) {
8767 parser->current.end = pound + 1;
8768 return PM_TOKEN_STRING_CONTENT;
8777 if (pound + 2 >= parser->end) {
8778 parser->current.end = pound + 1;
8779 return PM_TOKEN_STRING_CONTENT;
8784 const uint8_t *variable = pound + 2;
8785 if (*variable ==
'@' && pound + 3 < parser->end) variable++;
8787 if (char_is_identifier_start(parser, variable, parser->end - variable)) {
8791 if (pound > parser->current.start) {
8792 parser->current.end = pound;
8793 return PM_TOKEN_STRING_CONTENT;
8798 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8799 parser->current.end = pound + 1;
8800 return PM_TOKEN_EMBVAR;
8806 parser->current.end = pound + 1;
8812 if (pound + 2 >= parser->end) {
8813 parser->current.end = pound + 1;
8814 return PM_TOKEN_STRING_CONTENT;
8820 const uint8_t *check = pound + 2;
8822 if (pound[2] ==
'-') {
8823 if (pound + 3 >= parser->end) {
8824 parser->current.end = pound + 2;
8825 return PM_TOKEN_STRING_CONTENT;
8836 char_is_identifier_start(parser, check, parser->end - check) ||
8837 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8842 if (pound > parser->current.start) {
8843 parser->current.end = pound;
8844 return PM_TOKEN_STRING_CONTENT;
8849 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8850 parser->current.end = pound + 1;
8851 return PM_TOKEN_EMBVAR;
8856 parser->current.end = pound + 1;
8862 if (pound > parser->current.start) {
8863 parser->current.end = pound;
8864 return PM_TOKEN_STRING_CONTENT;
8867 parser->enclosure_nesting++;
8871 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8872 parser->current.end = pound + 2;
8873 parser->command_start =
true;
8874 pm_enclosure_frame_push(parser);
8875 return PM_TOKEN_EMBEXPR_BEGIN;
8880 parser->current.end = pound + 1;
8885static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8886static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8887static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8888static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8889static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8894static const bool ascii_printable_chars[] = {
8895 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8896 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8897 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8898 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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, 0, 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, 1, 1, 1, 0
8906char_is_ascii_printable(
const uint8_t b) {
8907 return (b < 0x80) && ascii_printable_chars[b];
8915escape_hexadecimal_digit(
const uint8_t value) {
8916 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8925escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const pm_location_t *error_location,
const uint8_t flags) {
8927 for (
size_t index = 0; index < length; index++) {
8928 if (index != 0) value <<= 4;
8929 value |= escape_hexadecimal_digit(
string[index]);
8934 if (value >= 0xD800 && value <= 0xDFFF) {
8935 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8938 }
else if (error_location != NULL) {
8939 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
8941 pm_parser_err(parser, U32(
string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
8953escape_byte(uint8_t value,
const uint8_t flags) {
8954 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8955 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8963escape_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) {
8967 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8968 if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
8969 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8973 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
8977 parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
8980 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8981 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8985 pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
8988 pm_buffer_append_byte(buffer, 0xEF);
8989 pm_buffer_append_byte(buffer, 0xBF);
8990 pm_buffer_append_byte(buffer, 0xBD);
9001 if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
9002 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9006 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
9010 parser->explicit_encoding = parser->encoding;
9013 pm_buffer_append_byte(buffer,
byte);
9033 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9034 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9037 escape_write_byte_encoded(parser, buffer, flags,
byte);
9046 if (parser->encoding_changed) {
9047 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9049 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9053 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);
9054 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
9055 }
else if (width > 1) {
9057 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9058 pm_buffer_append_bytes(b, parser->current.end, width);
9059 parser->current.end += width;
9063 parser->current.end++;
9064 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9074escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9075#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9077 PM_PARSER_WARN_TOKEN_FORMAT(
9080 PM_WARN_INVALID_CHARACTER,
9094 uint8_t peeked = peek(parser);
9097 parser->current.end++;
9098 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9102 parser->current.end++;
9103 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9107 parser->current.end++;
9108 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9112 parser->current.end++;
9113 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9117 parser->current.end++;
9118 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9122 parser->current.end++;
9123 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9127 parser->current.end++;
9128 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9132 parser->current.end++;
9133 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9137 parser->current.end++;
9138 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9142 parser->current.end++;
9143 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9147 parser->current.end++;
9148 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9151 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9152 uint8_t value = (uint8_t) (*parser->current.end -
'0');
9153 parser->current.end++;
9155 if (pm_char_is_octal_digit(peek(parser))) {
9156 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9157 parser->current.end++;
9159 if (pm_char_is_octal_digit(peek(parser))) {
9160 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9161 parser->current.end++;
9165 value = escape_byte(value, flags);
9166 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9170 const uint8_t *start = parser->current.end - 1;
9172 parser->current.end++;
9173 uint8_t
byte = peek(parser);
9175 if (pm_char_is_hexadecimal_digit(
byte)) {
9176 uint8_t value = escape_hexadecimal_digit(
byte);
9177 parser->current.end++;
9179 byte = peek(parser);
9180 if (pm_char_is_hexadecimal_digit(
byte)) {
9181 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9182 parser->current.end++;
9185 value = escape_byte(value, flags);
9186 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9187 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9188 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9190 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9194 escape_write_byte_encoded(parser, buffer, flags, value);
9196 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9202 const uint8_t *start = parser->current.end - 1;
9203 parser->current.end++;
9205 if (parser->current.end == parser->end) {
9206 const uint8_t *start = parser->current.end - 2;
9207 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9208 }
else if (peek(parser) ==
'{') {
9209 const uint8_t *unicode_codepoints_start = parser->current.end - 2;
9210 parser->current.end++;
9214 if ((whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end)) > 0) {
9215 parser->current.end += whitespace;
9216 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9221 parser->current.end += 2;
9227 const uint8_t *extra_codepoints_start = NULL;
9228 int codepoints_count = 0;
9230 while ((parser->current.end < parser->end) && (*parser->current.end !=
'}')) {
9231 const uint8_t *unicode_start = parser->current.end;
9232 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
9234 if (hexadecimal_length > 6) {
9236 pm_parser_err(parser, U32(unicode_start - parser->start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9237 }
else if (hexadecimal_length == 0) {
9240 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9245 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9247 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
9248 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9254 parser->current.end += hexadecimal_length;
9256 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9257 extra_codepoints_start = unicode_start;
9260 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
9261 escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
9263 parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
9268 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9269 pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9272 if (parser->current.end == parser->end) {
9273 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);
9274 }
else if (peek(parser) ==
'}') {
9275 parser->current.end++;
9277 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9282 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9284 pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9288 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9289 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->current.end - unicode_codepoints_start));
9292 size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
9295 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9296 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9298 const uint8_t *start = parser->current.end - 2;
9299 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9301 }
else if (length == 4) {
9302 uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
9304 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9305 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end + 4 - start));
9308 escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
9309 parser->current.end += 4;
9311 parser->current.end += length;
9313 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9317 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9319 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9327 parser->current.end++;
9328 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9329 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9332 if (parser->current.end == parser->end) {
9333 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9337 uint8_t peeked = peek(parser);
9340 parser->current.end++;
9341 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9345 parser->current.end++;
9347 if (match(parser,
'u') || match(parser,
'U')) {
9348 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9352 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9355 parser->current.end++;
9356 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9357 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9360 parser->current.end++;
9361 escape_read_warn(parser, flags, 0,
"\\t");
9362 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9365 if (!char_is_ascii_printable(peeked)) {
9366 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9370 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);
9371 parser->current.end++;
9372 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9378 parser->current.end++;
9379 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9380 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9383 if (peek(parser) !=
'-') {
9384 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9385 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9389 parser->current.end++;
9390 if (parser->current.end == parser->end) {
9391 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9395 uint8_t peeked = peek(parser);
9398 parser->current.end++;
9399 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9403 parser->current.end++;
9405 if (match(parser,
'u') || match(parser,
'U')) {
9406 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9410 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9413 parser->current.end++;
9414 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9415 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9418 parser->current.end++;
9419 escape_read_warn(parser, flags, 0,
"\\t");
9420 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9423 if (!char_is_ascii_printable(peeked)) {
9424 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9425 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9429 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);
9430 parser->current.end++;
9431 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9437 parser->current.end++;
9438 if (flags & PM_ESCAPE_FLAG_META) {
9439 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9442 if (peek(parser) !=
'-') {
9443 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9444 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9448 parser->current.end++;
9449 if (parser->current.end == parser->end) {
9450 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9454 uint8_t peeked = peek(parser);
9457 parser->current.end++;
9459 if (match(parser,
'u') || match(parser,
'U')) {
9460 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9464 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9467 parser->current.end++;
9468 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9469 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9472 parser->current.end++;
9473 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9474 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9477 if (!char_is_ascii_printable(peeked)) {
9478 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9479 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9483 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);
9484 parser->current.end++;
9485 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9490 if (peek_offset(parser, 1) ==
'\n') {
9491 if (parser->heredoc_end == NULL) pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
9492 parser->current.end += 2;
9493 escape_write_byte_encoded(parser, buffer, flags, escape_byte(
'\n', flags));
9499 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9500 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9501 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9504 if (parser->current.end < parser->end) {
9505 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9507 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9539static pm_token_type_t
9541 if (lex_state_end_p(parser)) {
9542 lex_state_set(parser, PM_LEX_STATE_BEG);
9543 return PM_TOKEN_QUESTION_MARK;
9551 parser->explicit_encoding = NULL;
9553 if (parser->current.end >= parser->end) {
9554 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9555 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9556 return PM_TOKEN_CHARACTER_LITERAL;
9559 if (pm_char_is_whitespace(*parser->current.end)) {
9560 lex_state_set(parser, PM_LEX_STATE_BEG);
9561 return PM_TOKEN_QUESTION_MARK;
9564 lex_state_set(parser, PM_LEX_STATE_BEG);
9566 if (match(parser,
'\\')) {
9567 lex_state_set(parser, PM_LEX_STATE_END);
9570 pm_buffer_init(&buffer, 3);
9572 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9575 void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length,
PRISM_ALIGNOF(uint8_t));
9576 pm_string_constant_init(&parser->current_string, (
const char *) arena_data, buffer.length);
9577 pm_buffer_cleanup(&buffer);
9579 return PM_TOKEN_CHARACTER_LITERAL;
9581 size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9586 !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) ==
'_') ||
9588 (parser->current.end + encoding_width >= parser->end) ||
9589 !char_is_identifier(parser, parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
9592 lex_state_set(parser, PM_LEX_STATE_END);
9593 parser->current.end += encoding_width;
9594 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9595 return PM_TOKEN_CHARACTER_LITERAL;
9599 return PM_TOKEN_QUESTION_MARK;
9606static pm_token_type_t
9608 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9609 const uint8_t *end = parser->end;
9612 if ((width = char_is_identifier_start(parser, parser->current.end, end - parser->current.end)) > 0) {
9613 parser->current.end += width;
9615 while ((width = char_is_identifier(parser, parser->current.end, end - parser->current.end)) > 0) {
9616 parser->current.end += width;
9618 }
else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
9619 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9620 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
9621 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9624 size_t width = parser->encoding->char_width(parser->current.end, end - parser->current.end);
9625 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, (
int) ((parser->current.end + width) - parser->current.start), (
const char *) parser->current.start);
9627 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9628 pm_parser_err_token(parser, &parser->current, diag_id);
9633 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
9634 lex_mode_pop(parser);
9645 if (parser->lex_callback.callback) {
9646 parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
9659 .location = TOK2LOC(parser, &parser->current)
9670static pm_token_type_t
9673 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9675 if (newline == NULL) {
9676 parser->current.end = parser->end;
9678 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9679 parser->current.end = newline + 1;
9682 parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
9683 parser_lex_callback(parser);
9686 const uint8_t *comment_start = parser->current.start;
9687 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9691 while (parser->current.end + 4 <= parser->end) {
9692 parser->current.start = parser->current.end;
9697 (memcmp(parser->current.end,
"=end", 4) == 0) &&
9699 (parser->current.end + 4 == parser->end) ||
9700 pm_char_is_whitespace(parser->current.end[4]) ||
9701 (parser->current.end[4] ==
'\0') ||
9702 (parser->current.end[4] ==
'\004') ||
9703 (parser->current.end[4] ==
'\032')
9706 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9708 if (newline == NULL) {
9709 parser->current.end = parser->end;
9711 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9712 parser->current.end = newline + 1;
9715 parser->current.type = PM_TOKEN_EMBDOC_END;
9716 parser_lex_callback(parser);
9718 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9719 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9721 return PM_TOKEN_EMBDOC_END;
9726 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9728 if (newline == NULL) {
9729 parser->current.end = parser->end;
9731 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9732 parser->current.end = newline + 1;
9735 parser->current.type = PM_TOKEN_EMBDOC_LINE;
9736 parser_lex_callback(parser);
9739 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9741 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9742 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9744 return PM_TOKEN_EOF;
9754 parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
9755 parser_lex_callback(parser);
9769 assert(parser->heredoc_end <= parser->end);
9770 parser->next_start = parser->heredoc_end;
9771 parser->heredoc_end = NULL;
9779 const uint8_t *cursor = parser->current.end;
9781 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9782 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9845 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9859 if (parser->encoding_changed) {
9860 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9862 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9867 return (width == 0 ? 1 : width);
9875 size_t width = parser_char_width(parser);
9876 pm_buffer_append_bytes(&token_buffer->
buffer, parser->current.end, width);
9877 parser->current.end += width;
9882 size_t width = parser_char_width(parser);
9883 const uint8_t *start = parser->current.end;
9884 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, width);
9885 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, width);
9886 parser->current.end += width;
9898 size_t len = pm_buffer_length(&token_buffer->
buffer);
9899 void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->
buffer),
len,
PRISM_ALIGNOF(uint8_t));
9900 pm_string_constant_init(&parser->current_string, (
const char *) arena_data,
len);
9901 pm_buffer_cleanup(&token_buffer->
buffer);
9906 pm_token_buffer_copy(parser, &token_buffer->
base);
9921 if (token_buffer->
cursor == NULL) {
9922 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9924 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->current.end - token_buffer->
cursor));
9925 pm_token_buffer_copy(parser, token_buffer);
9932 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9934 const uint8_t *cursor = token_buffer->
base.
cursor;
9935 size_t length = (size_t) (parser->current.end - cursor);
9936 pm_buffer_append_bytes(&token_buffer->
base.
buffer, cursor, length);
9937 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, cursor, length);
9938 pm_regexp_token_buffer_copy(parser, token_buffer);
9942#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9954 const uint8_t *start;
9955 if (token_buffer->
cursor == NULL) {
9956 pm_buffer_init(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9957 start = parser->current.start;
9959 start = token_buffer->
cursor;
9962 const uint8_t *end = parser->current.end - 1;
9963 assert(end >= start);
9964 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9966 token_buffer->
cursor = end;
9971 const uint8_t *start;
9973 pm_buffer_init(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9974 pm_buffer_init(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9975 start = parser->current.start;
9980 const uint8_t *end = parser->current.end - 1;
9981 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9982 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9987#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9994pm_heredoc_strspn_inline_whitespace(
pm_parser_t *parser,
const uint8_t **cursor, pm_heredoc_indent_t indent) {
9995 size_t whitespace = 0;
9998 case PM_HEREDOC_INDENT_NONE:
10003 case PM_HEREDOC_INDENT_DASH:
10005 *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
10007 case PM_HEREDOC_INDENT_TILDE:
10010 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10011 if (**cursor ==
'\t') {
10012 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10031 size_t eol_length = match_eol(parser);
10034 if (parser->heredoc_end) {
10038 parser_flush_heredoc_end(parser);
10041 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
10044 uint8_t delimiter = *parser->current.end;
10048 if (eol_length == 2) {
10049 delimiter = *(parser->current.end + 1);
10052 parser->current.end += eol_length;
10056 return *parser->current.end++;
10063#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10073 assert(parser->current.end <= parser->end);
10074 parser->previous = parser->current;
10077 bool previous_command_start = parser->command_start;
10078 parser->command_start =
false;
10082 bool lexed_comment =
false;
10086 unsigned int semantic_token_seen = parser->semantic_token_seen;
10087 parser->semantic_token_seen =
true;
10095 switch (parser->lex_modes.current->mode) {
10096 case PM_LEX_DEFAULT:
10097 case PM_LEX_EMBEXPR:
10098 case PM_LEX_EMBVAR:
10107 if (parser->next_start != NULL) {
10108 parser->current.end = parser->next_start;
10109 parser->next_start = NULL;
10114 bool space_seen =
false;
10119 bool chomping =
true;
10126 static const uint8_t inline_whitespace[256] = {
10127 [
' '] = 1, [
'\t'] = 1, [
'\f'] = 1, [
'\v'] = 1
10129 const uint8_t *scan = parser->current.end;
10130 while (scan < parser->end && inline_whitespace[*scan]) scan++;
10131 if (scan > parser->current.end) {
10132 parser->current.end = scan;
10135 if (scan >= parser->end)
break;
10138 switch (*parser->current.end) {
10140 if (match_eol_offset(parser, 1)) {
10143 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10144 parser->current.end++;
10149 size_t eol_length = match_eol_offset(parser, 1);
10151 if (parser->heredoc_end) {
10152 parser->current.end = parser->heredoc_end;
10153 parser->heredoc_end = NULL;
10155 parser->current.end += eol_length + 1;
10156 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10159 }
else if (pm_char_is_inline_whitespace(*parser->current.end)) {
10160 parser->current.end += 2;
10174 parser->current.start = parser->current.end;
10178 if (parser->current.end >= parser->end) {
10182 if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
10183 lex_mode_pop(parser);
10184 goto switch_lex_modes;
10192 if (parser->current.start > parser->start && (*(parser->current.start - 1) ==
'\n')) {
10193 parser->current.start -= 1;
10200 switch (*parser->current.end++) {
10204 parser->current.end--;
10208 const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
10209 parser->current.end = ending == NULL ? parser->end : ending;
10214 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10215 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
10217 parser->current.type = PM_TOKEN_COMMENT;
10218 parser_lex_callback(parser);
10222 if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
10223 ptrdiff_t length = parser->current.end - parser->current.start;
10229 if (length >= 10 && !parser->encoding_locked) {
10230 parser_lex_magic_comment_encoding(parser);
10238 if (ending == NULL) {
10239 lexed_comment =
true;
10241 parser->current.start = ending;
10242 parser->current.end = ending + 1;
10248 parser->semantic_token_seen = semantic_token_seen & 0x1;
10249 size_t eol_length = match_eol_at(parser, parser->current.end - 1);
10261 if (!lexed_comment) {
10262 parser->current.end += eol_length - 1;
10265 if (parser->heredoc_end == NULL) {
10266 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10270 if (parser->heredoc_end) {
10271 parser_flush_heredoc_end(parser);
10276 switch (lex_state_ignored_p(parser)) {
10277 case PM_IGNORED_NEWLINE_NONE:
10279 case PM_IGNORED_NEWLINE_PATTERN:
10280 if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
10281 if (!lexed_comment) {
10282 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10283 parser_lex_callback(parser);
10286 lex_state_set(parser, PM_LEX_STATE_BEG);
10287 parser->command_start =
true;
10288 parser->current.type = PM_TOKEN_NEWLINE;
10292 case PM_IGNORED_NEWLINE_ALL:
10293 if (!lexed_comment) parser_lex_ignored_newline(parser);
10294 lexed_comment =
false;
10295 goto lex_next_token;
10302 const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
10303 next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
10305 if (next_content < parser->end) {
10311 if (next_content[0] ==
'#') {
10313 const uint8_t *following = next_newline(next_content, parser->end - next_content);
10315 while (following && (following + 1 < parser->end)) {
10317 following += pm_strspn_inline_whitespace(following, parser->end - following);
10321 if (peek_at(parser, following) !=
'#')
break;
10325 following = next_newline(following, parser->end - following);
10330 if (lex_state_ignored_p(parser)) {
10331 if (!lexed_comment) parser_lex_ignored_newline(parser);
10332 lexed_comment =
false;
10333 goto lex_next_token;
10339 (peek_at(parser, following) ==
'.') ||
10340 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10342 if (!lexed_comment) parser_lex_ignored_newline(parser);
10343 lexed_comment =
false;
10344 goto lex_next_token;
10352 (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
10354 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10355 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10357 peek_at(parser, following) ==
'a' &&
10358 peek_at(parser, following + 1) ==
'n' &&
10359 peek_at(parser, following + 2) ==
'd' &&
10360 peek_at(parser, next_content + 3) !=
'!' &&
10361 peek_at(parser, next_content + 3) !=
'?' &&
10362 !char_is_identifier(parser, following + 3, parser->end - (following + 3))
10365 peek_at(parser, following) ==
'o' &&
10366 peek_at(parser, following + 1) ==
'r' &&
10367 peek_at(parser, next_content + 2) !=
'!' &&
10368 peek_at(parser, next_content + 2) !=
'?' &&
10369 !char_is_identifier(parser, following + 2, parser->end - (following + 2))
10373 if (!lexed_comment) parser_lex_ignored_newline(parser);
10374 lexed_comment =
false;
10375 goto lex_next_token;
10381 if (next_content[0] ==
'.') {
10385 if (peek_at(parser, next_content + 1) ==
'.') {
10386 if (!lexed_comment) {
10387 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10388 parser_lex_callback(parser);
10391 lex_state_set(parser, PM_LEX_STATE_BEG);
10392 parser->command_start =
true;
10393 parser->current.type = PM_TOKEN_NEWLINE;
10397 if (!lexed_comment) parser_lex_ignored_newline(parser);
10398 lex_state_set(parser, PM_LEX_STATE_DOT);
10399 parser->current.start = next_content;
10400 parser->current.end = next_content + 1;
10401 parser->next_start = NULL;
10407 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10408 if (!lexed_comment) parser_lex_ignored_newline(parser);
10409 lex_state_set(parser, PM_LEX_STATE_DOT);
10410 parser->current.start = next_content;
10411 parser->current.end = next_content + 2;
10412 parser->next_start = NULL;
10413 LEX(PM_TOKEN_AMPERSAND_DOT);
10416 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
10419 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10420 if (!lexed_comment) parser_lex_ignored_newline(parser);
10421 lex_state_set(parser, PM_LEX_STATE_BEG);
10422 parser->current.start = next_content;
10423 parser->current.end = next_content + 2;
10424 parser->next_start = NULL;
10425 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10430 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10431 if (!lexed_comment) parser_lex_ignored_newline(parser);
10432 lex_state_set(parser, PM_LEX_STATE_BEG);
10433 parser->current.start = next_content;
10434 parser->current.end = next_content + 2;
10435 parser->next_start = NULL;
10436 LEX(PM_TOKEN_PIPE_PIPE);
10442 peek_at(parser, next_content) ==
'a' &&
10443 peek_at(parser, next_content + 1) ==
'n' &&
10444 peek_at(parser, next_content + 2) ==
'd' &&
10445 peek_at(parser, next_content + 3) !=
'!' &&
10446 peek_at(parser, next_content + 3) !=
'?' &&
10447 !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
10449 if (!lexed_comment) parser_lex_ignored_newline(parser);
10450 lex_state_set(parser, PM_LEX_STATE_BEG);
10451 parser->current.start = next_content;
10452 parser->current.end = next_content + 3;
10453 parser->next_start = NULL;
10454 parser->command_start =
true;
10455 LEX(PM_TOKEN_KEYWORD_AND);
10461 peek_at(parser, next_content) ==
'o' &&
10462 peek_at(parser, next_content + 1) ==
'r' &&
10463 peek_at(parser, next_content + 2) !=
'!' &&
10464 peek_at(parser, next_content + 2) !=
'?' &&
10465 !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
10467 if (!lexed_comment) parser_lex_ignored_newline(parser);
10468 lex_state_set(parser, PM_LEX_STATE_BEG);
10469 parser->current.start = next_content;
10470 parser->current.end = next_content + 2;
10471 parser->next_start = NULL;
10472 parser->command_start =
true;
10473 LEX(PM_TOKEN_KEYWORD_OR);
10480 lex_state_set(parser, PM_LEX_STATE_BEG);
10481 parser->command_start =
true;
10482 parser->current.type = PM_TOKEN_NEWLINE;
10483 if (!lexed_comment) parser_lex_callback(parser);
10489 if ((parser->previous.
type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
10490 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
10493 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10494 LEX(PM_TOKEN_COMMA);
10502 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10504 if (lex_state_beg_p(parser)) {
10505 type = PM_TOKEN_PARENTHESIS_LEFT_GROUPING;
10506 }
else if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10507 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10510 parser->enclosure_nesting++;
10511 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10512 pm_enclosure_frame_push(parser);
10518 parser->enclosure_nesting--;
10519 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10520 pm_enclosure_frame_pop(parser);
10521 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10525 lex_state_set(parser, PM_LEX_STATE_BEG);
10526 parser->command_start =
true;
10527 LEX(PM_TOKEN_SEMICOLON);
10531 parser->enclosure_nesting++;
10532 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10534 if (lex_state_operator_p(parser)) {
10535 if (match(parser,
']')) {
10536 parser->enclosure_nesting--;
10537 lex_state_set(parser, PM_LEX_STATE_ARG);
10538 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10541 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10545 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10546 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10549 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10550 pm_enclosure_frame_push(parser);
10555 parser->enclosure_nesting--;
10556 lex_state_set(parser, PM_LEX_STATE_END);
10557 pm_enclosure_frame_pop(parser);
10558 LEX(PM_TOKEN_BRACKET_RIGHT);
10562 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10564 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
10566 parser->command_start =
true;
10567 lex_state_set(parser, PM_LEX_STATE_BEG);
10568 type = PM_TOKEN_LAMBDA_BEGIN;
10569 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10571 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10572 type = PM_TOKEN_BRACE_LEFT_HASH;
10573 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10575 parser->command_start =
true;
10576 lex_state_set(parser, PM_LEX_STATE_BEG);
10577 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10580 parser->command_start =
true;
10581 lex_state_set(parser, PM_LEX_STATE_BEG);
10582 type = PM_TOKEN_BRACE_LEFT_ARGUMENT;
10585 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10586 type = PM_TOKEN_BRACE_LEFT_HASH;
10589 parser->enclosure_nesting++;
10590 parser->brace_nesting++;
10591 pm_enclosure_frame_push(parser);
10598 parser->enclosure_nesting--;
10599 pm_enclosure_frame_pop(parser);
10601 if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
10602 lex_mode_pop(parser);
10603 LEX(PM_TOKEN_EMBEXPR_END);
10606 parser->brace_nesting--;
10607 lex_state_set(parser, PM_LEX_STATE_END);
10608 LEX(PM_TOKEN_BRACE_RIGHT);
10612 if (match(parser,
'*')) {
10613 if (match(parser,
'=')) {
10614 lex_state_set(parser, PM_LEX_STATE_BEG);
10615 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10618 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10620 if (lex_state_spcarg_p(parser, space_seen)) {
10621 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10622 type = PM_TOKEN_USTAR_STAR;
10623 }
else if (lex_state_beg_p(parser)) {
10624 type = PM_TOKEN_USTAR_STAR;
10625 }
else if (ambiguous_operator_p(parser, space_seen)) {
10626 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10629 if (lex_state_operator_p(parser)) {
10630 lex_state_set(parser, PM_LEX_STATE_ARG);
10632 lex_state_set(parser, PM_LEX_STATE_BEG);
10638 if (match(parser,
'=')) {
10639 lex_state_set(parser, PM_LEX_STATE_BEG);
10640 LEX(PM_TOKEN_STAR_EQUAL);
10643 pm_token_type_t
type = PM_TOKEN_STAR;
10645 if (lex_state_spcarg_p(parser, space_seen)) {
10646 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10647 type = PM_TOKEN_USTAR;
10648 }
else if (lex_state_beg_p(parser)) {
10649 type = PM_TOKEN_USTAR;
10650 }
else if (ambiguous_operator_p(parser, space_seen)) {
10651 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10654 if (lex_state_operator_p(parser)) {
10655 lex_state_set(parser, PM_LEX_STATE_ARG);
10657 lex_state_set(parser, PM_LEX_STATE_BEG);
10665 if (lex_state_operator_p(parser)) {
10666 lex_state_set(parser, PM_LEX_STATE_ARG);
10667 if (match(parser,
'@')) {
10668 LEX(PM_TOKEN_BANG);
10671 lex_state_set(parser, PM_LEX_STATE_BEG);
10674 if (match(parser,
'=')) {
10675 LEX(PM_TOKEN_BANG_EQUAL);
10678 if (match(parser,
'~')) {
10679 LEX(PM_TOKEN_BANG_TILDE);
10682 LEX(PM_TOKEN_BANG);
10687 current_token_starts_line(parser) &&
10688 (parser->current.end + 5 <= parser->end) &&
10689 memcmp(parser->current.end,
"begin", 5) == 0 &&
10690 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10692 pm_token_type_t
type = lex_embdoc(parser);
10693 if (
type == PM_TOKEN_EOF) {
10697 goto lex_next_token;
10700 if (lex_state_operator_p(parser)) {
10701 lex_state_set(parser, PM_LEX_STATE_ARG);
10703 lex_state_set(parser, PM_LEX_STATE_BEG);
10706 if (match(parser,
'>')) {
10707 LEX(PM_TOKEN_EQUAL_GREATER);
10710 if (match(parser,
'~')) {
10711 LEX(PM_TOKEN_EQUAL_TILDE);
10714 if (match(parser,
'=')) {
10715 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10718 LEX(PM_TOKEN_EQUAL);
10722 if (match(parser,
'<')) {
10724 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10725 !lex_state_end_p(parser) &&
10726 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10728 const uint8_t *end = parser->current.end;
10730 pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
10731 pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
10733 if (match(parser,
'-')) {
10734 indent = PM_HEREDOC_INDENT_DASH;
10736 else if (match(parser,
'~')) {
10737 indent = PM_HEREDOC_INDENT_TILDE;
10740 if (match(parser,
'`')) {
10741 quote = PM_HEREDOC_QUOTE_BACKTICK;
10743 else if (match(parser,
'"')) {
10744 quote = PM_HEREDOC_QUOTE_DOUBLE;
10746 else if (match(parser,
'\'')) {
10747 quote = PM_HEREDOC_QUOTE_SINGLE;
10750 const uint8_t *ident_start = parser->current.end;
10753 if (parser->current.end >= parser->end) {
10754 parser->current.end = end;
10755 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) == 0) {
10756 parser->current.end = end;
10758 if (quote == PM_HEREDOC_QUOTE_NONE) {
10759 parser->current.end += width;
10761 while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end))) {
10762 parser->current.end += width;
10767 while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
10768 if (*parser->current.end ==
'\r' || *parser->current.end ==
'\n')
break;
10769 parser->current.end++;
10773 size_t ident_length = (size_t) (parser->current.end - ident_start);
10774 bool ident_error =
false;
10776 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10777 pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10778 ident_error =
true;
10781 parser->explicit_encoding = NULL;
10783 .mode = PM_LEX_HEREDOC,
10786 .ident_start = ident_start,
10787 .ident_length = ident_length,
10791 .next_start = parser->current.end,
10792 .common_whitespace = NULL,
10793 .line_continuation =
false
10797 if (parser->heredoc_end == NULL) {
10798 const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
10800 if (body_start == NULL) {
10805 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10806 body_start = parser->end;
10810 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
10814 parser->next_start = body_start;
10816 parser->next_start = parser->heredoc_end;
10819 LEX(PM_TOKEN_HEREDOC_START);
10823 if (match(parser,
'=')) {
10824 lex_state_set(parser, PM_LEX_STATE_BEG);
10825 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10828 if (ambiguous_operator_p(parser, space_seen)) {
10829 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10832 if (lex_state_operator_p(parser)) {
10833 lex_state_set(parser, PM_LEX_STATE_ARG);
10835 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10836 lex_state_set(parser, PM_LEX_STATE_BEG);
10839 LEX(PM_TOKEN_LESS_LESS);
10842 if (lex_state_operator_p(parser)) {
10843 lex_state_set(parser, PM_LEX_STATE_ARG);
10845 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10846 lex_state_set(parser, PM_LEX_STATE_BEG);
10849 if (match(parser,
'=')) {
10850 if (match(parser,
'>')) {
10851 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10854 LEX(PM_TOKEN_LESS_EQUAL);
10857 LEX(PM_TOKEN_LESS);
10861 if (match(parser,
'>')) {
10862 if (lex_state_operator_p(parser)) {
10863 lex_state_set(parser, PM_LEX_STATE_ARG);
10865 lex_state_set(parser, PM_LEX_STATE_BEG);
10867 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10870 if (lex_state_operator_p(parser)) {
10871 lex_state_set(parser, PM_LEX_STATE_ARG);
10873 lex_state_set(parser, PM_LEX_STATE_BEG);
10876 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10880 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10881 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10882 LEX(PM_TOKEN_STRING_BEGIN);
10887 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10888 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10889 LEX(PM_TOKEN_BACKTICK);
10892 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10893 if (previous_command_start) {
10894 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10896 lex_state_set(parser, PM_LEX_STATE_ARG);
10899 LEX(PM_TOKEN_BACKTICK);
10902 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10903 LEX(PM_TOKEN_XSTRING_BEGIN);
10908 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10909 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10910 LEX(PM_TOKEN_STRING_BEGIN);
10915 LEX(lex_question_mark(parser));
10919 if (match(parser,
'&')) {
10920 lex_state_set(parser, PM_LEX_STATE_BEG);
10922 if (match(parser,
'=')) {
10923 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10926 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10929 if (match(parser,
'=')) {
10930 lex_state_set(parser, PM_LEX_STATE_BEG);
10931 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10934 if (match(parser,
'.')) {
10935 lex_state_set(parser, PM_LEX_STATE_DOT);
10936 LEX(PM_TOKEN_AMPERSAND_DOT);
10939 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10940 if (lex_state_spcarg_p(parser, space_seen)) {
10941 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10942 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10944 const uint8_t delim = peek_offset(parser, 1);
10946 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->current.end + 1, parser->end - (parser->current.end + 1))) {
10947 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10951 type = PM_TOKEN_UAMPERSAND;
10952 }
else if (lex_state_beg_p(parser)) {
10953 type = PM_TOKEN_UAMPERSAND;
10954 }
else if (ambiguous_operator_p(parser, space_seen)) {
10955 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10958 if (lex_state_operator_p(parser)) {
10959 lex_state_set(parser, PM_LEX_STATE_ARG);
10961 lex_state_set(parser, PM_LEX_STATE_BEG);
10969 if (match(parser,
'|')) {
10970 if (match(parser,
'=')) {
10971 lex_state_set(parser, PM_LEX_STATE_BEG);
10972 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10975 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10976 parser->current.end--;
10977 LEX(PM_TOKEN_PIPE);
10980 lex_state_set(parser, PM_LEX_STATE_BEG);
10981 LEX(PM_TOKEN_PIPE_PIPE);
10984 if (match(parser,
'=')) {
10985 lex_state_set(parser, PM_LEX_STATE_BEG);
10986 LEX(PM_TOKEN_PIPE_EQUAL);
10989 if (lex_state_operator_p(parser)) {
10990 lex_state_set(parser, PM_LEX_STATE_ARG);
10992 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10995 LEX(PM_TOKEN_PIPE);
10999 if (lex_state_operator_p(parser)) {
11000 lex_state_set(parser, PM_LEX_STATE_ARG);
11002 if (match(parser,
'@')) {
11003 LEX(PM_TOKEN_UPLUS);
11006 LEX(PM_TOKEN_PLUS);
11009 if (match(parser,
'=')) {
11010 lex_state_set(parser, PM_LEX_STATE_BEG);
11011 LEX(PM_TOKEN_PLUS_EQUAL);
11015 lex_state_beg_p(parser) ||
11016 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11018 lex_state_set(parser, PM_LEX_STATE_BEG);
11020 if (pm_char_is_decimal_digit(peek(parser))) {
11021 parser->current.end++;
11022 pm_token_type_t
type = lex_numeric(parser);
11023 lex_state_set(parser, PM_LEX_STATE_END);
11027 LEX(PM_TOKEN_UPLUS);
11030 if (ambiguous_operator_p(parser, space_seen)) {
11031 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11034 lex_state_set(parser, PM_LEX_STATE_BEG);
11035 LEX(PM_TOKEN_PLUS);
11040 if (lex_state_operator_p(parser)) {
11041 lex_state_set(parser, PM_LEX_STATE_ARG);
11043 if (match(parser,
'@')) {
11044 LEX(PM_TOKEN_UMINUS);
11047 LEX(PM_TOKEN_MINUS);
11050 if (match(parser,
'=')) {
11051 lex_state_set(parser, PM_LEX_STATE_BEG);
11052 LEX(PM_TOKEN_MINUS_EQUAL);
11055 if (match(parser,
'>')) {
11056 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11057 LEX(PM_TOKEN_MINUS_GREATER);
11060 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11061 bool is_beg = lex_state_beg_p(parser);
11062 if (!is_beg && spcarg) {
11063 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11066 if (is_beg || spcarg) {
11067 lex_state_set(parser, PM_LEX_STATE_BEG);
11068 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11071 if (ambiguous_operator_p(parser, space_seen)) {
11072 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11075 lex_state_set(parser, PM_LEX_STATE_BEG);
11076 LEX(PM_TOKEN_MINUS);
11081 bool beg_p = lex_state_beg_p(parser);
11083 if (match(parser,
'.')) {
11084 if (match(parser,
'.')) {
11086 if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) {
11087 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11088 lex_state_set(parser, PM_LEX_STATE_BEG);
11090 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11092 LEX(PM_TOKEN_UDOT_DOT_DOT);
11095 if (parser->enclosure_nesting == 0 && parser_end_of_line_p(parser)) {
11096 pm_parser_warn_token(parser, &parser->current, PM_WARN_DOT_DOT_DOT_EOL);
11099 lex_state_set(parser, PM_LEX_STATE_BEG);
11100 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11103 lex_state_set(parser, PM_LEX_STATE_BEG);
11104 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11107 lex_state_set(parser, PM_LEX_STATE_DOT);
11122 pm_token_type_t
type = lex_numeric(parser);
11123 lex_state_set(parser, PM_LEX_STATE_END);
11129 if (match(parser,
':')) {
11130 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)) {
11131 lex_state_set(parser, PM_LEX_STATE_BEG);
11132 LEX(PM_TOKEN_UCOLON_COLON);
11135 lex_state_set(parser, PM_LEX_STATE_DOT);
11136 LEX(PM_TOKEN_COLON_COLON);
11139 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11140 lex_state_set(parser, PM_LEX_STATE_BEG);
11141 LEX(PM_TOKEN_COLON);
11144 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11145 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->current.end);
11146 parser->current.end++;
11153 parser->explicit_encoding = NULL;
11156 lex_state_set(parser, PM_LEX_STATE_FNAME);
11157 LEX(PM_TOKEN_SYMBOL_BEGIN);
11161 if (lex_state_beg_p(parser)) {
11162 lex_mode_push_regexp(parser,
'\0',
'/');
11163 LEX(PM_TOKEN_REGEXP_BEGIN);
11166 if (match(parser,
'=')) {
11167 lex_state_set(parser, PM_LEX_STATE_BEG);
11168 LEX(PM_TOKEN_SLASH_EQUAL);
11171 if (lex_state_spcarg_p(parser, space_seen)) {
11173 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_4_0) {
11174 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
11176 lex_mode_push_regexp(parser,
'\0',
'/');
11177 LEX(PM_TOKEN_REGEXP_BEGIN);
11180 if (ambiguous_operator_p(parser, space_seen)) {
11181 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11184 if (lex_state_operator_p(parser)) {
11185 lex_state_set(parser, PM_LEX_STATE_ARG);
11187 lex_state_set(parser, PM_LEX_STATE_BEG);
11190 LEX(PM_TOKEN_SLASH);
11194 if (lex_state_operator_p(parser)) {
11195 lex_state_set(parser, PM_LEX_STATE_ARG);
11197 lex_state_set(parser, PM_LEX_STATE_BEG);
11199 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11203 if (lex_state_operator_p(parser)) {
11204 (void) match(parser,
'@');
11205 lex_state_set(parser, PM_LEX_STATE_ARG);
11207 lex_state_set(parser, PM_LEX_STATE_BEG);
11210 LEX(PM_TOKEN_TILDE);
11218 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
11219 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11220 LEX(PM_TOKEN_PERCENT);
11223 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11224 lex_state_set(parser, PM_LEX_STATE_BEG);
11225 LEX(PM_TOKEN_PERCENT_EQUAL);
11227 lex_state_beg_p(parser) ||
11228 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11229 lex_state_spcarg_p(parser, space_seen)
11231 if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) {
11232 if (*parser->current.end >= 0x80) {
11233 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11234 goto lex_next_token;
11237 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11238 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11239 LEX(PM_TOKEN_STRING_BEGIN);
11244 uint8_t delimiter = peek_offset(parser, 1);
11245 if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) {
11246 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11247 goto lex_next_token;
11250 switch (peek(parser)) {
11252 parser->current.end++;
11254 if (parser->current.end < parser->end) {
11255 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11257 lex_mode_push_list_eof(parser);
11260 LEX(PM_TOKEN_PERCENT_LOWER_I);
11263 parser->current.end++;
11265 if (parser->current.end < parser->end) {
11266 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11268 lex_mode_push_list_eof(parser);
11271 LEX(PM_TOKEN_PERCENT_UPPER_I);
11274 parser->current.end++;
11276 if (parser->current.end < parser->end) {
11277 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11278 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11280 lex_mode_push_regexp(parser,
'\0',
'\0');
11283 LEX(PM_TOKEN_REGEXP_BEGIN);
11286 parser->current.end++;
11288 if (parser->current.end < parser->end) {
11289 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11290 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11292 lex_mode_push_string_eof(parser);
11295 LEX(PM_TOKEN_STRING_BEGIN);
11298 parser->current.end++;
11300 if (parser->current.end < parser->end) {
11301 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11302 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11304 lex_mode_push_string_eof(parser);
11307 LEX(PM_TOKEN_STRING_BEGIN);
11310 parser->current.end++;
11312 if (parser->current.end < parser->end) {
11313 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11314 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11315 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11317 lex_mode_push_string_eof(parser);
11320 LEX(PM_TOKEN_SYMBOL_BEGIN);
11323 parser->current.end++;
11325 if (parser->current.end < parser->end) {
11326 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11328 lex_mode_push_list_eof(parser);
11331 LEX(PM_TOKEN_PERCENT_LOWER_W);
11334 parser->current.end++;
11336 if (parser->current.end < parser->end) {
11337 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11339 lex_mode_push_list_eof(parser);
11342 LEX(PM_TOKEN_PERCENT_UPPER_W);
11345 parser->current.end++;
11347 if (parser->current.end < parser->end) {
11348 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11349 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11351 lex_mode_push_string_eof(parser);
11354 LEX(PM_TOKEN_PERCENT_LOWER_X);
11361 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11362 goto lex_next_token;
11366 if (ambiguous_operator_p(parser, space_seen)) {
11367 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11370 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11371 LEX(PM_TOKEN_PERCENT);
11376 pm_token_type_t
type = lex_global_variable(parser);
11380 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
11381 lex_mode_pop(parser);
11384 lex_state_set(parser, PM_LEX_STATE_END);
11390 lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11391 LEX(lex_at_variable(parser));
11394 if (*parser->current.start !=
'_') {
11395 size_t width = char_is_identifier_start(parser, parser->current.start, parser->end - parser->current.start);
11402 if (*parser->current.start >= 0x80) {
11403 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
11404 }
else if (*parser->current.start ==
'\\') {
11405 switch (peek_at(parser, parser->current.start + 1)) {
11407 parser->current.end++;
11408 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11411 parser->current.end++;
11412 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11415 parser->current.end++;
11416 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11419 parser->current.end++;
11420 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11423 if (peek_at(parser, parser->current.start + 2) !=
'\n') {
11424 parser->current.end++;
11425 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11430 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11433 }
else if (char_is_ascii_printable(*parser->current.start)) {
11434 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
11436 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
11439 goto lex_next_token;
11442 parser->current.end = parser->current.start + width;
11445 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11452 ((parser->current.end - parser->current.start) == 7) &&
11453 current_token_starts_line(parser) &&
11454 (memcmp(parser->current.start,
"__END__", 7) == 0) &&
11455 (parser->current.end == parser->end || match_eol(parser))
11460 const uint8_t *cursor = parser->current.end;
11461 while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
11462 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
11465 parser->current.end = parser->end;
11466 parser->current.type = PM_TOKEN___END__;
11467 parser_lex_callback(parser);
11469 parser->data_loc.
start = PM_TOKEN_START(parser, &parser->current);
11470 parser->data_loc.
length = PM_TOKEN_LENGTH(&parser->current);
11475 pm_lex_state_t last_state = parser->lex_state;
11477 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11478 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11479 if (previous_command_start) {
11480 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11482 lex_state_set(parser, PM_LEX_STATE_ARG);
11484 }
else if (parser->lex_state == PM_LEX_STATE_FNAME) {
11485 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11487 lex_state_set(parser, PM_LEX_STATE_END);
11492 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11493 (
type == PM_TOKEN_IDENTIFIER) &&
11494 ((pm_parser_local_depth(parser, &parser->current) != -1) ||
11495 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
11497 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11504 case PM_LEX_LIST: {
11505 if (parser->next_start != NULL) {
11506 parser->current.end = parser->next_start;
11507 parser->next_start = NULL;
11511 parser->current.start = parser->current.end;
11519 if (parser->heredoc_end) {
11520 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11521 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11524 }
else if (lex_mode->as.list.terminator ==
'\n') {
11529 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11531 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));
11534 if (whitespace > 0) {
11535 parser->current.end += whitespace;
11536 if (peek_offset(parser, -1) ==
'\n') {
11538 parser_flush_heredoc_end(parser);
11541 lex_mode->as.list.started =
true;
11542 lex_mode->as.list.separated =
true;
11543 LEX(PM_TOKEN_WORDS_SEP);
11548 if (parser->current.end >= parser->end) {
11557 if (!lex_mode->as.list.started) {
11558 lex_mode->as.list.started =
true;
11559 lex_mode->as.list.separated =
true;
11560 parser->current.type = PM_TOKEN_WORDS_SEP_IMPLICIT;
11561 parser_lex_callback(parser);
11566 const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
11567 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11573 while (breakpoint != NULL) {
11578 if (pm_char_is_whitespace(*breakpoint) && *breakpoint != lex_mode->as.list.terminator) {
11579 parser->current.end = breakpoint;
11580 pm_token_buffer_flush(parser, &token_buffer);
11581 lex_mode->as.list.separated =
false;
11582 LEX(PM_TOKEN_STRING_CONTENT);
11587 if (*breakpoint == lex_mode->as.list.terminator) {
11590 if (lex_mode->as.list.nesting > 0) {
11591 parser->current.end = breakpoint + 1;
11592 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11593 lex_mode->as.list.nesting--;
11599 if (breakpoint > parser->current.start) {
11600 parser->current.end = breakpoint;
11601 pm_token_buffer_flush(parser, &token_buffer);
11602 lex_mode->as.list.separated =
false;
11603 LEX(PM_TOKEN_STRING_CONTENT);
11611 if (!lex_mode->as.list.separated) {
11612 lex_mode->as.list.separated =
true;
11613 parser->current.end = breakpoint;
11614 parser->current.type = PM_TOKEN_WORDS_SEP_IMPLICIT;
11615 parser_lex_callback(parser);
11620 parser->current.end = breakpoint + 1;
11625 if (*breakpoint ==
'\n') {
11626 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11629 lex_mode_pop(parser);
11630 lex_state_set(parser, PM_LEX_STATE_END);
11631 LEX(PM_TOKEN_STRING_END);
11635 if (*breakpoint ==
'\0') {
11636 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1),
true);
11643 if (*breakpoint ==
'\\') {
11644 parser->current.end = breakpoint + 1;
11648 if (parser->current.end == parser->end) {
11653 pm_token_buffer_escape(parser, &token_buffer);
11654 uint8_t peeked = peek(parser);
11662 pm_token_buffer_push_byte(&token_buffer, peeked);
11663 parser->current.end++;
11666 parser->current.end++;
11667 if (peek(parser) !=
'\n') {
11668 pm_token_buffer_push_byte(&token_buffer,
'\r');
11673 pm_token_buffer_push_byte(&token_buffer,
'\n');
11675 if (parser->heredoc_end) {
11679 parser_flush_heredoc_end(parser);
11680 pm_token_buffer_copy(parser, &token_buffer);
11681 LEX(PM_TOKEN_STRING_CONTENT);
11684 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11687 parser->current.end++;
11690 if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
11691 pm_token_buffer_push_byte(&token_buffer, peeked);
11692 parser->current.end++;
11693 }
else if (lex_mode->as.list.interpolation) {
11694 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11696 pm_token_buffer_push_byte(&token_buffer,
'\\');
11697 pm_token_buffer_push_escaped(&token_buffer, parser);
11703 token_buffer.
cursor = parser->current.end;
11704 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11709 if (*breakpoint ==
'#') {
11710 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11717 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11721 if (
type == PM_TOKEN_STRING_CONTENT) {
11722 pm_token_buffer_flush(parser, &token_buffer);
11725 lex_mode->as.list.separated =
false;
11731 assert(*breakpoint == lex_mode->as.list.incrementor);
11732 parser->current.end = breakpoint + 1;
11733 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11734 lex_mode->as.list.nesting++;
11738 if (parser->current.end > parser->current.start) {
11739 pm_token_buffer_flush(parser, &token_buffer);
11740 LEX(PM_TOKEN_STRING_CONTENT);
11745 parser->current.end = parser->end;
11746 pm_token_buffer_flush(parser, &token_buffer);
11747 LEX(PM_TOKEN_STRING_CONTENT);
11749 case PM_LEX_REGEXP: {
11751 if (parser->next_start == NULL) {
11752 parser->current.start = parser->current.end;
11754 parser->current.start = parser->next_start;
11755 parser->current.end = parser->next_start;
11756 parser->next_start = NULL;
11761 if (parser->current.end >= parser->end) {
11771 const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
11772 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11775 while (breakpoint != NULL) {
11776 uint8_t term = lex_mode->as.regexp.terminator;
11777 bool is_terminator = (*breakpoint == term);
11782 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11783 if (term ==
'\n') {
11784 is_terminator =
true;
11790 if (term ==
'\r') {
11791 is_terminator =
false;
11797 if (is_terminator) {
11798 if (lex_mode->as.regexp.nesting > 0) {
11799 parser->current.end = breakpoint + 1;
11800 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11801 lex_mode->as.regexp.nesting--;
11808 if (breakpoint > parser->current.start) {
11809 parser->current.end = breakpoint;
11810 pm_regexp_token_buffer_flush(parser, &token_buffer);
11811 LEX(PM_TOKEN_STRING_CONTENT);
11815 size_t eol_length = match_eol_at(parser, breakpoint);
11817 parser->current.end = breakpoint + eol_length;
11822 if (parser->heredoc_end == NULL) {
11823 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11826 parser->current.end = breakpoint + 1;
11831 parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
11833 lex_mode_pop(parser);
11834 lex_state_set(parser, PM_LEX_STATE_END);
11835 LEX(PM_TOKEN_REGEXP_END);
11840 if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
11841 parser->current.end = breakpoint + 1;
11842 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11843 lex_mode->as.regexp.nesting++;
11847 switch (*breakpoint) {
11850 parser->current.end = breakpoint + 1;
11851 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11854 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11855 parser->current.end = breakpoint + 1;
11856 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11861 parser->current.end = breakpoint;
11862 pm_regexp_token_buffer_escape(parser, &token_buffer);
11869 if (parser->heredoc_end == NULL) {
11870 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
11871 parser->current.end = breakpoint + 1;
11872 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11876 parser->current.end = breakpoint + 1;
11877 parser_flush_heredoc_end(parser);
11878 pm_regexp_token_buffer_flush(parser, &token_buffer);
11879 LEX(PM_TOKEN_STRING_CONTENT);
11884 parser->current.end = breakpoint + 1;
11888 if (parser->current.end == parser->end) {
11893 pm_regexp_token_buffer_escape(parser, &token_buffer);
11894 uint8_t peeked = peek(parser);
11898 parser->current.end++;
11899 if (peek(parser) !=
'\n') {
11900 if (lex_mode->as.regexp.terminator !=
'\r') {
11901 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11903 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11904 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11909 if (parser->heredoc_end) {
11913 parser_flush_heredoc_end(parser);
11914 pm_regexp_token_buffer_copy(parser, &token_buffer);
11915 LEX(PM_TOKEN_STRING_CONTENT);
11918 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11921 parser->current.end++;
11931 if (lex_mode->as.regexp.terminator == peeked) {
11936 case '$':
case ')':
case '*':
case '+':
11937 case '.':
case '>':
case '?':
case ']':
11938 case '^':
case '|':
case '}':
11939 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11945 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11946 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11947 parser->current.end++;
11951 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11952 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11956 token_buffer.
base.
cursor = parser->current.end;
11957 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11963 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11970 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11974 if (
type == PM_TOKEN_STRING_CONTENT) {
11975 pm_regexp_token_buffer_flush(parser, &token_buffer);
11981 assert(
false &&
"unreachable");
11986 if (parser->current.end > parser->current.start) {
11987 pm_regexp_token_buffer_flush(parser, &token_buffer);
11988 LEX(PM_TOKEN_STRING_CONTENT);
11993 parser->current.end = parser->end;
11994 pm_regexp_token_buffer_flush(parser, &token_buffer);
11995 LEX(PM_TOKEN_STRING_CONTENT);
11997 case PM_LEX_STRING: {
11999 if (parser->next_start == NULL) {
12000 parser->current.start = parser->current.end;
12002 parser->current.start = parser->next_start;
12003 parser->current.end = parser->next_start;
12004 parser->next_start = NULL;
12009 if (parser->current.end >= parser->end) {
12016 const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
12017 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12023 while (breakpoint != NULL) {
12026 if (lex_mode->as.string.incrementor !=
'\0' && *breakpoint == lex_mode->as.string.incrementor) {
12027 lex_mode->as.string.nesting++;
12028 parser->current.end = breakpoint + 1;
12029 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12033 uint8_t term = lex_mode->as.string.terminator;
12034 bool is_terminator = (*breakpoint == term);
12039 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12040 if (term ==
'\n') {
12041 is_terminator =
true;
12047 if (term ==
'\r') {
12048 is_terminator =
false;
12055 if (is_terminator) {
12058 if (lex_mode->as.string.nesting > 0) {
12059 parser->current.end = breakpoint + 1;
12060 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12061 lex_mode->as.string.nesting--;
12067 if (breakpoint > parser->current.start) {
12068 parser->current.end = breakpoint;
12069 pm_token_buffer_flush(parser, &token_buffer);
12070 LEX(PM_TOKEN_STRING_CONTENT);
12075 size_t eol_length = match_eol_at(parser, breakpoint);
12077 parser->current.end = breakpoint + eol_length;
12082 if (parser->heredoc_end == NULL) {
12083 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
12086 parser->current.end = breakpoint + 1;
12089 if (lex_mode->as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12090 parser->current.end++;
12091 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12092 lex_mode_pop(parser);
12093 LEX(PM_TOKEN_LABEL_END);
12099 if (term ==
'\n' && parser->heredoc_end) {
12100 parser_flush_heredoc_end(parser);
12103 lex_state_set(parser, PM_LEX_STATE_END);
12104 lex_mode_pop(parser);
12105 LEX(PM_TOKEN_STRING_END);
12108 switch (*breakpoint) {
12111 parser->current.end = breakpoint + 1;
12112 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12115 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12116 parser->current.end = breakpoint + 1;
12117 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12124 parser->current.end = breakpoint;
12125 pm_token_buffer_escape(parser, &token_buffer);
12126 token_buffer.
cursor = breakpoint;
12134 if (parser->heredoc_end == NULL) {
12135 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12136 parser->current.end = breakpoint + 1;
12137 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12141 parser->current.end = breakpoint + 1;
12142 parser_flush_heredoc_end(parser);
12143 pm_token_buffer_flush(parser, &token_buffer);
12144 LEX(PM_TOKEN_STRING_CONTENT);
12147 parser->current.end = breakpoint + 1;
12151 if (parser->current.end == parser->end) {
12156 pm_token_buffer_escape(parser, &token_buffer);
12157 uint8_t peeked = peek(parser);
12161 pm_token_buffer_push_byte(&token_buffer,
'\\');
12162 parser->current.end++;
12165 parser->current.end++;
12166 if (peek(parser) !=
'\n') {
12167 if (!lex_mode->as.string.interpolation) {
12168 pm_token_buffer_push_byte(&token_buffer,
'\\');
12170 pm_token_buffer_push_byte(&token_buffer,
'\r');
12175 if (!lex_mode->as.string.interpolation) {
12176 pm_token_buffer_push_byte(&token_buffer,
'\\');
12177 pm_token_buffer_push_byte(&token_buffer,
'\n');
12180 if (parser->heredoc_end) {
12184 parser_flush_heredoc_end(parser);
12185 pm_token_buffer_copy(parser, &token_buffer);
12186 LEX(PM_TOKEN_STRING_CONTENT);
12189 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
12192 parser->current.end++;
12195 if (lex_mode->as.string.incrementor !=
'\0' && peeked == lex_mode->as.string.incrementor) {
12196 pm_token_buffer_push_byte(&token_buffer, peeked);
12197 parser->current.end++;
12198 }
else if (lex_mode->as.string.terminator !=
'\0' && peeked == lex_mode->as.string.terminator) {
12199 pm_token_buffer_push_byte(&token_buffer, peeked);
12200 parser->current.end++;
12201 }
else if (lex_mode->as.string.interpolation) {
12202 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12204 pm_token_buffer_push_byte(&token_buffer,
'\\');
12205 pm_token_buffer_push_escaped(&token_buffer, parser);
12211 token_buffer.
cursor = parser->current.end;
12212 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12216 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12223 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12227 if (
type == PM_TOKEN_STRING_CONTENT) {
12228 pm_token_buffer_flush(parser, &token_buffer);
12234 assert(
false &&
"unreachable");
12238 if (parser->current.end > parser->current.start) {
12239 pm_token_buffer_flush(parser, &token_buffer);
12240 LEX(PM_TOKEN_STRING_CONTENT);
12245 parser->current.end = parser->end;
12246 pm_token_buffer_flush(parser, &token_buffer);
12247 LEX(PM_TOKEN_STRING_CONTENT);
12249 case PM_LEX_HEREDOC: {
12251 if (parser->next_start == NULL) {
12252 parser->current.start = parser->current.end;
12254 parser->current.start = parser->next_start;
12255 parser->current.end = parser->next_start;
12256 parser->heredoc_end = NULL;
12257 parser->next_start = NULL;
12265 bool line_continuation = lex_mode->as.heredoc.line_continuation;
12266 lex_mode->as.heredoc.line_continuation =
false;
12272 if (parser->current.end >= parser->end) {
12273 pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
12274 parser->next_start = lex_mode->as.heredoc.next_start;
12275 parser->heredoc_end = parser->current.end;
12276 lex_state_set(parser, PM_LEX_STATE_END);
12277 lex_mode_pop(parser);
12278 LEX(PM_TOKEN_HEREDOC_END);
12281 const uint8_t *ident_start = heredoc_lex_mode->ident_start;
12282 size_t ident_length = heredoc_lex_mode->ident_length;
12286 if (current_token_starts_line(parser)) {
12287 const uint8_t *start = parser->current.start;
12289 if (!line_continuation && (start + ident_length <= parser->end)) {
12290 const uint8_t *newline = next_newline(start, parser->end - start);
12291 const uint8_t *ident_end = newline;
12292 const uint8_t *terminator_end = newline;
12294 if (newline == NULL) {
12295 terminator_end = parser->end;
12296 ident_end = parser->end;
12299 if (newline[-1] ==
'\r') {
12304 const uint8_t *terminator_start = ident_end - ident_length;
12305 const uint8_t *cursor = start;
12307 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12308 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12314 (cursor == terminator_start) &&
12315 (memcmp(terminator_start, ident_start, ident_length) == 0)
12317 if (newline != NULL) {
12318 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
12321 parser->current.end = terminator_end;
12322 if (*lex_mode->as.heredoc.next_start ==
'\\') {
12323 parser->next_start = NULL;
12325 parser->next_start = lex_mode->as.heredoc.next_start;
12326 parser->heredoc_end = parser->current.end;
12329 lex_state_set(parser, PM_LEX_STATE_END);
12330 lex_mode_pop(parser);
12331 LEX(PM_TOKEN_HEREDOC_END);
12335 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
12337 heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
12338 lex_mode->as.heredoc.common_whitespace != NULL &&
12339 (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
12340 peek_at(parser, start) !=
'\n'
12342 *lex_mode->as.heredoc.common_whitespace = whitespace;
12349 uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] =
"\r\n\\#";
12351 pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
12352 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12353 breakpoints[3] =
'\0';
12356 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12358 bool was_line_continuation =
false;
12360 while (breakpoint != NULL) {
12361 switch (*breakpoint) {
12364 parser->current.end = breakpoint + 1;
12365 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12368 parser->current.end = breakpoint + 1;
12370 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12371 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12378 pm_token_buffer_escape(parser, &token_buffer);
12379 token_buffer.
cursor = breakpoint;
12383 if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
12384 parser_flush_heredoc_end(parser);
12385 parser->current.end = breakpoint + 1;
12386 pm_token_buffer_flush(parser, &token_buffer);
12387 LEX(PM_TOKEN_STRING_CONTENT);
12390 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12394 const uint8_t *start = breakpoint + 1;
12396 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12399 const uint8_t *newline = next_newline(start, parser->end - start);
12401 if (newline == NULL) {
12402 newline = parser->end;
12403 }
else if (newline[-1] ==
'\r') {
12408 const uint8_t *terminator_start = newline - ident_length;
12412 const uint8_t *cursor = start;
12414 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12415 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12421 cursor == terminator_start &&
12422 (memcmp(terminator_start, ident_start, ident_length) == 0)
12424 parser->current.end = breakpoint + 1;
12425 pm_token_buffer_flush(parser, &token_buffer);
12426 LEX(PM_TOKEN_STRING_CONTENT);
12430 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
12437 if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12438 if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12439 *lex_mode->as.heredoc.common_whitespace = whitespace;
12442 parser->current.end = breakpoint + 1;
12443 pm_token_buffer_flush(parser, &token_buffer);
12444 LEX(PM_TOKEN_STRING_CONTENT);
12449 parser->current.end = breakpoint + 1;
12450 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12460 parser->current.end = breakpoint + 1;
12464 if (parser->current.end == parser->end) {
12469 pm_token_buffer_escape(parser, &token_buffer);
12470 uint8_t peeked = peek(parser);
12472 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12475 parser->current.end++;
12476 if (peek(parser) !=
'\n') {
12477 pm_token_buffer_push_byte(&token_buffer,
'\\');
12478 pm_token_buffer_push_byte(&token_buffer,
'\r');
12483 pm_token_buffer_push_byte(&token_buffer,
'\\');
12484 pm_token_buffer_push_byte(&token_buffer,
'\n');
12485 token_buffer.
cursor = parser->current.end + 1;
12486 breakpoint = parser->current.end;
12489 pm_token_buffer_push_byte(&token_buffer,
'\\');
12490 pm_token_buffer_push_escaped(&token_buffer, parser);
12496 parser->current.end++;
12497 if (peek(parser) !=
'\n') {
12498 pm_token_buffer_push_byte(&token_buffer,
'\r');
12506 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12507 const uint8_t *end = parser->current.end;
12509 if (parser->heredoc_end == NULL) {
12510 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
12515 parser->current.end = breakpoint;
12516 pm_token_buffer_flush(parser, &token_buffer);
12520 parser->current.end = end + 1;
12521 lex_mode->as.heredoc.line_continuation =
true;
12522 LEX(PM_TOKEN_STRING_CONTENT);
12525 was_line_continuation =
true;
12526 token_buffer.
cursor = parser->current.end + 1;
12527 breakpoint = parser->current.end;
12530 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12535 token_buffer.
cursor = parser->current.end;
12536 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12540 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12548 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12552 if (
type == PM_TOKEN_STRING_CONTENT) {
12553 pm_token_buffer_flush(parser, &token_buffer);
12559 assert(
false &&
"unreachable");
12562 was_line_continuation =
false;
12565 if (parser->current.end > parser->current.start) {
12566 parser->current.end = parser->end;
12567 pm_token_buffer_flush(parser, &token_buffer);
12568 LEX(PM_TOKEN_STRING_CONTENT);
12573 parser->current.end = parser->end;
12574 pm_token_buffer_flush(parser, &token_buffer);
12575 LEX(PM_TOKEN_STRING_CONTENT);
12579 assert(
false &&
"unreachable");
12597 PM_BINDING_POWER_UNSET = 0,
12598 PM_BINDING_POWER_STATEMENT = 2,
12599 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12600 PM_BINDING_POWER_MODIFIER = 6,
12601 PM_BINDING_POWER_COMPOSITION = 8,
12602 PM_BINDING_POWER_NOT = 10,
12603 PM_BINDING_POWER_MATCH = 12,
12604 PM_BINDING_POWER_DEFINED = 14,
12605 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12606 PM_BINDING_POWER_ASSIGNMENT = 18,
12607 PM_BINDING_POWER_TERNARY = 20,
12608 PM_BINDING_POWER_RANGE = 22,
12609 PM_BINDING_POWER_LOGICAL_OR = 24,
12610 PM_BINDING_POWER_LOGICAL_AND = 26,
12611 PM_BINDING_POWER_EQUALITY = 28,
12612 PM_BINDING_POWER_COMPARISON = 30,
12613 PM_BINDING_POWER_BITWISE_OR = 32,
12614 PM_BINDING_POWER_BITWISE_AND = 34,
12615 PM_BINDING_POWER_SHIFT = 36,
12616 PM_BINDING_POWER_TERM = 38,
12617 PM_BINDING_POWER_FACTOR = 40,
12618 PM_BINDING_POWER_UMINUS = 42,
12619 PM_BINDING_POWER_EXPONENT = 44,
12620 PM_BINDING_POWER_UNARY = 46,
12621 PM_BINDING_POWER_INDEX = 48,
12622 PM_BINDING_POWER_CALL = 50,
12623 PM_BINDING_POWER_MAX = 52
12624} pm_binding_power_t;
12647#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12648#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12649#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12650#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12651#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12655 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12658 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12659 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12660 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12661 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12664 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12665 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12668 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12669 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12672 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12673 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12674 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12675 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12676 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12677 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12678 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12679 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12680 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12681 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12682 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12683 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12684 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12685 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12688 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12691 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12692 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12693 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12694 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12697 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12700 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12703 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12704 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12705 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12706 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12707 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12708 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12711 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12712 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12713 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12714 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12717 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12718 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12721 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12724 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12725 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12728 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12729 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12732 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12733 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12734 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12735 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12738 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12739 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12742 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12743 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12746 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12747 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12748 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12751 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12754 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12755 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12756 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12759#undef BINDING_POWER_ASSIGNMENT
12760#undef LEFT_ASSOCIATIVE
12761#undef RIGHT_ASSOCIATIVE
12762#undef RIGHT_ASSOCIATIVE_UNARY
12769 return parser->current.type ==
type;
12776match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12777 return match1(parser, type1) || match1(parser, type2);
12784match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12785 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12792match4(
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) {
12793 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12800match5(
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) {
12801 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5);
12808match6(
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) {
12809 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
12816match8(
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) {
12817 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);
12828 if (match1(parser,
type)) {
12829 parser_lex(parser);
12840accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12841 if (match2(parser, type1, type2)) {
12842 parser_lex(parser);
12860expect1(
pm_parser_t *parser, pm_token_type_t
type, pm_diagnostic_id_t diag_id) {
12861 if (accept1(parser,
type))
return;
12863 const uint8_t *location = parser->previous.
end;
12864 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12866 parser->previous.
start = location;
12867 parser->previous.
type = 0;
12875expect2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
12876 if (accept2(parser, type1, type2))
return;
12878 const uint8_t *location = parser->previous.
end;
12879 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12881 parser->previous.
start = location;
12882 parser->previous.
type = 0;
12890expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12891 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12892 parser_lex(parser);
12894 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12895 parser->previous.
start = parser->previous.
end;
12896 parser->previous.
type = 0;
12908 if (accept1(parser,
type))
return;
12910 const uint8_t *start = opening->
start;
12911 pm_parser_err(parser, U32(start - parser->start), U32(opening->
end - start), diag_id);
12913 parser->previous.
start = parser->previous.
end;
12914 parser->previous.
type = 0;
12918#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
12919#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
12920#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
12921#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
12932#define PM_PARSE_ACCEPTS_STATEMENT ((uint8_t) 0x10)
12935parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
12942parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
12943 pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
12944 pm_assert_value_expression(parser, node);
12967token_begins_expression_p(pm_token_type_t
type) {
12969 case PM_TOKEN_EQUAL_GREATER:
12970 case PM_TOKEN_KEYWORD_IN:
12974 case PM_TOKEN_BRACE_RIGHT:
12975 case PM_TOKEN_BRACKET_RIGHT:
12976 case PM_TOKEN_COLON:
12977 case PM_TOKEN_COMMA:
12978 case PM_TOKEN_EMBEXPR_END:
12980 case PM_TOKEN_LAMBDA_BEGIN:
12981 case PM_TOKEN_KEYWORD_DO:
12982 case PM_TOKEN_KEYWORD_DO_BLOCK:
12983 case PM_TOKEN_KEYWORD_DO_LAMBDA:
12984 case PM_TOKEN_KEYWORD_DO_LOOP:
12985 case PM_TOKEN_KEYWORD_END:
12986 case PM_TOKEN_KEYWORD_ELSE:
12987 case PM_TOKEN_KEYWORD_ELSIF:
12988 case PM_TOKEN_KEYWORD_ENSURE:
12989 case PM_TOKEN_KEYWORD_THEN:
12990 case PM_TOKEN_KEYWORD_RESCUE:
12991 case PM_TOKEN_KEYWORD_WHEN:
12992 case PM_TOKEN_NEWLINE:
12993 case PM_TOKEN_PARENTHESIS_RIGHT:
12994 case PM_TOKEN_SEMICOLON:
13000 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13002 case PM_TOKEN_UAMPERSAND:
13006 case PM_TOKEN_UCOLON_COLON:
13007 case PM_TOKEN_UMINUS:
13008 case PM_TOKEN_UMINUS_NUM:
13009 case PM_TOKEN_UPLUS:
13010 case PM_TOKEN_BANG:
13011 case PM_TOKEN_TILDE:
13012 case PM_TOKEN_UDOT_DOT:
13013 case PM_TOKEN_UDOT_DOT_DOT:
13020 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13040token_begins_pattern_p(pm_token_type_t
type) {
13042 token_begins_expression_p(
type) ||
13043 type == PM_TOKEN_USTAR ||
13044 type == PM_TOKEN_USTAR_STAR ||
13045 type == PM_TOKEN_CARET
13054parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
13055 if (accept1(parser, PM_TOKEN_USTAR)) {
13057 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));
13058 return UP(pm_splat_node_create(parser, &
operator, expression));
13061 return parse_value_expression(parser, binding_power, flags, diag_id, depth);
13065pm_node_unreference_each(
const pm_node_t *node,
void *data) {
13066 switch (PM_NODE_TYPE(node)) {
13071 case PM_BREAK_NODE:
13073 case PM_REDO_NODE: {
13077 while (index < parser->current_block_exits->size) {
13078 pm_node_t *block_exit = parser->current_block_exits->
nodes[index];
13080 if (block_exit == node) {
13081 if (index + 1 < parser->current_block_exits->
size) {
13083 &parser->current_block_exits->
nodes[index],
13084 &parser->current_block_exits->
nodes[index + 1],
13085 (parser->current_block_exits->
size - index - 1) *
sizeof(
pm_node_t *)
13088 parser->current_block_exits->
size--;
13103 case PM_LOCAL_VARIABLE_READ_NODE:
13104 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13106 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
13108 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13109 if (implicit_parameters->
nodes[index] == node) {
13113 if (index != implicit_parameters->
size - 1) {
13114 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13117 implicit_parameters->
size--;
13136 pm_visit_node(node, pm_node_unreference_each, parser);
13149 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *name_field);
13150 size_t length = constant->length;
13151 uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
13153 memcpy(name, constant->start, length);
13154 name[length] =
'=';
13156 *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
13167 switch (PM_NODE_TYPE(target)) {
13168 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13169 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13170 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13171 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13172 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13173 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13174 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13178 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
13194 switch (PM_NODE_TYPE(target)) {
13195 case PM_ERROR_RECOVERY_NODE:
13197 case PM_SOURCE_ENCODING_NODE:
13198 case PM_FALSE_NODE:
13199 case PM_SOURCE_FILE_NODE:
13200 case PM_SOURCE_LINE_NODE:
13203 case PM_TRUE_NODE: {
13206 return parse_unwriteable_target(parser, target);
13208 case PM_CLASS_VARIABLE_READ_NODE:
13210 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13212 case PM_CONSTANT_PATH_NODE:
13213 if (context_def_p(parser)) {
13214 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13218 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13221 case PM_CONSTANT_READ_NODE:
13222 if (context_def_p(parser)) {
13223 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13227 target->
type = PM_CONSTANT_TARGET_NODE;
13230 case PM_BACK_REFERENCE_READ_NODE:
13231 case PM_NUMBERED_REFERENCE_READ_NODE:
13232 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13233 return UP(pm_error_recovery_node_create_unexpected(parser, target));
13234 case PM_GLOBAL_VARIABLE_READ_NODE:
13236 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13238 case PM_LOCAL_VARIABLE_READ_NODE: {
13239 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13240 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
13241 pm_node_unreference(parser, target);
13245 uint32_t name = cast->
name;
13246 uint32_t depth = cast->
depth;
13247 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13250 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13254 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13256 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
13258 pm_node_unreference(parser, target);
13262 case PM_INSTANCE_VARIABLE_READ_NODE:
13264 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13266 case PM_MULTI_TARGET_NODE:
13267 if (splat_parent) {
13270 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13274 case PM_SPLAT_NODE: {
13283 case PM_CALL_NODE: {
13295 (call->
block == NULL)
13308 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
13310 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
13314 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13315 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13318 parse_write_name(parser, &call->
name);
13319 return UP(pm_call_target_node_create(parser, call));
13326 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13327 return UP(pm_index_target_node_create(parser, call));
13335 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13346 pm_node_t *result = parse_target(parser, target, multiple,
false);
13351 !match1(parser, PM_TOKEN_EQUAL) &&
13352 !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
13353 !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13355 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13367 pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
13369 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13370 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
13381 switch (PM_NODE_TYPE(target)) {
13382 case PM_ERROR_RECOVERY_NODE:
13384 case PM_CLASS_VARIABLE_READ_NODE: {
13388 case PM_CONSTANT_PATH_NODE: {
13391 if (context_def_p(parser)) {
13392 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13395 return parse_shareable_constant_write(parser, node);
13397 case PM_CONSTANT_READ_NODE: {
13400 if (context_def_p(parser)) {
13401 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13404 return parse_shareable_constant_write(parser, node);
13406 case PM_BACK_REFERENCE_READ_NODE:
13407 case PM_NUMBERED_REFERENCE_READ_NODE:
13408 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13410 case PM_GLOBAL_VARIABLE_READ_NODE: {
13414 case PM_LOCAL_VARIABLE_READ_NODE: {
13419 uint32_t depth = local_read->
depth;
13420 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13422 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13423 pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13424 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
13425 pm_node_unreference(parser, target);
13428 pm_locals_unread(&scope->locals, name);
13430 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
13432 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13434 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
13436 pm_node_unreference(parser, target);
13440 case PM_INSTANCE_VARIABLE_READ_NODE: {
13444 case PM_MULTI_TARGET_NODE:
13446 case PM_SPLAT_NODE: {
13454 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
13456 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
13458 case PM_CALL_NODE: {
13470 (call->
block == NULL)
13484 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
13485 pm_parser_local_add_location(parser, &message_loc, 0);
13487 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));
13488 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
13507 pm_arguments_node_arguments_append(parser->arena, arguments, value);
13508 PM_NODE_LENGTH_SET_NODE(call, arguments);
13509 call->
equal_loc = TOK2LOC(parser,
operator);
13511 parse_write_name(parser, &call->
name);
13512 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13521 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13523 call->
arguments = pm_arguments_node_create(parser);
13526 pm_arguments_node_arguments_append(parser->arena, call->
arguments, value);
13527 PM_NODE_LENGTH_SET_NODE(target, value);
13530 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13531 call->
equal_loc = TOK2LOC(parser,
operator);
13535 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13550 pm_node_unreference(parser, value);
13557 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13570 switch (PM_NODE_TYPE(target)) {
13571 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13572 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13573 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13574 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13575 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13576 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13577 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13598parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13599 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13602 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13604 while (accept1(parser, PM_TOKEN_COMMA)) {
13605 if (accept1(parser, PM_TOKEN_USTAR)) {
13610 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13613 pm_token_t star_operator = parser->previous;
13616 if (token_begins_expression_p(parser->current.type)) {
13617 name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13618 name = parse_target(parser, name,
true,
true);
13621 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13622 pm_multi_target_node_targets_append(parser, result, splat);
13624 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
13625 context_push(parser, PM_CONTEXT_MULTI_TARGET);
13626 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13627 target = parse_target(parser, target,
true,
false);
13629 pm_multi_target_node_targets_append(parser, result, target);
13630 context_pop(parser);
13631 }
else if (token_begins_expression_p(parser->current.type)) {
13632 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13633 target = parse_target(parser, target,
true,
false);
13635 pm_multi_target_node_targets_append(parser, result, target);
13636 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13639 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
13640 pm_multi_target_node_targets_append(parser, result, rest);
13653parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13654 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13659 if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
13660 accept1(parser, PM_TOKEN_NEWLINE);
13664 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13665 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13675parse_statements(
pm_parser_t *parser, pm_context_t context, uint16_t depth) {
13678 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13681 if (context_terminator(context, &parser->current))
return NULL;
13687 context_push(parser, context);
13690 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));
13691 pm_statements_node_body_append(parser, statements, node,
true);
13695 if (parser->recovering) {
13698 if (context_terminator(context, &parser->current)) parser->recovering =
false;
13704 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13707 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13708 if (context_terminator(context, &parser->current))
break;
13718 if (context_terminator(context, &parser->current))
break;
13730 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
13731 parser_lex(parser);
13737 if (match1(parser, PM_TOKEN_EOF)) {
13738 parser->recovering =
true;
13742 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13743 if (context_terminator(context, &parser->current))
break;
13744 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13748 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
13749 parser->previous.
start = parser->previous.
end;
13750 parser->previous.
type = 0;
13754 context_pop(parser);
13756 bool last_value =
true;
13758 case PM_CONTEXT_BEGIN_ENSURE:
13759 case PM_CONTEXT_DEF_ENSURE:
13760 last_value =
false;
13765 pm_void_statements_check(parser, statements, last_value);
13776 pm_static_literal_inspect(&buffer, &parser->line_offsets, parser->start, parser->start_line, parser->encoding, duplicated);
13778 pm_diagnostic_list_append_format(
13779 &parser->metadata_arena,
13780 &parser->warning_list,
13783 PM_WARN_DUPLICATED_HASH_KEY,
13784 (
int) pm_buffer_length(&buffer),
13785 pm_buffer_value(&buffer),
13786 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line
13789 pm_buffer_cleanup(&buffer);
13798 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
true);
13800 if (duplicated != NULL) {
13801 pm_hash_key_duplicated_warn(parser, duplicated, node);
13816 for (
size_t index = 0; index < elements->
size; index++) {
13819 switch (PM_NODE_TYPE(element)) {
13820 case PM_ASSOC_NODE: {
13822 const pm_node_t *duplicated = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, key,
true);
13824 if (duplicated != NULL && PM_NODE_START(duplicated) < boundary) {
13825 pm_hash_key_duplicated_warn(parser, duplicated, key);
13830 case PM_ASSOC_SPLAT_NODE: {
13833 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13834 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, boundary);
13853 if ((previous = pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, literals, node,
false)) != NULL) {
13854 pm_diagnostic_list_append_format(
13855 &parser->metadata_arena,
13856 &parser->warning_list,
13857 PM_NODE_START(node),
13858 PM_NODE_LENGTH(node),
13859 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13860 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line,
13861 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).
line
13871 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13872 bool contains_keyword_splat =
false;
13877 switch (parser->current.type) {
13878 case PM_TOKEN_USTAR_STAR: {
13879 parser_lex(parser);
13883 if (token_begins_expression_p(parser->current.type)) {
13884 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));
13888 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13889 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, PM_NODE_START(value));
13892 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13895 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13896 contains_keyword_splat =
true;
13899 case PM_TOKEN_LABEL: {
13901 parser_lex(parser);
13903 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13904 pm_hash_key_static_literals_add(parser, literals, key);
13908 if (token_begins_expression_p(parser->current.type)) {
13909 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13911 if (parser->encoding->isupper_char(label.
start, (label.
end - 1) - label.
start)) {
13912 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13913 value = UP(pm_constant_read_node_create(parser, &constant));
13918 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13919 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13921 depth = pm_parser_local_depth(parser, &identifier);
13925 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13927 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13932 value = UP(pm_implicit_node_create(parser, value));
13935 element = UP(pm_assoc_node_create(parser, key, NULL, value));
13939 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));
13943 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13944 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13947 pm_hash_key_static_literals_add(parser, literals, key);
13950 if (!pm_symbol_node_label_p(parser, key)) {
13951 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13952 operator = parser->previous;
13955 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));
13956 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
13961 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13962 pm_hash_node_elements_append(parser->arena, (
pm_hash_node_t *) node, element);
13968 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13972 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13976 if (token_begins_expression_p(parser->current.type))
continue;
13982 return contains_keyword_splat;
13987 if (pm_symbol_node_label_p(parser, argument)) {
13991 switch (PM_NODE_TYPE(argument)) {
13992 case PM_CALL_NODE: {
13995 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13998 if (cast->
block != NULL) {
14006 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
14015 arguments->
arguments = pm_arguments_node_create(parser);
14018 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, argument);
14029 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
14048 call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE) &&
14063 switch (PM_NODE_TYPE(node)) {
14064 case PM_CALL_NODE: {
14069 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)) {
14074 if (pm_constant_path_command_call_p(parser, call)) {
14081 return pm_command_call_value_p(parser, call->
receiver);
14086 case PM_SUPER_NODE: {
14093 !(cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE));
14095 case PM_YIELD_NODE: {
14099 case PM_RESCUE_MODIFIER_NODE:
14101 case PM_DEF_NODE: {
14105 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
14108 return pm_command_call_value_p(parser, body);
14124pm_block_call_p(
const pm_node_t *node) {
14125 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
14156 if (PM_NODE_TYPE_P(node, PM_SUPER_NODE)) {
14168parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
14169 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
14174 match2(parser, terminator, PM_TOKEN_EOF) ||
14175 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14176 context_terminator(parser->current_context->context, &parser->current)
14181 bool parsed_first_argument =
false;
14182 bool parsed_bare_hash =
false;
14183 bool parsed_block_argument =
false;
14184 bool parsed_forwarding_arguments =
false;
14186 while (!match1(parser, PM_TOKEN_EOF)) {
14187 if (parsed_forwarding_arguments) {
14188 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14193 switch (parser->current.type) {
14194 case PM_TOKEN_USTAR_STAR:
14195 case PM_TOKEN_LABEL: {
14196 if (parsed_bare_hash) {
14197 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14201 argument = UP(hash);
14204 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
14206 parse_arguments_append(parser, arguments, argument);
14208 pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14209 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14210 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14212 pm_static_literals_free(&hash_keys);
14213 parsed_bare_hash =
true;
14217 case PM_TOKEN_UAMPERSAND: {
14218 parser_lex(parser);
14222 if (token_begins_expression_p(parser->current.type)) {
14223 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14225 pm_parser_scope_forwarding_block_check(parser, &
operator);
14228 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
14229 if (parsed_block_argument) {
14230 parse_arguments_append(parser, arguments, argument);
14232 arguments->
block = argument;
14235 if (match1(parser, PM_TOKEN_COMMA)) {
14236 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14239 parsed_block_argument =
true;
14242 case PM_TOKEN_USTAR: {
14243 parser_lex(parser);
14246 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14247 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14248 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
14249 if (parsed_bare_hash) {
14250 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14253 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));
14255 if (parsed_bare_hash) {
14256 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);
14259 argument = UP(pm_splat_node_create(parser, &
operator, expression));
14262 parse_arguments_append(parser, arguments, argument);
14265 case PM_TOKEN_UDOT_DOT_DOT: {
14266 if (accepts_forwarding) {
14267 parser_lex(parser);
14269 if (token_begins_expression_p(parser->current.type)) {
14274 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));
14279 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14281 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14284 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
14286 pm_parser_scope_forwarding_all_check(parser, &parser->previous);
14287 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14288 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14291 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->previous));
14292 parse_arguments_append(parser, arguments, argument);
14293 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14295 parsed_forwarding_arguments =
true;
14302 if (argument == NULL) {
14303 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));
14306 bool contains_keywords =
false;
14307 bool contains_keyword_splat =
false;
14309 if (argument_allowed_for_bare_hash(parser, argument)) {
14310 if (parsed_bare_hash) {
14311 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14320 if (pm_command_call_value_p(parser, argument) || pm_block_call_p(argument)) {
14321 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->previous.
type));
14325 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
14326 operator = parser->previous;
14330 contains_keywords =
true;
14334 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14337 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));
14338 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
14340 pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
14341 argument = UP(bare_hash);
14344 if (accept1(parser, PM_TOKEN_COMMA) && (
14345 token_begins_expression_p(parser->current.type) ||
14346 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14348 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
14351 pm_static_literals_free(&hash_keys);
14352 parsed_bare_hash =
true;
14355 parse_arguments_append(parser, arguments, argument);
14357 pm_node_flags_t node_flags = 0;
14358 if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14359 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14360 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14366 parsed_first_argument =
true;
14369 if (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_NODE) || parser->recovering)
break;
14374 bool accepted_newline =
false;
14375 if (terminator != PM_TOKEN_EOF) {
14376 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14379 if (parser->previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14383 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14386 if (accepted_newline) {
14387 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14393 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
14396 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14408 if (match1(parser, terminator)) {
14414 if (parsed_forwarding_arguments) {
14415 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14434parse_required_destructured_parameter(
pm_parser_t *parser) {
14435 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14438 pm_multi_target_node_opening_set(parser, node, &parser->previous);
14447 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14448 param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14449 pm_multi_target_node_targets_append(parser, node, param);
14450 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14454 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
14455 param = UP(parse_required_destructured_parameter(parser));
14456 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14460 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14462 value = UP(pm_required_parameter_node_create(parser, &name));
14463 if (pm_parser_parameter_name_check(parser, &name)) {
14464 pm_node_flag_set_repeated_parameter(value);
14466 pm_parser_local_add_token(parser, &name, 1);
14469 param = UP(pm_splat_node_create(parser, &star, value));
14471 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14474 param = UP(pm_required_parameter_node_create(parser, &name));
14475 if (pm_parser_parameter_name_check(parser, &name)) {
14476 pm_node_flag_set_repeated_parameter(param);
14478 pm_parser_local_add_token(parser, &name, 1);
14481 pm_multi_target_node_targets_append(parser, node, param);
14482 }
while (accept1(parser, PM_TOKEN_COMMA));
14484 accept1(parser, PM_TOKEN_NEWLINE);
14485 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14486 pm_multi_target_node_closing_set(parser, node, &parser->previous);
14496 PM_PARAMETERS_NO_CHANGE = 0,
14497 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14498 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14499 PM_PARAMETERS_ORDER_KEYWORDS,
14500 PM_PARAMETERS_ORDER_REST,
14501 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14502 PM_PARAMETERS_ORDER_OPTIONAL,
14503 PM_PARAMETERS_ORDER_NAMED,
14504 PM_PARAMETERS_ORDER_NONE,
14505} pm_parameters_order_t;
14510static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14511 [0] = PM_PARAMETERS_NO_CHANGE,
14512 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14513 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14514 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14515 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14516 [PM_TOKEN_PARENTHESIS_LEFT_GROUPING] = PM_PARAMETERS_ORDER_NAMED,
14517 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14518 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14519 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14520 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14521 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14522 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14534 pm_parameters_order_t state = parameters_ordering[token->type];
14535 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14539 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14540 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14542 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14546 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14547 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14549 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14550 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14552 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14554 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14558 if (state < *current) *current = state;
14563parse_parameters_handle_trailing_comma(
14566 pm_parameters_order_t order,
14568 bool allows_trailing_comma
14570 if (!allows_trailing_comma) {
14571 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14576 if (order >= PM_PARAMETERS_ORDER_NAMED) {
14578 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14580 if (params->
rest == NULL) {
14581 pm_parameters_node_rest_set(params, param);
14583 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14584 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14588 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14593 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
14594 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14605 pm_binding_power_t binding_power,
14606 bool uses_parentheses,
14607 bool allows_trailing_comma,
14608 bool allows_forwarding_parameters,
14609 bool accepts_blocks_in_defaults,
14611 pm_diagnostic_id_t diag_id_forwarding,
14614 pm_do_loop_stack_push(parser,
false);
14617 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14620 bool parsing =
true;
14622 switch (parser->current.type) {
14623 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
14624 update_parameter_state(parser, &parser->current, &order);
14625 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
14627 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14628 pm_parameters_node_requireds_append(parser->arena, params, param);
14630 pm_parameters_node_posts_append(parser->arena, params, param);
14634 case PM_TOKEN_UAMPERSAND:
14635 case PM_TOKEN_AMPERSAND: {
14636 update_parameter_state(parser, &parser->current, &order);
14637 parser_lex(parser);
14642 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14643 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->previous);
14647 bool repeated =
false;
14648 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14649 name = parser->previous;
14650 repeated = pm_parser_parameter_name_check(parser, &name);
14651 pm_parser_local_add_token(parser, &name, 1);
14653 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
14656 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
14658 pm_node_flag_set_repeated_parameter(param);
14662 if (params->
block == NULL) {
14663 pm_parameters_node_block_set(params, param);
14665 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
14666 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14671 case PM_TOKEN_UDOT_DOT_DOT: {
14672 if (!allows_forwarding_parameters) {
14673 pm_parser_err_current(parser, diag_id_forwarding);
14676 bool succeeded = update_parameter_state(parser, &parser->current, &order);
14677 parser_lex(parser);
14679 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
14686 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, keyword_rest)));
14687 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14691 pm_parameters_node_keyword_rest_set(params, UP(param));
14694 case PM_TOKEN_CLASS_VARIABLE:
14695 case PM_TOKEN_IDENTIFIER:
14696 case PM_TOKEN_CONSTANT:
14697 case PM_TOKEN_INSTANCE_VARIABLE:
14698 case PM_TOKEN_GLOBAL_VARIABLE:
14699 case PM_TOKEN_METHOD_NAME: {
14700 parser_lex(parser);
14701 switch (parser->previous.
type) {
14702 case PM_TOKEN_CONSTANT:
14703 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14705 case PM_TOKEN_INSTANCE_VARIABLE:
14706 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14708 case PM_TOKEN_GLOBAL_VARIABLE:
14709 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14711 case PM_TOKEN_CLASS_VARIABLE:
14712 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14714 case PM_TOKEN_METHOD_NAME:
14715 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14720 if (parser->current.type == PM_TOKEN_EQUAL) {
14721 update_parameter_state(parser, &parser->current, &order);
14723 update_parameter_state(parser, &parser->previous, &order);
14727 bool repeated = pm_parser_parameter_name_check(parser, &name);
14728 pm_parser_local_add_token(parser, &name, 1);
14730 if (match1(parser, PM_TOKEN_EQUAL)) {
14732 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14733 parser_lex(parser);
14736 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14738 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14739 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14740 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14745 pm_node_flag_set_repeated_parameter(UP(param));
14747 pm_parameters_node_optionals_append(parser->arena, params, param);
14752 if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14753 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
14756 context_pop(parser);
14761 if (parser->recovering) {
14765 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14768 pm_node_flag_set_repeated_parameter(UP(param));
14770 pm_parameters_node_requireds_append(parser->arena, params, UP(param));
14774 pm_node_flag_set_repeated_parameter(UP(param));
14776 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14781 case PM_TOKEN_LABEL: {
14782 if (!uses_parentheses && !in_block) parser->in_keyword_arg =
true;
14783 update_parameter_state(parser, &parser->current, &order);
14785 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14786 parser_lex(parser);
14792 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)) {
14793 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14794 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14795 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14798 bool repeated = pm_parser_parameter_name_check(parser, &local);
14799 pm_parser_local_add_token(parser, &local, 1);
14801 switch (parser->current.type) {
14802 case PM_TOKEN_COMMA:
14803 case PM_TOKEN_PARENTHESIS_RIGHT:
14804 case PM_TOKEN_PIPE: {
14805 context_pop(parser);
14807 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14809 pm_node_flag_set_repeated_parameter(param);
14812 pm_parameters_node_keywords_append(parser->arena, params, param);
14815 case PM_TOKEN_SEMICOLON:
14816 case PM_TOKEN_NEWLINE: {
14817 context_pop(parser);
14819 if (uses_parentheses) {
14824 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14826 pm_node_flag_set_repeated_parameter(param);
14829 pm_parameters_node_keywords_append(parser->arena, params, param);
14835 if (token_begins_expression_p(parser->current.type)) {
14837 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14839 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14840 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));
14841 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14843 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14844 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
14847 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14850 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14854 pm_node_flag_set_repeated_parameter(param);
14857 context_pop(parser);
14858 pm_parameters_node_keywords_append(parser->arena, params, param);
14863 if (parser->recovering) {
14870 parser->in_keyword_arg =
false;
14873 case PM_TOKEN_USTAR:
14874 case PM_TOKEN_STAR: {
14875 update_parameter_state(parser, &parser->current, &order);
14876 parser_lex(parser);
14880 bool repeated =
false;
14882 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14883 name = parser->previous;
14884 repeated = pm_parser_parameter_name_check(parser, &name);
14885 pm_parser_local_add_token(parser, &name, 1);
14887 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
14890 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14892 pm_node_flag_set_repeated_parameter(param);
14895 if (params->
rest == NULL) {
14896 pm_parameters_node_rest_set(params, param);
14898 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14899 pm_parameters_node_posts_append(parser->arena, params, param);
14904 case PM_TOKEN_STAR_STAR:
14905 case PM_TOKEN_USTAR_STAR: {
14906 pm_parameters_order_t previous_order = order;
14907 update_parameter_state(parser, &parser->current, &order);
14908 parser_lex(parser);
14913 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14914 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14915 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14918 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
14922 bool repeated =
false;
14923 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14924 name = parser->previous;
14925 repeated = pm_parser_parameter_name_check(parser, &name);
14926 pm_parser_local_add_token(parser, &name, 1);
14928 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
14931 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
14933 pm_node_flag_set_repeated_parameter(param);
14938 pm_parameters_node_keyword_rest_set(params, param);
14940 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14941 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14947 if (parser->previous.
type == PM_TOKEN_COMMA) {
14948 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
14958 if (!parsing)
break;
14960 bool accepted_newline =
false;
14961 if (uses_parentheses) {
14962 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14965 if (accept1(parser, PM_TOKEN_COMMA)) {
14968 if (accepted_newline) {
14969 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14977 pm_do_loop_stack_pop(parser);
14980 if (PM_NODE_START(params) == PM_NODE_END(params)) {
14993 if (parser->heredoc_end == NULL) {
14997 return parser->line_offsets.
size - 1;
15003 return (
size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
15012token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
15013 const uint8_t *cursor = parser->start + parser->line_offsets.
offsets[newline_index];
15014 const uint8_t *end = token->start;
15018 newline_index == 0 &&
15019 parser->start[0] == 0xef &&
15020 parser->start[1] == 0xbb &&
15021 parser->start[2] == 0xbf
15024 int64_t column = 0;
15025 for (; cursor < end; cursor++) {
15028 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15035 if (break_on_non_space)
return -1;
15048parser_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) {
15050 if (!parser->warn_mismatched_indentation)
return;
15053 size_t closing_newline_index = token_newline_index(parser);
15054 if (opening_newline_index == closing_newline_index)
return;
15059 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15060 if (!if_after_else && (opening_column == -1))
return;
15064 pm_token_t *closing_token = &parser->current;
15067 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15068 if ((closing_column == -1) || (opening_column == closing_column))
return;
15072 if (allow_indent && (closing_column > opening_column))
return;
15075 PM_PARSER_WARN_FORMAT(
15077 PM_TOKEN_START(parser, closing_token),
15078 PM_TOKEN_LENGTH(closing_token),
15079 PM_WARN_INDENTATION_MISMATCH,
15080 (
int) (closing_token->
end - closing_token->
start),
15081 (
const char *) closing_token->
start,
15082 (
int) (opening_token->
end - opening_token->
start),
15083 (
const char *) opening_token->
start,
15084 ((int32_t) opening_newline_index) + parser->start_line
15089 PM_RESCUES_BEGIN = 1,
15096} pm_rescues_type_t;
15106 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15107 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15108 parser_lex(parser);
15110 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
15112 switch (parser->current.type) {
15113 case PM_TOKEN_EQUAL_GREATER: {
15117 parser_lex(parser);
15118 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15120 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15121 reference = parse_target(parser, reference,
false,
false);
15123 pm_rescue_node_reference_set(rescue, reference);
15126 case PM_TOKEN_NEWLINE:
15127 case PM_TOKEN_SEMICOLON:
15128 case PM_TOKEN_KEYWORD_THEN:
15133 if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
15138 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15139 pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
15143 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15147 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15148 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15150 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15151 reference = parse_target(parser, reference,
false,
false);
15153 pm_rescue_node_reference_set(rescue, reference);
15156 }
while (accept1(parser, PM_TOKEN_COMMA));
15161 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15162 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15166 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15170 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15171 pm_accepts_block_stack_push(parser,
true);
15172 pm_context_t context;
15175 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_RESCUE;
break;
15176 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_RESCUE;
break;
15177 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_RESCUE;
break;
15178 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_RESCUE;
break;
15179 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE;
break;
15180 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE;
break;
15181 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE;
break;
15182 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15186 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15188 pm_accepts_block_stack_pop(parser);
15189 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15192 if (current == NULL) {
15193 pm_begin_node_rescue_clause_set(parent_node, rescue);
15195 pm_rescue_node_subsequent_set(current, rescue);
15204 if (current != NULL) {
15207 while (clause != NULL) {
15208 PM_NODE_LENGTH_SET_NODE(clause, current);
15214 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15215 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15216 opening_newline_index = token_newline_index(parser);
15218 else_keyword = parser->current;
15219 opening = &else_keyword;
15221 parser_lex(parser);
15222 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15225 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15226 pm_accepts_block_stack_push(parser,
true);
15227 pm_context_t context;
15230 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ELSE;
break;
15231 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ELSE;
break;
15232 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ELSE;
break;
15233 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ELSE;
break;
15234 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE;
break;
15235 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE;
break;
15236 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE;
break;
15237 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_ELSE;
break;
15240 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15241 pm_accepts_block_stack_pop(parser);
15243 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15246 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
15247 pm_begin_node_else_clause_set(parent_node, else_clause);
15251 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
15254 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15255 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15256 pm_token_t ensure_keyword = parser->current;
15258 parser_lex(parser);
15259 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15262 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15263 pm_accepts_block_stack_push(parser,
true);
15264 pm_context_t context;
15267 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ENSURE;
break;
15268 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ENSURE;
break;
15269 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ENSURE;
break;
15270 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ENSURE;
break;
15271 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE;
break;
15272 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE;
break;
15273 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE;
break;
15274 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15277 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15278 pm_accepts_block_stack_pop(parser);
15280 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15283 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
15284 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15287 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15288 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15289 pm_begin_node_end_keyword_set(parser, parent_node, &parser->current);
15292 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
15302 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
15303 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15306 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
15315parse_block_parameters(
15317 bool allows_trailing_comma,
15319 bool is_lambda_literal,
15320 bool accepts_blocks_in_defaults,
15324 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15325 if (!is_lambda_literal) {
15326 context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
15328 parameters = parse_parameters(
15330 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15332 allows_trailing_comma,
15334 accepts_blocks_in_defaults,
15336 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
15337 (uint16_t) (depth + 1)
15339 if (!is_lambda_literal) {
15340 context_pop(parser);
15345 if (opening != NULL) {
15346 accept1(parser, PM_TOKEN_NEWLINE);
15348 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15350 switch (parser->current.type) {
15351 case PM_TOKEN_CONSTANT:
15352 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15353 parser_lex(parser);
15355 case PM_TOKEN_INSTANCE_VARIABLE:
15356 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15357 parser_lex(parser);
15359 case PM_TOKEN_GLOBAL_VARIABLE:
15360 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15361 parser_lex(parser);
15363 case PM_TOKEN_CLASS_VARIABLE:
15364 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15365 parser_lex(parser);
15368 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15372 bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
15373 pm_parser_local_add_token(parser, &parser->previous, 1);
15376 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
15378 pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
15379 }
while (accept1(parser, PM_TOKEN_COMMA));
15383 return block_parameters;
15391outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15392 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15393 if (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15404static const char *
const pm_numbered_parameter_names[] = {
15405 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15415 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
15419 if (parameters != NULL) {
15421 if (implicit_parameters->
size > 0) {
15424 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15425 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15426 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15427 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15429 assert(
false &&
"unreachable");
15438 if (implicit_parameters->
size == 0) {
15445 uint8_t numbered_parameter = 0;
15446 bool it_parameter =
false;
15448 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15451 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15452 if (it_parameter) {
15453 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15454 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15455 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15456 }
else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
15457 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15458 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
15459 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->
location.
start + 1] -
'0'));
15461 assert(
false &&
"unreachable");
15463 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15464 if (numbered_parameter > 0) {
15465 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15467 it_parameter =
true;
15472 if (numbered_parameter > 0) {
15475 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15476 scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15478 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
15481 if (it_parameter) {
15482 return UP(pm_it_parameters_node_create(parser, opening, closing));
15492parse_block(
pm_parser_t *parser, uint16_t depth) {
15494 accept1(parser, PM_TOKEN_NEWLINE);
15500 bool do_block = opening.
type != PM_TOKEN_BRACE_LEFT && opening.
type != PM_TOKEN_BRACE_LEFT_ARGUMENT;
15501 if (do_block) pm_accepts_block_stack_push(parser,
true);
15502 pm_parser_scope_push(parser,
false);
15506 if (accept1(parser, PM_TOKEN_PIPE)) {
15507 pm_token_t block_parameters_opening = parser->previous;
15508 if (match1(parser, PM_TOKEN_PIPE)) {
15509 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15510 parser->command_start =
true;
15511 parser_lex(parser);
15513 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15514 accept1(parser, PM_TOKEN_NEWLINE);
15515 parser->command_start =
true;
15516 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15519 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
15522 accept1(parser, PM_TOKEN_NEWLINE);
15526 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15527 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
15530 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
15532 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15533 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15534 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)));
15537 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15538 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15539 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
15545 pm_accepts_block_stack_pop(parser);
15546 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
15550 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
15551 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
15553 pm_parser_scope_pop(parser);
15554 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
15569parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool full_arguments, uint8_t flags, uint16_t depth) {
15574 !token_begins_expression_p(parser->current.type) &&
15575 !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)
15580 bool found =
false;
15581 bool parsed_command_args =
false;
15583 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15585 arguments->
opening_loc = TOK2LOC(parser, &parser->previous);
15587 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15588 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15590 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
15598 if (!full_arguments && parser->previous.
type == PM_TOKEN_COMMA) {
15599 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15602 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15603 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
15604 parser->previous.
start = parser->previous.
end;
15605 parser->previous.
type = 0;
15608 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15610 }
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)) {
15612 parsed_command_args =
true;
15622 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);
15623 if (lookahead_delimiter) pm_accepts_block_stack_pop(parser);
15624 pm_accepts_block_stack_push(parser,
false);
15625 if (lookahead_delimiter) pm_accepts_block_stack_push(parser,
true);
15630 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
15635 if (parser->previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15636 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15644 bool lookahead_brace = match2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT);
15645 if (lookahead_brace) pm_accepts_block_stack_pop(parser);
15646 pm_accepts_block_stack_pop(parser);
15647 if (lookahead_brace) pm_accepts_block_stack_push(parser,
true);
15653 if (full_arguments) {
15656 if (accept2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT)) {
15658 block = parse_block(parser, (uint16_t) (depth + 1));
15659 pm_arguments_validate_block(parser, arguments, block);
15660 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15662 block = parse_block(parser, (uint16_t) (depth + 1));
15663 }
else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
15665 block = parse_block(parser, (uint16_t) (depth + 1));
15668 if (block != NULL) {
15670 arguments->
block = UP(block);
15672 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
15674 if (arguments->
block != NULL) {
15676 arguments->
arguments = pm_arguments_node_create(parser);
15678 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, arguments->
block);
15680 arguments->
block = UP(block);
15694 bool in_sclass =
false;
15695 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15696 switch (context_node->context) {
15697 case PM_CONTEXT_BEGIN_ELSE:
15698 case PM_CONTEXT_BEGIN_ENSURE:
15699 case PM_CONTEXT_BEGIN_RESCUE:
15700 case PM_CONTEXT_BEGIN:
15701 case PM_CONTEXT_CASE_IN:
15702 case PM_CONTEXT_CASE_WHEN:
15703 case PM_CONTEXT_DEFAULT_PARAMS:
15704 case PM_CONTEXT_DEFINED:
15705 case PM_CONTEXT_ELSE:
15706 case PM_CONTEXT_ELSIF:
15707 case PM_CONTEXT_EMBEXPR:
15708 case PM_CONTEXT_FOR_INDEX:
15709 case PM_CONTEXT_FOR:
15710 case PM_CONTEXT_IF:
15711 case PM_CONTEXT_LOOP_PREDICATE:
15712 case PM_CONTEXT_MAIN:
15713 case PM_CONTEXT_MULTI_TARGET:
15714 case PM_CONTEXT_PARENS:
15715 case PM_CONTEXT_POSTEXE:
15716 case PM_CONTEXT_PREDICATE:
15717 case PM_CONTEXT_PREEXE:
15718 case PM_CONTEXT_RESCUE_MODIFIER:
15719 case PM_CONTEXT_TERNARY:
15720 case PM_CONTEXT_UNLESS:
15721 case PM_CONTEXT_UNTIL:
15722 case PM_CONTEXT_WHILE:
15726 case PM_CONTEXT_SCLASS_ELSE:
15727 case PM_CONTEXT_SCLASS_ENSURE:
15728 case PM_CONTEXT_SCLASS_RESCUE:
15729 case PM_CONTEXT_SCLASS:
15732 case PM_CONTEXT_CLASS_ELSE:
15733 case PM_CONTEXT_CLASS_ENSURE:
15734 case PM_CONTEXT_CLASS_RESCUE:
15735 case PM_CONTEXT_CLASS:
15736 case PM_CONTEXT_MODULE_ELSE:
15737 case PM_CONTEXT_MODULE_ENSURE:
15738 case PM_CONTEXT_MODULE_RESCUE:
15739 case PM_CONTEXT_MODULE:
15741 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15743 case PM_CONTEXT_BLOCK_BRACES:
15744 case PM_CONTEXT_BLOCK_ELSE:
15745 case PM_CONTEXT_BLOCK_ENSURE:
15746 case PM_CONTEXT_BLOCK_KEYWORDS:
15747 case PM_CONTEXT_BLOCK_RESCUE:
15748 case PM_CONTEXT_BLOCK_PARAMETERS:
15749 case PM_CONTEXT_DEF_ELSE:
15750 case PM_CONTEXT_DEF_ENSURE:
15751 case PM_CONTEXT_DEF_PARAMS:
15752 case PM_CONTEXT_DEF_RESCUE:
15753 case PM_CONTEXT_DEF:
15754 case PM_CONTEXT_LAMBDA_BRACES:
15755 case PM_CONTEXT_LAMBDA_DO_END:
15756 case PM_CONTEXT_LAMBDA_ELSE:
15757 case PM_CONTEXT_LAMBDA_ENSURE:
15758 case PM_CONTEXT_LAMBDA_RESCUE:
15762 case PM_CONTEXT_NONE:
15763 case PM_CONTEXT_MAXIMUM:
15765 assert(
false &&
"unreachable");
15769 if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
15770 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15780 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15781 switch (context_node->context) {
15782 case PM_CONTEXT_BLOCK_BRACES:
15783 case PM_CONTEXT_BLOCK_KEYWORDS:
15784 case PM_CONTEXT_BLOCK_ELSE:
15785 case PM_CONTEXT_BLOCK_ENSURE:
15786 case PM_CONTEXT_BLOCK_PARAMETERS:
15787 case PM_CONTEXT_BLOCK_RESCUE:
15788 case PM_CONTEXT_DEFINED:
15789 case PM_CONTEXT_FOR:
15790 case PM_CONTEXT_LAMBDA_BRACES:
15791 case PM_CONTEXT_LAMBDA_DO_END:
15792 case PM_CONTEXT_LAMBDA_ELSE:
15793 case PM_CONTEXT_LAMBDA_ENSURE:
15794 case PM_CONTEXT_LAMBDA_RESCUE:
15795 case PM_CONTEXT_LOOP_PREDICATE:
15796 case PM_CONTEXT_UNTIL:
15797 case PM_CONTEXT_WHILE:
15801 case PM_CONTEXT_POSTEXE:
15803 if (context_node->context == PM_CONTEXT_POSTEXE) {
15804 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
15809 case PM_CONTEXT_DEF:
15810 case PM_CONTEXT_DEF_PARAMS:
15811 case PM_CONTEXT_DEF_ELSE:
15812 case PM_CONTEXT_DEF_ENSURE:
15813 case PM_CONTEXT_DEF_RESCUE:
15814 case PM_CONTEXT_MAIN:
15815 case PM_CONTEXT_PREEXE:
15816 case PM_CONTEXT_SCLASS:
15817 case PM_CONTEXT_SCLASS_ELSE:
15818 case PM_CONTEXT_SCLASS_ENSURE:
15819 case PM_CONTEXT_SCLASS_RESCUE:
15829 assert(parser->current_block_exits != NULL);
15830 pm_node_list_append(parser->arena, parser->current_block_exits, node);
15832 case PM_CONTEXT_BEGIN_ELSE:
15833 case PM_CONTEXT_BEGIN_ENSURE:
15834 case PM_CONTEXT_BEGIN_RESCUE:
15835 case PM_CONTEXT_BEGIN:
15836 case PM_CONTEXT_CASE_IN:
15837 case PM_CONTEXT_CASE_WHEN:
15838 case PM_CONTEXT_CLASS_ELSE:
15839 case PM_CONTEXT_CLASS_ENSURE:
15840 case PM_CONTEXT_CLASS_RESCUE:
15841 case PM_CONTEXT_CLASS:
15842 case PM_CONTEXT_DEFAULT_PARAMS:
15843 case PM_CONTEXT_ELSE:
15844 case PM_CONTEXT_ELSIF:
15845 case PM_CONTEXT_EMBEXPR:
15846 case PM_CONTEXT_FOR_INDEX:
15847 case PM_CONTEXT_IF:
15848 case PM_CONTEXT_MODULE_ELSE:
15849 case PM_CONTEXT_MODULE_ENSURE:
15850 case PM_CONTEXT_MODULE_RESCUE:
15851 case PM_CONTEXT_MODULE:
15852 case PM_CONTEXT_MULTI_TARGET:
15853 case PM_CONTEXT_PARENS:
15854 case PM_CONTEXT_PREDICATE:
15855 case PM_CONTEXT_RESCUE_MODIFIER:
15856 case PM_CONTEXT_TERNARY:
15857 case PM_CONTEXT_UNLESS:
15861 case PM_CONTEXT_NONE:
15862 case PM_CONTEXT_MAXIMUM:
15864 assert(
false &&
"unreachable");
15876 pm_node_list_t *previous_block_exits = parser->current_block_exits;
15877 parser->current_block_exits = current_block_exits;
15878 return previous_block_exits;
15892 switch (PM_NODE_TYPE(block_exit)) {
15893 case PM_BREAK_NODE:
type =
"break";
break;
15894 case PM_NEXT_NODE:
type =
"next";
break;
15895 case PM_REDO_NODE:
type =
"redo";
break;
15896 default: assert(
false &&
"unreachable");
type =
"";
break;
15899 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15902 parser->current_block_exits = previous_block_exits;
15911 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15915 parser->current_block_exits = previous_block_exits;
15916 }
else if (previous_block_exits != NULL) {
15922 pm_node_list_concat(parser->arena, previous_block_exits, parser->current_block_exits);
15923 parser->current_block_exits = previous_block_exits;
15928 flush_block_exits(parser, previous_block_exits);
15933parse_predicate(
pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context,
pm_token_t *then_keyword, uint16_t depth) {
15934 context_push(parser, PM_CONTEXT_PREDICATE);
15935 pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
15936 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));
15939 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15941 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15942 predicate_closed =
true;
15943 *then_keyword = parser->previous;
15946 if (!predicate_closed) {
15947 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15950 context_pop(parser);
15955parse_conditional(
pm_parser_t *parser, pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15957 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15962 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, context, &then_keyword, (uint16_t) (depth + 1));
15965 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15966 pm_accepts_block_stack_push(parser,
true);
15967 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15968 pm_accepts_block_stack_pop(parser);
15969 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15975 case PM_CONTEXT_IF:
15976 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
15978 case PM_CONTEXT_UNLESS:
15979 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
15982 assert(
false &&
"unreachable");
15990 if (context == PM_CONTEXT_IF) {
15991 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15992 if (parser_end_of_line_p(parser)) {
15993 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
15996 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15998 parser_lex(parser);
16000 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
16001 pm_accepts_block_stack_push(parser,
true);
16003 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
16004 pm_accepts_block_stack_pop(parser);
16005 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16007 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
16013 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
16014 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16015 opening_newline_index = token_newline_index(parser);
16017 parser_lex(parser);
16020 pm_accepts_block_stack_push(parser,
true);
16021 pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
16022 pm_accepts_block_stack_pop(parser);
16024 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16025 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
16026 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
16028 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
16031 case PM_CONTEXT_IF:
16032 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
16034 case PM_CONTEXT_UNLESS:
16038 assert(
false &&
"unreachable");
16042 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
16043 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
16048 case PM_CONTEXT_IF: {
16050 bool recursing =
true;
16052 while (recursing) {
16053 switch (PM_NODE_TYPE(current)) {
16055 pm_if_node_end_keyword_loc_set(parser, (
pm_if_node_t *) current, &parser->previous);
16057 recursing = current != NULL;
16060 pm_else_node_end_keyword_loc_set(parser, (
pm_else_node_t *) current, &parser->previous);
16071 case PM_CONTEXT_UNLESS:
16072 pm_unless_node_end_keyword_loc_set(parser, (
pm_unless_node_t *) parent, &parser->previous);
16075 assert(
false &&
"unreachable");
16079 pop_block_exits(parser, previous_block_exits);
16087#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16088 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16089 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16090 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: \
16091 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16092 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16093 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16094 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16095 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16096 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16097 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16103#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16104 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16105 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16106 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16107 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16108 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16109 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16110 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16117#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16118 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16119 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16120 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_XSTRING_BEGIN: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16121 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16122 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16123 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16124 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16125 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16131#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16132 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16133 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16134 case PM_TOKEN_CLASS_VARIABLE
16140#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16141 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16142 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16143 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16147PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16155 if (explicit_encoding != NULL) {
16156 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
16159 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16160 }
else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
16165 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16176parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16177 switch (parser->current.type) {
16184 case PM_TOKEN_STRING_CONTENT: {
16185 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16186 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
16188 parser_lex(parser);
16197 case PM_TOKEN_EMBEXPR_BEGIN: {
16200 parser->explicit_encoding = NULL;
16202 pm_lex_state_t state = parser->lex_state;
16203 int brace_nesting = parser->brace_nesting;
16205 parser->brace_nesting = 0;
16206 lex_state_set(parser, PM_LEX_STATE_BEG);
16207 parser_lex(parser);
16212 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
16213 statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
16216 parser->brace_nesting = brace_nesting;
16217 lex_state_set(parser, state);
16218 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16223 if (statements != NULL && statements->
body.
size == 1) {
16224 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16227 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
16236 case PM_TOKEN_EMBVAR: {
16239 parser->explicit_encoding = NULL;
16241 lex_state_set(parser, PM_LEX_STATE_BEG);
16242 parser_lex(parser);
16247 switch (parser->current.type) {
16250 case PM_TOKEN_BACK_REFERENCE:
16251 parser_lex(parser);
16252 variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
16256 case PM_TOKEN_NUMBERED_REFERENCE:
16257 parser_lex(parser);
16258 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16262 case PM_TOKEN_GLOBAL_VARIABLE:
16263 parser_lex(parser);
16264 variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
16268 case PM_TOKEN_INSTANCE_VARIABLE:
16269 parser_lex(parser);
16270 variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
16274 case PM_TOKEN_CLASS_VARIABLE:
16275 parser_lex(parser);
16276 variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
16282 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16283 variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16287 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
16290 parser_lex(parser);
16291 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16301static const uint8_t *
16302parse_operator_symbol_name(
const pm_token_t *name) {
16303 switch (name->
type) {
16304 case PM_TOKEN_TILDE:
16305 case PM_TOKEN_BANG:
16306 if (name->
end[-1] ==
'@')
return name->
end - 1;
16315 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
16316 const uint8_t *end = parse_operator_symbol_name(&parser->current);
16318 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16319 parser_lex(parser);
16321 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, end);
16322 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16334 const pm_token_t opening = parser->previous;
16336 if (lex_mode->mode != PM_LEX_STRING) {
16337 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16339 switch (parser->current.type) {
16340 case PM_CASE_OPERATOR:
16341 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16342 case PM_TOKEN_IDENTIFIER:
16343 case PM_TOKEN_CONSTANT:
16344 case PM_TOKEN_INSTANCE_VARIABLE:
16345 case PM_TOKEN_METHOD_NAME:
16346 case PM_TOKEN_CLASS_VARIABLE:
16347 case PM_TOKEN_GLOBAL_VARIABLE:
16348 case PM_TOKEN_NUMBERED_REFERENCE:
16349 case PM_TOKEN_BACK_REFERENCE:
16350 case PM_CASE_KEYWORD:
16351 parser_lex(parser);
16354 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16358 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
16359 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16360 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16365 if (lex_mode->as.string.interpolation) {
16367 if (match1(parser, PM_TOKEN_STRING_END)) {
16368 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16369 parser_lex(parser);
16371 .
type = PM_TOKEN_STRING_CONTENT,
16372 .start = parser->previous.
start,
16373 .end = parser->previous.
start
16376 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
16380 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16384 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16385 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16386 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16388 return UP(pm_string_node_to_symbol_node(parser, (
pm_string_node_t *) part, &opening, &parser->previous));
16392 if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16394 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16395 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16396 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16400 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16401 if (match1(parser, PM_TOKEN_EOF)) {
16402 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16404 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16407 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16414 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16415 content = parser->current;
16416 unescaped = parser->current_string;
16417 parser_lex(parser);
16428 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16430 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16431 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16433 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
16434 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16436 if (next_state != PM_LEX_STATE_NONE) {
16437 lex_state_set(parser, next_state);
16440 parser_lex(parser);
16441 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16443 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16447 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.
end, .end = parser->previous.
end };
16448 pm_string_shared_init(&unescaped, content.
start, content.
end);
16451 if (next_state != PM_LEX_STATE_NONE) {
16452 lex_state_set(parser, next_state);
16455 if (match1(parser, PM_TOKEN_EOF)) {
16456 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16458 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16461 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
false)));
16469parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16470 switch (parser->current.type) {
16471 case PM_CASE_OPERATOR:
16472 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
16473 case PM_CASE_KEYWORD:
16474 case PM_TOKEN_CONSTANT:
16475 case PM_TOKEN_IDENTIFIER:
16476 case PM_TOKEN_METHOD_NAME: {
16477 parser_lex(parser);
16479 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16480 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16481 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16485 case PM_TOKEN_SYMBOL_BEGIN: {
16487 parser_lex(parser);
16489 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16492 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16493 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16504parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16505 switch (parser->current.type) {
16506 case PM_CASE_OPERATOR:
16507 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16508 case PM_CASE_KEYWORD:
16509 case PM_TOKEN_CONSTANT:
16510 case PM_TOKEN_IDENTIFIER:
16511 case PM_TOKEN_METHOD_NAME: {
16512 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16513 parser_lex(parser);
16515 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16516 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16517 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16521 case PM_TOKEN_SYMBOL_BEGIN: {
16523 parser_lex(parser);
16525 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16527 case PM_TOKEN_BACK_REFERENCE:
16528 parser_lex(parser);
16529 return UP(pm_back_reference_read_node_create(parser, &parser->previous));
16530 case PM_TOKEN_NUMBERED_REFERENCE:
16531 parser_lex(parser);
16532 return UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16533 case PM_TOKEN_GLOBAL_VARIABLE:
16534 parser_lex(parser);
16535 return UP(pm_global_variable_read_node_create(parser, &parser->previous));
16537 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16538 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16548 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
16550 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
16552 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16553 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth,
false));
16556 pm_scope_t *current_scope = parser->current_scope;
16557 if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16558 if (is_numbered_param) {
16563 uint8_t maximum = (uint8_t) (parser->previous.
start[1] -
'0');
16564 for (uint8_t number = 1; number <= maximum; number++) {
16565 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16568 if (!match1(parser, PM_TOKEN_EQUAL)) {
16569 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
16572 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0,
false));
16573 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16576 }
else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.
start, parser->previous.
end)) {
16577 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16578 pm_node_list_append(parser->arena, ¤t_scope->implicit_parameters, node);
16592 pm_node_flags_t flags = 0;
16594 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.
end[-1] !=
'!') && (parser->previous.
end[-1] !=
'?')) {
16595 pm_node_t *node = parse_variable(parser);
16596 if (node != NULL)
return node;
16597 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16600 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
16601 pm_node_flag_set(UP(node), flags);
16612parse_method_definition_name(
pm_parser_t *parser) {
16613 switch (parser->current.type) {
16614 case PM_CASE_KEYWORD:
16615 case PM_TOKEN_CONSTANT:
16616 case PM_TOKEN_METHOD_NAME:
16617 parser_lex(parser);
16618 return parser->previous;
16619 case PM_TOKEN_IDENTIFIER:
16620 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
16621 parser_lex(parser);
16622 return parser->previous;
16623 case PM_CASE_OPERATOR:
16624 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16625 parser_lex(parser);
16626 return parser->previous;
16628 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
16629 return (
pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end };
16640 if (string->
type != PM_STRING_OWNED) {
16641 size_t length = pm_string_length(
string);
16642 writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(
string), length,
PRISM_ALIGNOF(uint8_t));
16643 pm_string_constant_init(
string, (
const char *) writable, length);
16645 writable = (uint8_t *) string->
source;
16651 size_t dest_length = pm_string_length(
string);
16652 const uint8_t *source_cursor = writable;
16653 const uint8_t *source_end = source_cursor + dest_length;
16658 size_t trimmed_whitespace = 0;
16664 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16665 if (*source_cursor ==
'\t') {
16666 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16667 if (trimmed_whitespace > common_whitespace)
break;
16669 trimmed_whitespace++;
16676 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
16677 string->length = dest_length;
16687 const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->
content_loc);
16688 return pm_memchr(cursor,
'\\', string_node->
content_loc.
length, parser->encoding_changed, parser->encoding) == NULL;
16700 bool dedent_next =
true;
16704 size_t write_index = 0;
16711 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16712 nodes->
nodes[write_index++] = node;
16713 dedent_next =
false;
16719 parse_heredoc_dedent_string(parser->arena, &string_node->
unescaped, common_whitespace);
16722 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16724 nodes->
nodes[write_index++] = node;
16728 dedent_next =
true;
16731 nodes->
size = write_index;
16738parse_strings_empty_content(
const uint8_t *location) {
16739 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16747 assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
16748 bool concating =
false;
16750 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16756 assert(lex_mode->mode == PM_LEX_STRING);
16757 bool lex_interpolation = lex_mode->as.string.interpolation;
16758 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
16761 parser_lex(parser);
16763 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16764 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16768 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
16769 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->previous);
16773 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16777 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
16778 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
start);
16781 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16782 }
else if (!lex_interpolation) {
16788 if (match1(parser, PM_TOKEN_EOF)) {
16789 unescaped = PM_STRING_EMPTY;
16790 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
16792 unescaped = parser->current_string;
16793 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16794 content = parser->previous;
16808 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16810 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16811 pm_node_list_append(parser->arena, &parts, part);
16814 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16815 pm_node_list_append(parser->arena, &parts, part);
16816 parser_lex(parser);
16817 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16819 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16820 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16821 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16822 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
true)));
16823 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16824 }
else if (match1(parser, PM_TOKEN_EOF)) {
16825 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16826 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16827 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16828 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16830 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.
type));
16831 parser->previous.
start = parser->previous.
end;
16832 parser->previous.
type = 0;
16833 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16835 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16842 const pm_encoding_t *explicit_encoding = parser->explicit_encoding;
16843 parser_lex(parser);
16845 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16846 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16847 pm_node_flag_set(node, parse_unescaped_encoding(parser, explicit_encoding));
16853 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16854 const uint8_t *location = parser->previous.
end;
16855 if (location > parser->start && location[-1] ==
'\n') location--;
16856 pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
16858 parser->previous.
start = parser->previous.
end;
16859 parser->previous.
type = 0;
16861 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16862 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, explicit_encoding, &content, &unescaped,
true)));
16863 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16868 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
16869 pm_node_flag_set(part, parse_unescaped_encoding(parser, explicit_encoding));
16870 pm_node_list_append(parser->arena, &parts, part);
16872 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16873 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16874 pm_node_list_append(parser->arena, &parts, part);
16878 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16879 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16880 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16881 }
else if (match1(parser, PM_TOKEN_EOF)) {
16882 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16883 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16885 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16886 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16896 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16897 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16898 pm_node_list_append(parser->arena, &parts, part);
16902 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16903 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
16904 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16905 }
else if (match1(parser, PM_TOKEN_EOF)) {
16906 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16907 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
16909 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16910 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16914 if (current == NULL) {
16918 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16929 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16930 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16936 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16937 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16942 pm_interpolated_string_node_append(parser, container, current);
16943 current = UP(container);
16953#define PM_PARSE_PATTERN_SINGLE 0
16954#define PM_PARSE_PATTERN_TOP 1
16955#define PM_PARSE_PATTERN_MULTI 2
16968 if (peek_at(parser, parser->start + location->
start) ==
'_')
return;
16970 if (!pm_constant_id_set_insert(parser->arena, captures, capture)) {
16971 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16982 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16984 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16985 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
16991 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16999 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
17000 opening = parser->previous;
17001 accept1(parser, PM_TOKEN_NEWLINE);
17003 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17004 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17005 accept1(parser, PM_TOKEN_NEWLINE);
17006 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17009 closing = parser->previous;
17011 parser_lex(parser);
17012 opening = parser->previous;
17013 accept1(parser, PM_TOKEN_NEWLINE);
17015 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17016 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17017 accept1(parser, PM_TOKEN_NEWLINE);
17018 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17021 closing = parser->previous;
17027 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
17034 switch (PM_NODE_TYPE(inner)) {
17035 case PM_ARRAY_PATTERN_NODE: {
17039 PM_NODE_START_SET_NODE(pattern_node, node);
17040 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17043 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17044 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17046 return UP(pattern_node);
17051 case PM_FIND_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_HASH_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);
17090 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17091 pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
17092 return UP(pattern_node);
17100 assert(parser->previous.
type == PM_TOKEN_USTAR);
17107 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17108 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17111 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17112 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17115 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17116 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17117 name = UP(pm_local_variable_target_node_create(
17121 (uint32_t) (depth == -1 ? 0 : depth)
17126 return pm_splat_node_create(parser, &
operator, name);
17134 assert(parser->current.type == PM_TOKEN_USTAR_STAR);
17135 parser_lex(parser);
17140 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17141 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
17144 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17145 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17148 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17149 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17152 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17153 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17154 value = UP(pm_local_variable_target_node_create(
17158 (uint32_t) (depth == -1 ? 0 : depth)
17162 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
17170pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17171 ptrdiff_t length = end - start;
17172 if (length == 0)
return false;
17175 size_t width = char_is_identifier_start(parser, start, end - start);
17176 if (width == 0)
return false;
17179 if (parser->encoding_changed) {
17180 if (parser->encoding->isupper_char(start, length))
return false;
17182 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17187 const uint8_t *cursor = start + width;
17188 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17189 return cursor == end;
17199 const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
17200 const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
17202 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
17205 if (pm_slice_is_valid_local(parser, start, end)) {
17206 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17208 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
17210 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
17211 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
17216 pm_parser_local_add(parser, constant_id, start, end, 0);
17219 parse_pattern_capture(parser, captures, constant_id, value_loc);
17224 (uint32_t) (depth == -1 ? 0 : depth)
17227 return UP(pm_implicit_node_create(parser, UP(target)));
17236 if (pm_static_literals_add(&parser->line_offsets, parser->start, parser->start_line, parser->encoding, keys, node,
true) != NULL) {
17237 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17250 switch (PM_NODE_TYPE(first_node)) {
17251 case PM_ASSOC_SPLAT_NODE:
17252 case PM_NO_KEYWORDS_PARAMETER_NODE:
17255 case PM_INTERPOLATED_SYMBOL_NODE:
17256 case PM_SYMBOL_NODE: {
17257 if (pm_symbol_node_label_p(parser, first_node)) {
17258 if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
17259 pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17261 parse_pattern_hash_key(parser, &keys, first_node);
17271 if (!token_begins_pattern_p(parser->current.type)) {
17272 if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
17273 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17275 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
17280 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17283 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17284 pm_node_list_append(parser->arena, &assocs, assoc);
17293 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;
17294 pm_parser_err_node(parser, first_node, diag_id);
17296 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
17297 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17299 pm_node_list_append(parser->arena, &assocs, assoc);
17305 while (accept1(parser, PM_TOKEN_COMMA)) {
17311 if (!token_begins_pattern_p(parser->current.type)) {
17313 if (rest != NULL) {
17314 pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17320 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17321 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17323 if (rest == NULL) {
17326 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17327 pm_node_list_append(parser->arena, &assocs, assoc);
17332 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17333 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17335 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17336 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17337 }
else if (!pm_symbol_node_label_p(parser, key)) {
17338 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17340 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
17341 key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17343 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17345 pm_token_t label = { .
type = PM_TOKEN_LABEL, .start = parser->previous.
end, .end = parser->previous.
end };
17346 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
17349 parse_pattern_hash_key(parser, &keys, key);
17357 if (!token_begins_pattern_p(parser->current.type)) {
17358 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
17359 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17361 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
17364 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17367 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
17369 if (rest != NULL) {
17370 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17373 pm_node_list_append(parser->arena, &assocs, assoc);
17380 pm_static_literals_free(&keys);
17389 switch (parser->current.type) {
17390 case PM_TOKEN_IDENTIFIER:
17391 case PM_TOKEN_METHOD_NAME: {
17392 parser_lex(parser);
17393 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17396 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17397 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17400 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17401 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17402 return UP(pm_local_variable_target_node_create(
17406 (uint32_t) (depth == -1 ? 0 : depth)
17409 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17411 parser_lex(parser);
17413 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17416 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
17421 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17423 accept1(parser, PM_TOKEN_NEWLINE);
17424 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17427 switch (PM_NODE_TYPE(inner)) {
17428 case PM_ARRAY_PATTERN_NODE: {
17431 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17432 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17434 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17435 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17437 return UP(pattern_node);
17442 case PM_FIND_PATTERN_NODE: {
17445 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17446 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17448 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17449 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17451 return UP(pattern_node);
17461 pm_array_pattern_node_requireds_append(parser->arena, node, inner);
17464 case PM_TOKEN_BRACE_LEFT_HASH: {
17465 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17466 parser->pattern_matching_newlines =
false;
17470 parser_lex(parser);
17472 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17475 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
17479 switch (parser->current.type) {
17480 case PM_TOKEN_LABEL:
17481 parser_lex(parser);
17482 first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
17484 case PM_TOKEN_USTAR_STAR:
17485 first_node = parse_pattern_keyword_rest(parser, captures);
17487 case PM_TOKEN_STRING_BEGIN:
17488 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));
17491 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
17492 parser_lex(parser);
17494 first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
17499 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17501 accept1(parser, PM_TOKEN_NEWLINE);
17502 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
17505 PM_NODE_START_SET_TOKEN(parser, node, &opening);
17506 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
17512 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17515 case PM_TOKEN_UDOT_DOT:
17516 case PM_TOKEN_UDOT_DOT_DOT: {
17518 parser_lex(parser);
17522 switch (parser->current.type) {
17523 case PM_CASE_PRIMITIVE: {
17524 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));
17525 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17528 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17529 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17530 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17534 case PM_CASE_PRIMITIVE: {
17535 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));
17538 if (pm_symbol_node_label_p(parser, node))
return node;
17541 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17542 pm_parser_err_node(parser, node, diag_id);
17543 return UP(pm_error_recovery_node_create_unexpected(parser, node));
17547 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17553 switch (parser->current.type) {
17554 case PM_CASE_PRIMITIVE: {
17555 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));
17556 return UP(pm_range_node_create(parser, node, &
operator, right));
17559 return UP(pm_range_node_create(parser, node, &
operator, NULL));
17565 case PM_TOKEN_CARET: {
17566 parser_lex(parser);
17571 switch (parser->current.type) {
17572 case PM_TOKEN_IDENTIFIER: {
17573 parser_lex(parser);
17574 pm_node_t *variable = UP(parse_variable(parser));
17576 if (variable == NULL) {
17577 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
17578 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
17581 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17583 case PM_TOKEN_INSTANCE_VARIABLE: {
17584 parser_lex(parser);
17585 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
17587 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17589 case PM_TOKEN_CLASS_VARIABLE: {
17590 parser_lex(parser);
17591 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
17593 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17595 case PM_TOKEN_GLOBAL_VARIABLE: {
17596 parser_lex(parser);
17597 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
17599 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17601 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
17602 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17603 parser->pattern_matching_newlines =
false;
17606 parser_lex(parser);
17608 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));
17609 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17611 accept1(parser, PM_TOKEN_NEWLINE);
17612 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
17613 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->previous));
17618 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17619 pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17620 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17624 case PM_TOKEN_UCOLON_COLON: {
17626 parser_lex(parser);
17628 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17631 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
17633 case PM_TOKEN_CONSTANT: {
17635 parser_lex(parser);
17637 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
17638 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17641 pm_parser_err_current(parser, diag_id);
17642 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17654parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
17657 switch (PM_NODE_TYPE(node)) {
17658 case PM_LOCAL_VARIABLE_TARGET_NODE:
17661 if (peek_at(parser, parser->start + PM_NODE_START(node)) !=
'_') {
17662 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17665 case PM_ARRAY_PATTERN_NODE:
17666 case PM_ASSOC_NODE:
17667 case PM_ASSOC_SPLAT_NODE:
17668 case PM_CAPTURE_PATTERN_NODE:
17669 case PM_FIND_PATTERN_NODE:
17670 case PM_HASH_PATTERN_NODE:
17671 case PM_IMPLICIT_NODE:
17672 case PM_PARENTHESES_NODE:
17673 case PM_SPLAT_NODE:
17687 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
17697 bool alternation =
false;
17699 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
17700 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->size) {
17701 parse_pattern_alternation_error(parser, node);
17704 switch (parser->current.type) {
17705 case PM_TOKEN_IDENTIFIER:
17706 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17707 case PM_TOKEN_BRACE_LEFT_HASH:
17708 case PM_TOKEN_CARET:
17709 case PM_TOKEN_CONSTANT:
17710 case PM_TOKEN_UCOLON_COLON:
17711 case PM_TOKEN_UDOT_DOT:
17712 case PM_TOKEN_UDOT_DOT_DOT:
17713 case PM_CASE_PRIMITIVE: {
17714 if (!alternation) {
17715 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17718 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17720 if (captures->size) parse_pattern_alternation_error(parser, right);
17721 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17726 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
17727 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17730 parser_lex(parser);
17732 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17733 accept1(parser, PM_TOKEN_NEWLINE);
17734 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17735 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
17737 if (!alternation) {
17740 if (captures->size) parse_pattern_alternation_error(parser, right);
17741 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17747 pm_parser_err_current(parser, diag_id);
17748 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17750 if (!alternation) {
17753 if (captures->size) parse_pattern_alternation_error(parser, right);
17754 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
17764 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17766 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17768 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17771 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17772 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17775 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17776 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17781 (uint32_t) (depth == -1 ? 0 : depth)
17784 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17797 bool leading_rest =
false;
17798 bool trailing_rest =
false;
17800 switch (parser->current.type) {
17801 case PM_TOKEN_LABEL: {
17802 parser_lex(parser);
17803 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17804 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17806 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17807 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17812 case PM_TOKEN_USTAR_STAR: {
17813 node = parse_pattern_keyword_rest(parser, captures);
17814 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17816 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17817 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17822 case PM_TOKEN_STRING_BEGIN: {
17825 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17827 if (pm_symbol_node_label_p(parser, node)) {
17828 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17830 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17831 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17837 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17840 case PM_TOKEN_USTAR: {
17841 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17842 parser_lex(parser);
17843 node = UP(parse_pattern_rest(parser, captures));
17844 leading_rest =
true;
17850 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17856 if (pm_symbol_node_label_p(parser, node)) {
17857 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17860 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17865 pm_node_list_append(parser->arena, &nodes, node);
17868 while (accept1(parser, PM_TOKEN_COMMA)) {
17874 if (!token_begins_pattern_p(parser->current.type)) {
17879 if (trailing_rest) {
17880 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17883 node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
17884 pm_node_list_append(parser->arena, &nodes, node);
17885 trailing_rest =
true;
17889 if (accept1(parser, PM_TOKEN_USTAR)) {
17890 node = UP(parse_pattern_rest(parser, captures));
17895 if (trailing_rest) {
17896 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17899 trailing_rest =
true;
17901 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17904 pm_node_list_append(parser->arena, &nodes, node);
17911 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17912 node = UP(pm_find_pattern_node_create(parser, &nodes));
17914 if (nodes.
size == 2) {
17915 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17918 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17920 if (leading_rest && trailing_rest) {
17921 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17926 }
else if (leading_rest) {
17929 node = UP(pm_array_pattern_node_rest_create(parser, node));
17941parse_negative_numeric(
pm_node_t *node) {
17942 switch (PM_NODE_TYPE(node)) {
17943 case PM_INTEGER_NODE: {
17950 case PM_FLOAT_NODE: {
17957 case PM_RATIONAL_NODE: {
17964 case PM_IMAGINARY_NODE:
17970 assert(
false &&
"unreachable");
17981pm_parser_err_prefix(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
17983 case PM_ERR_HASH_KEY: {
17984 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.
type));
17987 case PM_ERR_HASH_VALUE:
17988 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17989 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
17992 case PM_ERR_UNARY_RECEIVER: {
17993 const char *human = (parser->current.type == PM_TOKEN_EOF ?
"end-of-input" : pm_token_str(parser->current.type));
17994 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.
start[0]);
17997 case PM_ERR_UNARY_DISALLOWED:
17998 case PM_ERR_EXPECT_ARGUMENT: {
17999 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
18003 pm_parser_err_previous(parser, diag_id);
18013#define CONTEXT_NONE 0
18014#define CONTEXT_THROUGH_ENSURE 1
18015#define CONTEXT_THROUGH_ELSE 2
18018 int context = CONTEXT_NONE;
18020 while (context_node != NULL) {
18021 switch (context_node->context) {
18022 case PM_CONTEXT_BEGIN_RESCUE:
18023 case PM_CONTEXT_BLOCK_RESCUE:
18024 case PM_CONTEXT_CLASS_RESCUE:
18025 case PM_CONTEXT_DEF_RESCUE:
18026 case PM_CONTEXT_LAMBDA_RESCUE:
18027 case PM_CONTEXT_MODULE_RESCUE:
18028 case PM_CONTEXT_SCLASS_RESCUE:
18029 case PM_CONTEXT_DEFINED:
18030 case PM_CONTEXT_RESCUE_MODIFIER:
18033 case PM_CONTEXT_CLASS:
18034 case PM_CONTEXT_DEF:
18035 case PM_CONTEXT_DEF_PARAMS:
18036 case PM_CONTEXT_MAIN:
18037 case PM_CONTEXT_MODULE:
18038 case PM_CONTEXT_PREEXE:
18039 case PM_CONTEXT_SCLASS:
18042 if (context == CONTEXT_NONE) {
18043 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
18044 }
else if (context == CONTEXT_THROUGH_ENSURE) {
18045 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
18046 }
else if (context == CONTEXT_THROUGH_ELSE) {
18047 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
18050 case PM_CONTEXT_BEGIN_ELSE:
18051 case PM_CONTEXT_BLOCK_ELSE:
18052 case PM_CONTEXT_CLASS_ELSE:
18053 case PM_CONTEXT_DEF_ELSE:
18054 case PM_CONTEXT_LAMBDA_ELSE:
18055 case PM_CONTEXT_MODULE_ELSE:
18056 case PM_CONTEXT_SCLASS_ELSE:
18059 context = CONTEXT_THROUGH_ELSE;
18061 case PM_CONTEXT_BEGIN_ENSURE:
18062 case PM_CONTEXT_BLOCK_ENSURE:
18063 case PM_CONTEXT_CLASS_ENSURE:
18064 case PM_CONTEXT_DEF_ENSURE:
18065 case PM_CONTEXT_LAMBDA_ENSURE:
18066 case PM_CONTEXT_MODULE_ENSURE:
18067 case PM_CONTEXT_SCLASS_ENSURE:
18070 context = CONTEXT_THROUGH_ENSURE;
18072 case PM_CONTEXT_NONE:
18073 case PM_CONTEXT_MAXIMUM:
18075 assert(
false &&
"unreachable");
18077 case PM_CONTEXT_BEGIN:
18078 case PM_CONTEXT_BLOCK_BRACES:
18079 case PM_CONTEXT_BLOCK_KEYWORDS:
18080 case PM_CONTEXT_BLOCK_PARAMETERS:
18081 case PM_CONTEXT_CASE_IN:
18082 case PM_CONTEXT_CASE_WHEN:
18083 case PM_CONTEXT_DEFAULT_PARAMS:
18084 case PM_CONTEXT_ELSE:
18085 case PM_CONTEXT_ELSIF:
18086 case PM_CONTEXT_EMBEXPR:
18087 case PM_CONTEXT_FOR_INDEX:
18088 case PM_CONTEXT_FOR:
18089 case PM_CONTEXT_IF:
18090 case PM_CONTEXT_LAMBDA_BRACES:
18091 case PM_CONTEXT_LAMBDA_DO_END:
18092 case PM_CONTEXT_LOOP_PREDICATE:
18093 case PM_CONTEXT_MULTI_TARGET:
18094 case PM_CONTEXT_PARENS:
18095 case PM_CONTEXT_POSTEXE:
18096 case PM_CONTEXT_PREDICATE:
18097 case PM_CONTEXT_TERNARY:
18098 case PM_CONTEXT_UNLESS:
18099 case PM_CONTEXT_UNTIL:
18100 case PM_CONTEXT_WHILE:
18106 context_node = context_node->prev;
18110#undef CONTEXT_ENSURE
18121 while (context_node != NULL) {
18122 switch (context_node->context) {
18123 case PM_CONTEXT_DEF:
18124 case PM_CONTEXT_DEF_PARAMS:
18125 case PM_CONTEXT_DEFINED:
18126 case PM_CONTEXT_DEF_ENSURE:
18127 case PM_CONTEXT_DEF_RESCUE:
18128 case PM_CONTEXT_DEF_ELSE:
18132 case PM_CONTEXT_CLASS:
18133 case PM_CONTEXT_CLASS_ENSURE:
18134 case PM_CONTEXT_CLASS_RESCUE:
18135 case PM_CONTEXT_CLASS_ELSE:
18136 case PM_CONTEXT_MAIN:
18137 case PM_CONTEXT_MODULE:
18138 case PM_CONTEXT_MODULE_ENSURE:
18139 case PM_CONTEXT_MODULE_RESCUE:
18140 case PM_CONTEXT_MODULE_ELSE:
18141 case PM_CONTEXT_SCLASS:
18142 case PM_CONTEXT_SCLASS_RESCUE:
18143 case PM_CONTEXT_SCLASS_ENSURE:
18144 case PM_CONTEXT_SCLASS_ELSE:
18147 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
18149 case PM_CONTEXT_NONE:
18150 case PM_CONTEXT_MAXIMUM:
18152 assert(
false &&
"unreachable");
18154 case PM_CONTEXT_BEGIN:
18155 case PM_CONTEXT_BEGIN_ELSE:
18156 case PM_CONTEXT_BEGIN_ENSURE:
18157 case PM_CONTEXT_BEGIN_RESCUE:
18158 case PM_CONTEXT_BLOCK_BRACES:
18159 case PM_CONTEXT_BLOCK_KEYWORDS:
18160 case PM_CONTEXT_BLOCK_ELSE:
18161 case PM_CONTEXT_BLOCK_ENSURE:
18162 case PM_CONTEXT_BLOCK_PARAMETERS:
18163 case PM_CONTEXT_BLOCK_RESCUE:
18164 case PM_CONTEXT_CASE_IN:
18165 case PM_CONTEXT_CASE_WHEN:
18166 case PM_CONTEXT_DEFAULT_PARAMS:
18167 case PM_CONTEXT_ELSE:
18168 case PM_CONTEXT_ELSIF:
18169 case PM_CONTEXT_EMBEXPR:
18170 case PM_CONTEXT_FOR_INDEX:
18171 case PM_CONTEXT_FOR:
18172 case PM_CONTEXT_IF:
18173 case PM_CONTEXT_LAMBDA_BRACES:
18174 case PM_CONTEXT_LAMBDA_DO_END:
18175 case PM_CONTEXT_LAMBDA_ELSE:
18176 case PM_CONTEXT_LAMBDA_ENSURE:
18177 case PM_CONTEXT_LAMBDA_RESCUE:
18178 case PM_CONTEXT_LOOP_PREDICATE:
18179 case PM_CONTEXT_MULTI_TARGET:
18180 case PM_CONTEXT_PARENS:
18181 case PM_CONTEXT_POSTEXE:
18182 case PM_CONTEXT_PREDICATE:
18183 case PM_CONTEXT_PREEXE:
18184 case PM_CONTEXT_RESCUE_MODIFIER:
18185 case PM_CONTEXT_TERNARY:
18186 case PM_CONTEXT_UNLESS:
18187 case PM_CONTEXT_UNTIL:
18188 case PM_CONTEXT_WHILE:
18194 context_node = context_node->prev;
18203parse_case(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18204 size_t opening_newline_index = token_newline_index(parser);
18205 parser_lex(parser);
18211 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18213 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18214 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18216 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18218 }
else if (!token_begins_expression_p(parser->current.type)) {
18221 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));
18222 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18225 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18226 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18227 parser_lex(parser);
18228 pop_block_exits(parser, previous_block_exits);
18229 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18230 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->previous));
18237 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18238 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
18244 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18245 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18246 parser_lex(parser);
18249 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18252 if (accept1(parser, PM_TOKEN_USTAR)) {
18254 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));
18256 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18257 pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
18259 if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE))
break;
18261 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));
18262 pm_when_node_conditions_append(parser->arena, when_node, condition);
18266 if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE))
break;
18270 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18271 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18272 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE) && parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
18273 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18276 pm_when_clause_static_literals_add(parser, &literals, condition);
18278 }
while (accept1(parser, PM_TOKEN_COMMA));
18280 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18281 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18282 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18285 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18286 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18289 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18290 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18291 if (statements != NULL) {
18292 pm_when_node_statements_set(when_node, statements);
18296 pm_case_node_condition_append(parser->arena, case_node, UP(when_node));
18302 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18305 pm_static_literals_free(&literals);
18306 node = UP(case_node);
18308 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
18312 if (predicate == NULL) {
18313 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18318 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18319 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18321 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
18322 parser->pattern_matching_newlines =
true;
18324 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18325 parser->command_start =
false;
18326 parser_lex(parser);
18331 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));
18333 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
18338 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18340 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));
18341 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18342 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18344 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));
18345 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18352 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18353 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18354 then_keyword = parser->previous;
18357 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18358 then_keyword = parser->previous;
18364 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18367 statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
18372 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
18373 pm_case_match_node_condition_append(parser->arena, case_node, condition);
18379 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18382 node = UP(case_node);
18385 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18386 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18390 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18391 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
18393 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
18396 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18397 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18403 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18404 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18406 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18407 pm_case_node_end_keyword_loc_set(parser, (
pm_case_node_t *) node, &parser->previous);
18409 pm_case_match_node_end_keyword_loc_set(parser, (
pm_case_match_node_t *) node, &parser->previous);
18412 pop_block_exits(parser, previous_block_exits);
18421parse_class(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18422 size_t opening_newline_index = token_newline_index(parser);
18423 parser_lex(parser);
18425 pm_token_t class_keyword = parser->previous;
18426 pm_do_loop_stack_push(parser,
false);
18429 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18431 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18433 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));
18435 pm_parser_scope_push(parser,
true);
18436 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18437 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
18441 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18442 pm_accepts_block_stack_push(parser,
true);
18443 statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18444 pm_accepts_block_stack_pop(parser);
18447 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18448 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18449 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)));
18451 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18454 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18457 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18459 pm_parser_scope_pop(parser);
18460 pm_do_loop_stack_pop(parser);
18462 flush_block_exits(parser, previous_block_exits);
18463 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->previous));
18466 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));
18468 if (name.
type != PM_TOKEN_CONSTANT) {
18469 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18475 if (match1(parser, PM_TOKEN_LESS)) {
18476 inheritance_operator = parser->current;
18477 lex_state_set(parser, PM_LEX_STATE_BEG);
18479 parser->command_start =
true;
18480 parser_lex(parser);
18482 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));
18487 pm_parser_scope_push(parser,
true);
18489 if (inheritance_operator.
start != NULL) {
18490 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18492 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18496 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18497 pm_accepts_block_stack_push(parser,
true);
18498 statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18499 pm_accepts_block_stack_pop(parser);
18502 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18503 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18504 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)));
18506 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18509 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18511 if (context_def_p(parser)) {
18512 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18516 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18518 pm_parser_scope_pop(parser);
18519 pm_do_loop_stack_pop(parser);
18521 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18522 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18523 if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18524 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18528 pop_block_exits(parser, previous_block_exits);
18529 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
18536parse_def(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
18538 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18541 size_t opening_newline_index = token_newline_index(parser);
18549 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18550 parser_lex(parser);
18554 bool valid_name =
true;
18556 switch (parser->current.type) {
18557 case PM_CASE_OPERATOR:
18558 pm_parser_scope_push(parser,
true);
18559 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18560 parser_lex(parser);
18562 name = parser->previous;
18564 case PM_TOKEN_IDENTIFIER: {
18565 parser_lex(parser);
18567 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18568 receiver = parse_variable_call(parser);
18570 pm_parser_scope_push(parser,
true);
18571 lex_state_set(parser, PM_LEX_STATE_FNAME);
18572 parser_lex(parser);
18574 operator = parser->previous;
18575 name = parse_method_definition_name(parser);
18577 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
18578 pm_parser_scope_push(parser,
true);
18580 name = parser->previous;
18585 case PM_TOKEN_INSTANCE_VARIABLE:
18586 case PM_TOKEN_CLASS_VARIABLE:
18587 case PM_TOKEN_GLOBAL_VARIABLE:
18588 valid_name =
false;
18590 case PM_TOKEN_CONSTANT:
18591 case PM_TOKEN_KEYWORD_NIL:
18592 case PM_TOKEN_KEYWORD_SELF:
18593 case PM_TOKEN_KEYWORD_TRUE:
18594 case PM_TOKEN_KEYWORD_FALSE:
18595 case PM_TOKEN_KEYWORD___FILE__:
18596 case PM_TOKEN_KEYWORD___LINE__:
18597 case PM_TOKEN_KEYWORD___ENCODING__: {
18598 pm_parser_scope_push(parser,
true);
18599 parser_lex(parser);
18603 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18604 lex_state_set(parser, PM_LEX_STATE_FNAME);
18605 parser_lex(parser);
18606 operator = parser->previous;
18608 switch (identifier.
type) {
18609 case PM_TOKEN_CONSTANT:
18610 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18612 case PM_TOKEN_INSTANCE_VARIABLE:
18613 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18615 case PM_TOKEN_CLASS_VARIABLE:
18616 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18618 case PM_TOKEN_GLOBAL_VARIABLE:
18619 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18621 case PM_TOKEN_KEYWORD_NIL:
18622 receiver = UP(pm_nil_node_create(parser, &identifier));
18624 case PM_TOKEN_KEYWORD_SELF:
18625 receiver = UP(pm_self_node_create(parser, &identifier));
18627 case PM_TOKEN_KEYWORD_TRUE:
18628 receiver = UP(pm_true_node_create(parser, &identifier));
18630 case PM_TOKEN_KEYWORD_FALSE:
18631 receiver = UP(pm_false_node_create(parser, &identifier));
18633 case PM_TOKEN_KEYWORD___FILE__:
18634 receiver = UP(pm_source_file_node_create(parser, &identifier));
18636 case PM_TOKEN_KEYWORD___LINE__:
18637 receiver = UP(pm_source_line_node_create(parser, &identifier));
18639 case PM_TOKEN_KEYWORD___ENCODING__:
18640 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18646 name = parse_method_definition_name(parser);
18649 PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.
type));
18656 case PM_TOKEN_PARENTHESIS_LEFT: {
18660 context_pop(parser);
18661 parser_lex(parser);
18664 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));
18666 accept1(parser, PM_TOKEN_NEWLINE);
18667 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18670 lex_state_set(parser, PM_LEX_STATE_FNAME);
18671 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18673 operator = parser->previous;
18674 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18678 pm_parser_scope_push(parser,
true);
18679 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18680 name = parse_method_definition_name(parser);
18684 pm_parser_scope_push(parser,
true);
18685 name = parse_method_definition_name(parser);
18693 bool accept_endless_def =
true;
18694 switch (parser->current.type) {
18695 case PM_TOKEN_PARENTHESIS_LEFT: {
18696 parser_lex(parser);
18697 lparen = parser->previous;
18699 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18703 bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
18704 params = parse_parameters(
18706 PM_BINDING_POWER_DEFINED,
18708 allow_trailing_comma,
18712 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18713 (uint16_t) (depth + 1)
18717 lex_state_set(parser, PM_LEX_STATE_BEG);
18718 parser->command_start =
true;
18720 context_pop(parser);
18721 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18722 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
18723 parser->previous.
start = parser->previous.
end;
18724 parser->previous.
type = 0;
18727 rparen = parser->previous;
18730 case PM_CASE_PARAMETER: {
18733 if (parser->current.type == PM_TOKEN_LABEL) {
18734 lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
18737 params = parse_parameters(
18739 PM_BINDING_POWER_DEFINED,
18745 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18746 (uint16_t) (depth + 1)
18751 accept_endless_def =
false;
18753 context_pop(parser);
18758 context_pop(parser);
18767 if (accept1(parser, PM_TOKEN_EQUAL)) {
18768 if (token_is_setter_name(&name)) {
18769 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18771 if (!accept_endless_def) {
18772 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18775 parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
18776 parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
18778 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");
18780 equal = parser->previous;
18782 context_push(parser, PM_CONTEXT_DEF);
18783 pm_do_loop_stack_push(parser,
false);
18784 statements = UP(pm_statements_node_create(parser));
18786 uint8_t allow_flags;
18787 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
18788 allow_flags = flags & PM_PARSE_ACCEPTS_COMMAND_CALL;
18792 allow_flags = (binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18805 pm_accepts_block_stack_push(parser,
true);
18806 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));
18813 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18814 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18815 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18822 while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18823 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18825 pm_token_t rescue_keyword = parser->previous;
18829 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));
18830 context_pop(parser);
18832 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18835 pm_accepts_block_stack_pop(parser);
18840 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(parser, statement)) {
18841 PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18844 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18845 pm_do_loop_stack_pop(parser);
18846 context_pop(parser);
18848 if (lparen.
start == NULL) {
18849 lex_state_set(parser, PM_LEX_STATE_BEG);
18850 parser->command_start =
true;
18851 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18853 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18856 pm_accepts_block_stack_push(parser,
true);
18857 pm_do_loop_stack_push(parser,
false);
18859 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18860 pm_accepts_block_stack_push(parser,
true);
18861 statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18862 pm_accepts_block_stack_pop(parser);
18865 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18866 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18867 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)));
18869 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18872 pm_accepts_block_stack_pop(parser);
18873 pm_do_loop_stack_pop(parser);
18875 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18876 end_keyword = parser->previous;
18880 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18881 pm_parser_scope_pop(parser);
18886 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
18888 flush_block_exits(parser, previous_block_exits);
18890 return UP(pm_def_node_create(
18899 NTOK2PTR(
operator),
18903 NTOK2PTR(end_keyword)
18911parse_module(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18913 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18915 size_t opening_newline_index = token_newline_index(parser);
18916 parser_lex(parser);
18917 pm_token_t module_keyword = parser->previous;
18919 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));
18924 if (PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18925 pop_block_exits(parser, previous_block_exits);
18928 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
18931 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
18934 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
18935 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
18941 name = parser->previous;
18942 if (name.
type != PM_TOKEN_CONSTANT) {
18943 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
18946 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)) {
18947 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18950 pm_parser_scope_push(parser,
true);
18951 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
18954 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18955 pm_accepts_block_stack_push(parser,
true);
18956 statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
18957 pm_accepts_block_stack_pop(parser);
18960 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18961 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18962 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)));
18964 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
18968 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18970 pm_parser_scope_pop(parser);
18971 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
18973 if (context_def_p(parser)) {
18974 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
18977 pop_block_exits(parser, previous_block_exits);
18979 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
18986parse_string_array(
pm_parser_t *parser, uint16_t depth) {
18987 parser_lex(parser);
18995 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
18996 switch (parser->current.type) {
18997 case PM_TOKEN_WORDS_SEP: {
19000 parser->explicit_encoding = NULL;
19002 if (current == NULL) {
19009 pm_array_node_elements_append(parser->arena, array, current);
19013 parser_lex(parser);
19016 case PM_TOKEN_STRING_CONTENT: {
19017 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
19018 pm_node_flag_set(
string, parse_unescaped_encoding(parser, parser->explicit_encoding));
19019 parser_lex(parser);
19021 if (current == NULL) {
19027 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19032 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19038 pm_interpolated_string_node_append(parser, interpolated, current);
19039 pm_interpolated_string_node_append(parser, interpolated,
string);
19040 current = UP(interpolated);
19042 assert(
false &&
"unreachable");
19047 case PM_TOKEN_EMBVAR: {
19048 if (current == NULL) {
19052 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19053 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19059 pm_interpolated_string_node_append(parser, interpolated, current);
19060 current = UP(interpolated);
19067 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19071 case PM_TOKEN_EMBEXPR_BEGIN: {
19072 if (current == NULL) {
19076 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
19077 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19083 pm_interpolated_string_node_append(parser, interpolated, current);
19084 current = UP(interpolated);
19085 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19089 assert(
false &&
"unreachable");
19092 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19097 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19098 parser_lex(parser);
19105 pm_array_node_elements_append(parser->arena, array, current);
19109 if (match1(parser, PM_TOKEN_EOF)) {
19110 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19111 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19113 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19116 pm_array_node_close_set(parser, array, &closing);
19124parse_symbol_array(
pm_parser_t *parser, uint16_t depth) {
19125 parser_lex(parser);
19133 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19134 switch (parser->current.type) {
19135 case PM_TOKEN_WORDS_SEP: {
19138 parser->explicit_encoding = NULL;
19140 if (current == NULL) {
19147 pm_array_node_elements_append(parser->arena, array, current);
19151 parser_lex(parser);
19154 case PM_TOKEN_STRING_CONTENT: {
19155 if (current == NULL) {
19160 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
19161 parser_lex(parser);
19162 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19166 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
19167 parser_lex(parser);
19170 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19177 .
type = PM_TOKEN_STRING_CONTENT,
19182 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
19183 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
19184 parser_lex(parser);
19187 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
19188 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
19190 current = UP(interpolated);
19192 assert(
false &&
"unreachable");
19197 case PM_TOKEN_EMBVAR: {
19198 bool start_location_set =
false;
19199 if (current == NULL) {
19203 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19204 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19211 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19212 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
19213 PM_NODE_START_SET_NODE(interpolated, current);
19214 start_location_set =
true;
19215 current = UP(interpolated);
19222 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19224 if (!start_location_set) {
19225 PM_NODE_START_SET_NODE(current, part);
19229 case PM_TOKEN_EMBEXPR_BEGIN: {
19230 bool start_location_set =
false;
19231 if (current == NULL) {
19235 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
19236 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19243 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19244 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
19245 PM_NODE_START_SET_NODE(interpolated, current);
19246 start_location_set =
true;
19247 current = UP(interpolated);
19248 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19252 assert(
false &&
"unreachable");
19255 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19257 if (!start_location_set) {
19258 PM_NODE_START_SET_NODE(current, part);
19263 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19264 parser_lex(parser);
19271 pm_array_node_elements_append(parser->arena, array, current);
19275 if (match1(parser, PM_TOKEN_EOF)) {
19276 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19277 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19279 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19281 pm_array_node_close_set(parser, array, &closing);
19291parse_parentheses(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19293 pm_node_flags_t paren_flags = 0;
19296 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19298 parser_lex(parser);
19300 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19301 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19302 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19309 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
19313 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT) && opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19314 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19317 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19318 pop_block_exits(parser, previous_block_exits);
19319 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
19324 context_push(parser, PM_CONTEXT_PARENS);
19325 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));
19326 context_pop(parser);
19331 bool terminator_found =
false;
19333 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19334 terminator_found =
true;
19335 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19336 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
19337 terminator_found =
true;
19340 if (terminator_found) {
19342 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19343 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19344 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19352 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19353 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19354 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19357 parser_lex(parser);
19358 pop_block_exits(parser, previous_block_exits);
19360 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19366 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
19369 multi_target = pm_multi_target_node_create(parser);
19370 pm_multi_target_node_targets_append(parser, multi_target, statement);
19373 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
19374 multi_target->
rparen_loc = TOK2LOC(parser, &parser->previous);
19375 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
19376 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
19379 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
19380 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19381 accept1(parser, PM_TOKEN_NEWLINE);
19383 result = UP(multi_target);
19386 if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
19388 }
else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match2(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_COMMA)) {
19392 }
else if (flags & PM_PARSE_ACCEPTS_STATEMENT) {
19396 if (pm_binding_powers[parser->current.type].binary && !match1(parser, PM_TOKEN_EQUAL)) {
19397 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19399 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
19402 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19403 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
19406 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19416 pm_statements_node_body_append(parser, statements, statement,
true);
19418 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19424 context_push(parser, PM_CONTEXT_PARENS);
19425 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19428 pm_statements_node_body_append(parser, statements, statement,
true);
19432 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
19433 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19438 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));
19439 pm_statements_node_body_append(parser, statements, node,
true);
19443 if (parser->recovering) {
19446 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering =
false;
19452 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE))
break;
19456 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19457 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
19458 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
19459 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19461 }
else if (!match1(parser, PM_TOKEN_EOF)) {
19464 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19468 context_pop(parser);
19469 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19478 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19480 pm_multi_target_node_targets_append(parser, multi_target, statement);
19482 statement = UP(multi_target);
19486 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
19487 const uint8_t *offset = parser->start + PM_NODE_END(statement);
19488 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
19489 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
19491 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
19494 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
19498 pop_block_exits(parser, previous_block_exits);
19499 pm_void_statements_check(parser, statements,
true);
19500 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19509parse_splat(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19513 if (token_begins_expression_p(parser->current.type)) {
19514 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19517 return UP(pm_splat_node_create(parser, &
operator, name));
19524parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
19525 switch (parser->current.type) {
19526 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
19527 parser_lex(parser);
19529 pm_array_node_t *array = pm_array_node_create(parser, &parser->previous);
19530 bool parsed_bare_hash =
false;
19532 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
19533 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
19537 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19543 if (accept1(parser, PM_TOKEN_COMMA)) {
19546 if (accepted_newline) {
19547 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
19552 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
19553 parser->previous.
start = parser->previous.
end;
19554 parser->previous.
type = 0;
19561 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
19565 if (accept1(parser, PM_TOKEN_USTAR)) {
19569 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
19570 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
19572 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));
19575 element = UP(pm_splat_node_create(parser, &
operator, expression));
19576 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
19577 if (parsed_bare_hash) {
19578 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
19581 element = UP(pm_keyword_hash_node_create(parser));
19584 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)) {
19585 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19588 pm_static_literals_free(&hash_keys);
19589 parsed_bare_hash =
true;
19591 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));
19593 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
19594 if (parsed_bare_hash) {
19595 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
19600 pm_hash_key_static_literals_add(parser, &hash_keys, element);
19603 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
19604 operator = parser->previous;
19607 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));
19608 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, NTOK2PTR(
operator), value));
19609 pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
19611 element = UP(hash);
19612 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19613 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19616 pm_static_literals_free(&hash_keys);
19617 parsed_bare_hash =
true;
19621 pm_array_node_elements_append(parser->arena, array, element);
19622 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
19625 accept1(parser, PM_TOKEN_NEWLINE);
19627 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19628 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
19629 parser->previous.
start = parser->previous.
end;
19630 parser->previous.
type = 0;
19633 pm_array_node_close_set(parser, array, &parser->previous);
19637 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
19638 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
19639 return parse_parentheses(parser, binding_power, flags, depth);
19640 case PM_TOKEN_BRACE_LEFT_HASH: {
19641 parser_lex(parser);
19646 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
19648 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
19649 pm_static_literals_free(&hash_keys);
19651 accept1(parser, PM_TOKEN_NEWLINE);
19654 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
19655 pm_hash_node_closing_loc_set(parser, node, &parser->previous);
19659 case PM_TOKEN_CHARACTER_LITERAL: {
19660 pm_node_t *node = UP(pm_string_node_create_current_string(
19663 .type = PM_TOKEN_STRING_BEGIN,
19664 .start = parser->current.start,
19665 .end = parser->current.start + 1
19668 .type = PM_TOKEN_STRING_CONTENT,
19669 .start = parser->current.start + 1,
19670 .end = parser->current.end
19675 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
19679 parser_lex(parser);
19683 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19684 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19689 case PM_TOKEN_CLASS_VARIABLE: {
19690 parser_lex(parser);
19691 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->previous));
19693 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19694 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19699 case PM_TOKEN_CONSTANT: {
19700 parser_lex(parser);
19706 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
19707 ((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))) ||
19708 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19709 match1(parser, PM_TOKEN_BRACE_LEFT)
19712 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19713 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
19716 pm_node_t *node = UP(pm_constant_read_node_create(parser, &parser->previous));
19718 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19721 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19726 case PM_TOKEN_UCOLON_COLON: {
19727 parser_lex(parser);
19730 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19731 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous));
19733 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19734 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19739 case PM_TOKEN_UDOT_DOT:
19740 case PM_TOKEN_UDOT_DOT_DOT: {
19742 parser_lex(parser);
19744 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));
19750 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
19751 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
19754 return UP(pm_range_node_create(parser, NULL, &
operator, right));
19756 case PM_TOKEN_FLOAT:
19757 parser_lex(parser);
19758 return UP(pm_float_node_create(parser, &parser->previous));
19759 case PM_TOKEN_FLOAT_IMAGINARY:
19760 parser_lex(parser);
19761 return UP(pm_float_node_imaginary_create(parser, &parser->previous));
19762 case PM_TOKEN_FLOAT_RATIONAL:
19763 parser_lex(parser);
19764 return UP(pm_float_node_rational_create(parser, &parser->previous));
19765 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
19766 parser_lex(parser);
19767 return UP(pm_float_node_rational_imaginary_create(parser, &parser->previous));
19768 case PM_TOKEN_NUMBERED_REFERENCE: {
19769 parser_lex(parser);
19770 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
19772 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19773 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19778 case PM_TOKEN_GLOBAL_VARIABLE: {
19779 parser_lex(parser);
19780 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->previous));
19782 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19783 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19788 case PM_TOKEN_BACK_REFERENCE: {
19789 parser_lex(parser);
19790 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->previous));
19792 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
19793 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19798 case PM_TOKEN_IDENTIFIER:
19799 case PM_TOKEN_METHOD_NAME: {
19800 parser_lex(parser);
19802 pm_node_t *node = parse_variable_call(parser);
19804 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
19812 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
19815 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
19824 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
19826 PM_NODE_LENGTH_SET_LOCATION(call, end);
19834 ((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))) ||
19835 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
19836 match1(parser, PM_TOKEN_BRACE_LEFT)
19839 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
19840 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
19842 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
19846 pm_node_unreference(parser, node);
19852 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
19854 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
19855 pm_node_unreference(parser, node);
19858 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
19866 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
19867 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19872 case PM_TOKEN_HEREDOC_START: {
19875 assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
19878 size_t common_whitespace = (size_t) -1;
19879 parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
19881 parser_lex(parser);
19887 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19890 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19891 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
19893 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19894 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19896 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19899 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
19900 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
19907 node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19908 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19913 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
19917 cast->
closing_loc = TOK2LOC(parser, &parser->current);
19920 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19922 cast->
base.
type = PM_X_STRING_NODE;
19925 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19926 parse_heredoc_dedent_string(parser->arena, &cast->
unescaped, common_whitespace);
19930 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19936 pm_node_list_append(parser->arena, &parts, part);
19938 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19939 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19940 pm_node_list_append(parser->arena, &parts, part);
19946 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19948 cast->
parts = parts;
19950 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19951 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
19958 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19959 pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
19967 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19969 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19975 parse_heredoc_dedent(parser, nodes, common_whitespace);
19983 pm_lex_mode_t *whitespace_mode = parser->lex_modes.current;
19985 if (whitespace_mode->mode == PM_LEX_HEREDOC && whitespace_mode->as.heredoc.common_whitespace == &common_whitespace) {
19986 whitespace_mode->as.heredoc.common_whitespace = NULL;
19988 whitespace_mode = whitespace_mode->prev;
19989 }
while (whitespace_mode != NULL);
19991 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19992 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19997 case PM_TOKEN_INSTANCE_VARIABLE: {
19998 parser_lex(parser);
19999 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
20001 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
20002 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20007 case PM_TOKEN_INTEGER: {
20008 pm_node_flags_t base = parser->integer.base;
20009 parser_lex(parser);
20010 return UP(pm_integer_node_create(parser, base, &parser->previous));
20012 case PM_TOKEN_INTEGER_IMAGINARY: {
20013 pm_node_flags_t base = parser->integer.base;
20014 parser_lex(parser);
20015 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
20017 case PM_TOKEN_INTEGER_RATIONAL: {
20018 pm_node_flags_t base = parser->integer.base;
20019 parser_lex(parser);
20020 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
20022 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
20023 pm_node_flags_t base = parser->integer.base;
20024 parser_lex(parser);
20025 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
20027 case PM_TOKEN_KEYWORD___ENCODING__:
20028 parser_lex(parser);
20029 return UP(pm_source_encoding_node_create(parser, &parser->previous));
20030 case PM_TOKEN_KEYWORD___FILE__:
20031 parser_lex(parser);
20032 return UP(pm_source_file_node_create(parser, &parser->previous));
20033 case PM_TOKEN_KEYWORD___LINE__:
20034 parser_lex(parser);
20035 return UP(pm_source_line_node_create(parser, &parser->previous));
20036 case PM_TOKEN_KEYWORD_ALIAS: {
20037 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20038 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
20041 parser_lex(parser);
20044 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
20045 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
20047 switch (PM_NODE_TYPE(new_name)) {
20048 case PM_BACK_REFERENCE_READ_NODE:
20049 case PM_NUMBERED_REFERENCE_READ_NODE:
20050 case PM_GLOBAL_VARIABLE_READ_NODE: {
20051 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)) {
20052 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
20053 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
20055 }
else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
20056 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
20057 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
20060 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
20062 case PM_SYMBOL_NODE:
20063 case PM_INTERPOLATED_SYMBOL_NODE: {
20064 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)) {
20065 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
20066 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
20071 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
20074 case PM_TOKEN_KEYWORD_CASE:
20075 return parse_case(parser, flags, depth);
20076 case PM_TOKEN_KEYWORD_BEGIN: {
20077 size_t opening_newline_index = token_newline_index(parser);
20078 parser_lex(parser);
20080 pm_token_t begin_keyword = parser->previous;
20081 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20084 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20087 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
20088 pm_accepts_block_stack_push(parser,
true);
20089 begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
20090 pm_accepts_block_stack_pop(parser);
20091 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20094 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
20095 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
20096 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
20098 PM_NODE_LENGTH_SET_TOKEN(parser, begin_node, &parser->previous);
20099 pm_begin_node_end_keyword_set(parser, begin_node, &parser->previous);
20100 pop_block_exits(parser, previous_block_exits);
20101 return UP(begin_node);
20103 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
20105 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20107 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20108 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
20111 parser_lex(parser);
20114 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
20116 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
20118 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
20119 pm_context_t context = parser->current_context->context;
20120 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
20121 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
20124 flush_block_exits(parser, previous_block_exits);
20125 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
20127 case PM_TOKEN_KEYWORD_BREAK:
20128 case PM_TOKEN_KEYWORD_NEXT:
20129 case PM_TOKEN_KEYWORD_RETURN: {
20130 parser_lex(parser);
20136 token_begins_expression_p(parser->current.type) ||
20137 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
20139 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
20141 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
20143 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
20146 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
20147 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.
type));
20156 if (parser->previous.
type == PM_TOKEN_COMMA && match1(parser, PM_TOKEN_EOF)) {
20157 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
20164 if (arguments.
block != NULL) {
20165 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20166 pm_node_unreference(parser, arguments.
block);
20167 arguments.
block = NULL;
20171 switch (keyword.
type) {
20172 case PM_TOKEN_KEYWORD_BREAK: {
20174 if (!parser->partial_script) parse_block_exit(parser, node);
20177 case PM_TOKEN_KEYWORD_NEXT: {
20179 if (!parser->partial_script) parse_block_exit(parser, node);
20182 case PM_TOKEN_KEYWORD_RETURN: {
20184 parse_return(parser, node);
20188 assert(
false &&
"unreachable");
20189 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20192 case PM_TOKEN_KEYWORD_SUPER: {
20193 parser_lex(parser);
20197 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20202 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
20204 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
20207 return UP(pm_super_node_create(parser, &keyword, &arguments));
20209 case PM_TOKEN_KEYWORD_YIELD: {
20210 parser_lex(parser);
20214 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
20220 if (arguments.
block != NULL) {
20221 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20222 pm_node_unreference(parser, arguments.
block);
20223 arguments.
block = NULL;
20227 if (!parser->parsing_eval && !parser->partial_script) parse_yield(parser, node);
20231 case PM_TOKEN_KEYWORD_CLASS:
20232 return parse_class(parser, flags, depth);
20233 case PM_TOKEN_KEYWORD_DEF:
20234 return parse_def(parser, binding_power, flags, depth);
20235 case PM_TOKEN_KEYWORD_DEFINED: {
20236 parser_lex(parser);
20243 context_push(parser, PM_CONTEXT_DEFINED);
20244 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
20246 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20247 lparen = parser->previous;
20249 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20250 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20253 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));
20255 if (!parser->recovering) {
20256 accept1(parser, PM_TOKEN_NEWLINE);
20257 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20258 rparen = parser->previous;
20262 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
20265 context_pop(parser);
20266 return UP(pm_defined_node_create(
20274 case PM_TOKEN_KEYWORD_END_UPCASE: {
20275 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20276 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
20279 parser_lex(parser);
20282 if (context_def_p(parser)) {
20283 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
20286 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
20288 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
20290 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
20291 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous));
20293 case PM_TOKEN_KEYWORD_FALSE:
20294 parser_lex(parser);
20295 return UP(pm_false_node_create(parser, &parser->previous));
20296 case PM_TOKEN_KEYWORD_FOR: {
20297 size_t opening_newline_index = token_newline_index(parser);
20298 parser_lex(parser);
20303 context_push(parser, PM_CONTEXT_FOR_INDEX);
20306 if (accept1(parser, PM_TOKEN_USTAR)) {
20307 index = parse_splat(parser, flags, depth);
20308 }
else if (token_begins_expression_p(parser->current.type)) {
20309 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
20311 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
20312 index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
20316 if (match1(parser, PM_TOKEN_COMMA)) {
20317 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20319 index = parse_target(parser, index,
false,
false);
20322 context_pop(parser);
20323 pm_do_loop_stack_push(parser,
true);
20325 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
20328 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));
20329 pm_do_loop_stack_pop(parser);
20332 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20333 do_keyword = parser->previous;
20335 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
20336 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
20341 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20342 statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
20345 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
20346 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
20348 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous));
20350 case PM_TOKEN_KEYWORD_IF:
20351 if (parser_end_of_line_p(parser)) {
20352 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
20355 size_t opening_newline_index = token_newline_index(parser);
20356 bool if_after_else = parser->previous.
type == PM_TOKEN_KEYWORD_ELSE;
20357 parser_lex(parser);
20359 return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
20360 case PM_TOKEN_KEYWORD_UNDEF: {
20361 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20362 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
20365 parser_lex(parser);
20366 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
20367 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20369 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20371 pm_undef_node_append(parser->arena, undef, name);
20373 while (match1(parser, PM_TOKEN_COMMA)) {
20374 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
20375 parser_lex(parser);
20376 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20378 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20382 pm_undef_node_append(parser->arena, undef, name);
20388 case PM_TOKEN_KEYWORD_NOT: {
20389 parser_lex(parser);
20402 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
20403 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
20404 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
20406 accept1(parser, PM_TOKEN_NEWLINE);
20407 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
20410 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
20413 accept1(parser, PM_TOKEN_NEWLINE);
20415 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20418 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20419 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20421 arguments.
opening_loc = TOK2LOC(parser, &lparen);
20422 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));
20424 if (!parser->recovering) {
20425 accept1(parser, PM_TOKEN_NEWLINE);
20426 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20427 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
20431 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));
20434 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
20436 case PM_TOKEN_KEYWORD_UNLESS: {
20437 size_t opening_newline_index = token_newline_index(parser);
20438 parser_lex(parser);
20440 return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
20442 case PM_TOKEN_KEYWORD_MODULE:
20443 return parse_module(parser, flags, depth);
20444 case PM_TOKEN_KEYWORD_NIL:
20445 parser_lex(parser);
20446 return UP(pm_nil_node_create(parser, &parser->previous));
20447 case PM_TOKEN_KEYWORD_REDO: {
20448 parser_lex(parser);
20450 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
20451 if (!parser->partial_script) parse_block_exit(parser, node);
20455 case PM_TOKEN_KEYWORD_RETRY: {
20456 parser_lex(parser);
20458 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
20459 parse_retry(parser, node);
20463 case PM_TOKEN_KEYWORD_SELF:
20464 parser_lex(parser);
20465 return UP(pm_self_node_create(parser, &parser->previous));
20466 case PM_TOKEN_KEYWORD_TRUE:
20467 parser_lex(parser);
20468 return UP(pm_true_node_create(parser, &parser->previous));
20469 case PM_TOKEN_KEYWORD_UNTIL: {
20470 size_t opening_newline_index = token_newline_index(parser);
20472 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20473 pm_do_loop_stack_push(parser,
true);
20475 parser_lex(parser);
20477 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));
20479 pm_do_loop_stack_pop(parser);
20480 context_pop(parser);
20483 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20484 do_keyword = parser->previous;
20486 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
20490 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20491 pm_accepts_block_stack_push(parser,
true);
20492 statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
20493 pm_accepts_block_stack_pop(parser);
20494 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20497 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20498 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
20500 return UP(pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20502 case PM_TOKEN_KEYWORD_WHILE: {
20503 size_t opening_newline_index = token_newline_index(parser);
20505 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20506 pm_do_loop_stack_push(parser,
true);
20508 parser_lex(parser);
20510 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));
20512 pm_do_loop_stack_pop(parser);
20513 context_pop(parser);
20516 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20517 do_keyword = parser->previous;
20519 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20523 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20524 pm_accepts_block_stack_push(parser,
true);
20525 statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20526 pm_accepts_block_stack_pop(parser);
20527 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20530 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20531 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
20533 return UP(pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0));
20535 case PM_TOKEN_PERCENT_LOWER_I: {
20536 parser_lex(parser);
20541 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20542 accept1(parser, PM_TOKEN_WORDS_SEP);
20543 if (match1(parser, PM_TOKEN_STRING_END))
break;
20547 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20549 if (current == NULL) {
20550 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20551 parser_lex(parser);
20552 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20553 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20554 parser_lex(parser);
20556 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20559 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &cast->
unescaped));
20560 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20561 parser_lex(parser);
20564 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20565 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20568 current = UP(interpolated);
20570 assert(
false &&
"unreachable");
20575 pm_array_node_elements_append(parser->arena, array, current);
20578 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20583 if (match1(parser, PM_TOKEN_EOF)) {
20584 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20585 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20587 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20589 pm_array_node_close_set(parser, array, &closing);
20593 case PM_TOKEN_PERCENT_UPPER_I:
20594 return parse_symbol_array(parser, depth);
20595 case PM_TOKEN_PERCENT_LOWER_W: {
20596 parser_lex(parser);
20601 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20602 accept1(parser, PM_TOKEN_WORDS_SEP);
20603 if (match1(parser, PM_TOKEN_STRING_END))
break;
20607 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20608 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20611 if (current == NULL) {
20613 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20615 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20617 pm_interpolated_string_node_append(parser, interpolated, current);
20618 pm_interpolated_string_node_append(parser, interpolated,
string);
20619 current = UP(interpolated);
20621 assert(
false &&
"unreachable");
20623 parser_lex(parser);
20627 pm_array_node_elements_append(parser->arena, array, current);
20630 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20635 if (match1(parser, PM_TOKEN_EOF)) {
20636 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20637 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20639 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20642 pm_array_node_close_set(parser, array, &closing);
20645 case PM_TOKEN_PERCENT_UPPER_W:
20646 return parse_string_array(parser, depth);
20647 case PM_TOKEN_REGEXP_BEGIN: {
20649 parser_lex(parser);
20651 if (match1(parser, PM_TOKEN_REGEXP_END)) {
20656 .
type = PM_TOKEN_STRING_CONTENT,
20657 .start = parser->previous.
end,
20658 .end = parser->previous.
end
20661 parser_lex(parser);
20664 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20670 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20677 parser_lex(parser);
20682 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
20689 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
20690 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
20698 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20700 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20701 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
20705 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
20708 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20713 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
20719 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
20720 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20721 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
20726 if (match1(parser, PM_TOKEN_EOF)) {
20727 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
20728 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20730 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
20733 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
20734 return UP(interpolated);
20736 case PM_TOKEN_XSTRING_BEGIN:
20737 case PM_TOKEN_PERCENT_LOWER_X: {
20738 parser_lex(parser);
20745 if (match1(parser, PM_TOKEN_STRING_END)) {
20750 .
type = PM_TOKEN_STRING_CONTENT,
20751 .start = parser->previous.
end,
20752 .end = parser->previous.
end
20755 parser_lex(parser);
20756 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
20761 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20768 parser_lex(parser);
20770 if (match1(parser, PM_TOKEN_STRING_END)) {
20771 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
20772 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
20773 parser_lex(parser);
20779 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20781 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20782 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
20784 pm_interpolated_xstring_node_append(parser->arena, node, part);
20789 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20793 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20794 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20795 pm_interpolated_xstring_node_append(parser->arena, node, part);
20800 if (match1(parser, PM_TOKEN_EOF)) {
20801 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20802 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20804 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20806 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
20810 case PM_TOKEN_USTAR: {
20811 parser_lex(parser);
20816 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20817 pm_parser_err_prefix(parser, diag_id);
20818 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20821 pm_node_t *splat = parse_splat(parser, flags, depth);
20823 if (match1(parser, PM_TOKEN_COMMA)) {
20824 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20826 return parse_target_validate(parser, splat,
true);
20829 case PM_TOKEN_BANG: {
20830 if (binding_power > PM_BINDING_POWER_UNARY) {
20831 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20834 parser_lex(parser);
20837 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));
20838 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20840 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20843 case PM_TOKEN_TILDE: {
20844 if (binding_power > PM_BINDING_POWER_UNARY) {
20845 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20847 parser_lex(parser);
20850 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));
20851 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20855 case PM_TOKEN_UMINUS: {
20856 if (binding_power > PM_BINDING_POWER_UNARY) {
20857 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20859 parser_lex(parser);
20862 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));
20863 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20867 case PM_TOKEN_UMINUS_NUM: {
20868 parser_lex(parser);
20871 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));
20873 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20874 pm_token_t exponent_operator = parser->previous;
20875 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));
20876 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20877 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20879 switch (PM_NODE_TYPE(node)) {
20880 case PM_INTEGER_NODE:
20881 case PM_FLOAT_NODE:
20882 case PM_RATIONAL_NODE:
20883 case PM_IMAGINARY_NODE:
20884 parse_negative_numeric(node);
20887 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20894 case PM_TOKEN_MINUS_GREATER: {
20895 int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
20896 parser->lambda_enclosure_nesting = parser->enclosure_nesting;
20898 size_t opening_newline_index = token_newline_index(parser);
20899 parser_lex(parser);
20902 pm_parser_scope_push(parser,
false);
20906 switch (parser->current.type) {
20907 case PM_TOKEN_PARENTHESIS_LEFT: {
20909 parser_lex(parser);
20911 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20912 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20914 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20917 accept1(parser, PM_TOKEN_NEWLINE);
20918 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20920 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
20923 case PM_CASE_PARAMETER: {
20924 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
20928 block_parameters = NULL;
20936 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20937 opening = parser->previous;
20939 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20940 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
20943 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20951 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
20952 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20960 pm_accepts_block_stack_push(parser,
true);
20961 expect1(parser, PM_TOKEN_KEYWORD_DO_LAMBDA, PM_ERR_LAMBDA_OPEN);
20962 opening = parser->previous;
20968 parser->lambda_enclosure_nesting = -1;
20970 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20971 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
20974 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20975 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20976 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)));
20978 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20981 pm_accepts_block_stack_pop(parser);
20986 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
20987 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20991 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
20992 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->previous);
20994 pm_parser_scope_pop(parser);
20996 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->previous, parameters, body));
20998 case PM_TOKEN_UPLUS: {
20999 if (binding_power > PM_BINDING_POWER_UNARY) {
21000 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
21002 parser_lex(parser);
21005 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));
21006 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
21010 case PM_TOKEN_STRING_BEGIN:
21011 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
21012 case PM_TOKEN_SYMBOL_BEGIN: {
21014 parser_lex(parser);
21016 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
21019 pm_context_t recoverable = context_recoverable(parser, &parser->current);
21021 if (recoverable != PM_CONTEXT_NONE) {
21022 parser->recovering =
true;
21027 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
21028 pm_parser_err_prefix(parser, diag_id);
21034 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
21035 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
21039 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
21041 pm_parser_err_prefix(parser, diag_id);
21044 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
21050parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth);
21060parse_rescue_modifier_terminator(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
21061 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
21062 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21063 parser_lex(parser);
21064 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));
21078parse_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) {
21079 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));
21085 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(parser, value) || pm_block_call_p(value))) {
21086 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21087 parser_lex(parser);
21088 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));
21093 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21094 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21097 parser_lex(parser);
21102 bool statement_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21103 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21105 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21106 context_pop(parser);
21111 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21112 parse_rescue_modifier_terminator(parser, flags, depth);
21115 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21127 switch (PM_NODE_TYPE(node)) {
21128 case PM_BEGIN_NODE: {
21133 case PM_LOCAL_VARIABLE_WRITE_NODE: {
21135 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
21138 case PM_PARENTHESES_NODE: {
21140 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
21143 case PM_STATEMENTS_NODE: {
21148 parse_assignment_value_local(parser, statement);
21170parse_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) {
21171 bool statement_level = (previous_binding_power == PM_BINDING_POWER_STATEMENT) || (flags & PM_PARSE_ACCEPTS_STATEMENT);
21173 bool permitted =
true;
21174 if (!statement_level && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
21179 uint8_t command_call_flag = (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT)
21180 ? (uint8_t) (flags & PM_PARSE_ACCEPTS_COMMAND_CALL)
21181 : ((previous_binding_power < PM_BINDING_POWER_MODIFIER || statement_level) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0);
21183 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));
21184 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
21186 parse_assignment_value_local(parser, value);
21187 bool single_value =
true;
21192 if (statement_level && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
21193 single_value =
false;
21196 pm_array_node_elements_append(parser->arena, array, value);
21199 while (accept1(parser, PM_TOKEN_COMMA)) {
21200 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
21202 pm_array_node_elements_append(parser->arena, array, element);
21203 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
21205 parse_assignment_value_local(parser, element);
21213 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))) {
21214 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21215 parser_lex(parser);
21216 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));
21221 bool multiple_assignment = (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1));
21222 if ((single_value || multiple_assignment) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21223 bool command_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21232 if (multiple_assignment && command_value)
return value;
21234 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21237 parser_lex(parser);
21243 bool statement_value = multiple_assignment || command_value;
21244 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21246 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21247 context_pop(parser);
21252 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21253 parse_rescue_modifier_terminator(parser, flags, depth);
21256 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21275parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth) {
21280 if (match1(parser, PM_TOKEN_USTAR)) {
21282 parser_lex(parser);
21283 value = parse_splat(parser, flags, depth);
21290 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));
21291 multiple = match1(parser, PM_TOKEN_COMMA) || PM_NODE_TYPE_P(value, PM_MULTI_TARGET_NODE);
21295 pm_node_t *target = parse_targets_validate(parser, value, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21302 if (!match1(parser, PM_TOKEN_EQUAL)) {
21303 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
21308 parser_lex(parser);
21310 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));
21311 value = parse_write(parser, target, &
operator, values);
21318 if (!PM_NODE_TYPE_P(value, PM_MATCH_REQUIRED_NODE) && !PM_NODE_TYPE_P(value, PM_MATCH_PREDICATE_NODE)) {
21319 parse_rescue_modifier_terminator(parser, flags, depth);
21327 return parse_expression(parser, PM_BINDING_POWER_DEFINED, flags, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21340 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
21341 pm_node_unreference(parser, UP(call_node->
arguments));
21345 if (call_node->
block != NULL) {
21346 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
21347 pm_node_unreference(parser, UP(call_node->
block));
21348 call_node->
block = NULL;
21353pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21356 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21357 uint8_t value = escape_hexadecimal_digit(*cursor);
21360 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21361 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21365 pm_buffer_append_byte(unescaped, value);
21367 pm_buffer_append_string(unescaped,
"\\x", 2);
21374pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21375 uint8_t value = (uint8_t) (*cursor -
'0');
21378 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21379 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21382 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21383 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21388 pm_buffer_append_byte(unescaped, value);
21394 const uint8_t *start = cursor - 1;
21397 if (cursor >= end) {
21398 pm_buffer_append_string(unescaped,
"\\u", 2);
21402 if (*cursor !=
'{') {
21403 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21404 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21406 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21407 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21410 return cursor + length;
21415 while (cursor < end && *cursor ==
' ') cursor++;
21417 if (cursor >= end)
break;
21418 if (*cursor ==
'}') {
21423 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21427 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21429 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21437pm_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) {
21438 const uint8_t *end = source + length;
21439 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21442 if (++cursor >= end) {
21443 pm_buffer_append_byte(unescaped,
'\\');
21449 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21451 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21452 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21455 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
21458 pm_buffer_append_byte(unescaped,
'\\');
21462 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->encoding_changed, parser->encoding);
21463 if (next_cursor == NULL)
break;
21465 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21466 cursor = next_cursor;
21469 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21481 const uint8_t *source = pm_string_source(capture);
21482 size_t length = pm_string_length(capture);
21493 const uint8_t *cursor = pm_memchr(source,
'\\', length, parser->encoding_changed, parser->encoding);
21494 if (PRISM_UNLIKELY(cursor != NULL)) {
21495 pm_named_capture_escape(parser, &unescaped, source, length, cursor, shared ? NULL : &call->receiver->location);
21496 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21497 length = pm_buffer_length(&unescaped);
21500 const uint8_t *start;
21501 const uint8_t *end;
21506 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21507 pm_buffer_cleanup(&unescaped);
21515 end = source + length;
21516 name = pm_parser_constant_id_raw(parser, start, end);
21520 start = parser->start + PM_NODE_START(call->
receiver);
21521 end = parser->start + PM_NODE_END(call->
receiver);
21523 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
21524 memcpy(memory, source, length);
21525 name = pm_parser_constant_id_owned(parser, memory, length);
21532 if (name != 0 && pm_constant_id_set_insert(parser->arena, names, name)) {
21535 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21538 if (pm_local_is_keyword((
const char *) source, length)) {
21539 pm_buffer_cleanup(&unescaped);
21545 pm_parser_local_add(parser, name, start, end, 0);
21550 if (callback_data->match == NULL) {
21551 callback_data->match = pm_match_write_node_create(parser, call);
21556 pm_token_t token = { .type = 0, .start = start, .end = end };
21558 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &token_loc, name, depth == -1 ? 0 : (uint32_t) depth));
21559 pm_node_list_append(parser->arena, &callback_data->match->
targets, target);
21562 pm_buffer_cleanup(&unescaped);
21578 pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content),
false, extended_mode, parse_regular_expression_named_capture, &callback_data);
21580 if (callback_data.match != NULL) {
21581 return UP(callback_data.match);
21588parse_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) {
21591 switch (token.type) {
21592 case PM_TOKEN_EQUAL: {
21593 switch (PM_NODE_TYPE(node)) {
21594 case PM_CALL_NODE: {
21600 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21601 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
21605 case PM_CASE_WRITABLE: {
21609 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
21610 pm_parser_local_add_location(parser, &node->
location, 0);
21613 parser_lex(parser);
21614 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));
21616 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
21617 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
21620 return parse_write(parser, node, &token, value);
21622 case PM_SPLAT_NODE: {
21624 pm_multi_target_node_targets_append(parser, multi_target, node);
21626 parser_lex(parser);
21627 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));
21628 return parse_write(parser, UP(multi_target), &token, value);
21630 case PM_SOURCE_ENCODING_NODE:
21631 case PM_FALSE_NODE:
21632 case PM_SOURCE_FILE_NODE:
21633 case PM_SOURCE_LINE_NODE:
21636 case PM_TRUE_NODE: {
21639 parser_lex(parser);
21640 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
21641 return parse_unwriteable_write(parser, node, &token, value);
21647 parser_lex(parser);
21648 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
21652 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
21653 switch (PM_NODE_TYPE(node)) {
21654 case PM_BACK_REFERENCE_READ_NODE:
21655 case PM_NUMBERED_REFERENCE_READ_NODE:
21656 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21658 case PM_GLOBAL_VARIABLE_READ_NODE: {
21659 parser_lex(parser);
21661 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21662 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
21666 case PM_CLASS_VARIABLE_READ_NODE: {
21667 parser_lex(parser);
21669 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21674 case PM_CONSTANT_PATH_NODE: {
21675 parser_lex(parser);
21677 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21680 return parse_shareable_constant_write(parser, write);
21682 case PM_CONSTANT_READ_NODE: {
21683 parser_lex(parser);
21685 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21688 if (context_def_p(parser)) {
21689 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21692 return parse_shareable_constant_write(parser, write);
21694 case PM_INSTANCE_VARIABLE_READ_NODE: {
21695 parser_lex(parser);
21697 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21702 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21704 parser_lex(parser);
21706 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21707 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
21709 pm_node_unreference(parser, node);
21712 case PM_LOCAL_VARIABLE_READ_NODE: {
21713 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21715 pm_node_unreference(parser, node);
21719 parser_lex(parser);
21721 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21722 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21726 case PM_CALL_NODE: {
21732 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21735 parser_lex(parser);
21737 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21738 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21745 parser_lex(parser);
21750 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21751 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21752 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
21756 if (pm_call_node_writable_p(parser, cast)) {
21757 parse_write_name(parser, &cast->
name);
21759 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21762 parse_call_operator_write(parser, cast, &token);
21763 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
21764 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
21766 case PM_MULTI_WRITE_NODE: {
21767 parser_lex(parser);
21768 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
21772 parser_lex(parser);
21777 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
21781 case PM_TOKEN_PIPE_PIPE_EQUAL: {
21782 switch (PM_NODE_TYPE(node)) {
21783 case PM_BACK_REFERENCE_READ_NODE:
21784 case PM_NUMBERED_REFERENCE_READ_NODE:
21785 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21787 case PM_GLOBAL_VARIABLE_READ_NODE: {
21788 parser_lex(parser);
21790 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21791 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
21795 case PM_CLASS_VARIABLE_READ_NODE: {
21796 parser_lex(parser);
21798 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21803 case PM_CONSTANT_PATH_NODE: {
21804 parser_lex(parser);
21806 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21809 return parse_shareable_constant_write(parser, write);
21811 case PM_CONSTANT_READ_NODE: {
21812 parser_lex(parser);
21814 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21817 if (context_def_p(parser)) {
21818 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21821 return parse_shareable_constant_write(parser, write);
21823 case PM_INSTANCE_VARIABLE_READ_NODE: {
21824 parser_lex(parser);
21826 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21831 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21833 parser_lex(parser);
21835 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21836 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
21838 pm_node_unreference(parser, node);
21841 case PM_LOCAL_VARIABLE_READ_NODE: {
21842 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21843 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21844 pm_node_unreference(parser, node);
21848 parser_lex(parser);
21850 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21851 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21855 case PM_CALL_NODE: {
21861 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21864 parser_lex(parser);
21866 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21867 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21874 parser_lex(parser);
21879 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21880 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21881 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
21885 if (pm_call_node_writable_p(parser, cast)) {
21886 parse_write_name(parser, &cast->
name);
21888 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21891 parse_call_operator_write(parser, cast, &token);
21892 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
21893 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
21895 case PM_MULTI_WRITE_NODE: {
21896 parser_lex(parser);
21897 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
21901 parser_lex(parser);
21906 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
21910 case PM_TOKEN_AMPERSAND_EQUAL:
21911 case PM_TOKEN_CARET_EQUAL:
21912 case PM_TOKEN_GREATER_GREATER_EQUAL:
21913 case PM_TOKEN_LESS_LESS_EQUAL:
21914 case PM_TOKEN_MINUS_EQUAL:
21915 case PM_TOKEN_PERCENT_EQUAL:
21916 case PM_TOKEN_PIPE_EQUAL:
21917 case PM_TOKEN_PLUS_EQUAL:
21918 case PM_TOKEN_SLASH_EQUAL:
21919 case PM_TOKEN_STAR_EQUAL:
21920 case PM_TOKEN_STAR_STAR_EQUAL: {
21921 switch (PM_NODE_TYPE(node)) {
21922 case PM_BACK_REFERENCE_READ_NODE:
21923 case PM_NUMBERED_REFERENCE_READ_NODE:
21924 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21926 case PM_GLOBAL_VARIABLE_READ_NODE: {
21927 parser_lex(parser);
21929 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21930 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
21934 case PM_CLASS_VARIABLE_READ_NODE: {
21935 parser_lex(parser);
21937 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21942 case PM_CONSTANT_PATH_NODE: {
21943 parser_lex(parser);
21945 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21948 return parse_shareable_constant_write(parser, write);
21950 case PM_CONSTANT_READ_NODE: {
21951 parser_lex(parser);
21953 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21956 if (context_def_p(parser)) {
21957 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
21960 return parse_shareable_constant_write(parser, write);
21962 case PM_INSTANCE_VARIABLE_READ_NODE: {
21963 parser_lex(parser);
21965 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21970 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21972 parser_lex(parser);
21974 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21975 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21977 pm_node_unreference(parser, node);
21980 case PM_LOCAL_VARIABLE_READ_NODE: {
21981 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
21982 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
21983 pm_node_unreference(parser, 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_OPERATOR, (uint16_t) (depth + 1));
21990 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21994 case PM_CALL_NODE: {
21995 parser_lex(parser);
22001 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22004 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22005 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
22013 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22014 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22015 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
22019 if (pm_call_node_writable_p(parser, cast)) {
22020 parse_write_name(parser, &cast->
name);
22022 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22025 parse_call_operator_write(parser, cast, &token);
22026 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22027 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
22029 case PM_MULTI_WRITE_NODE: {
22030 parser_lex(parser);
22031 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
22035 parser_lex(parser);
22040 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
22044 case PM_TOKEN_AMPERSAND_AMPERSAND:
22045 case PM_TOKEN_KEYWORD_AND: {
22046 parser_lex(parser);
22048 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));
22049 return UP(pm_and_node_create(parser, node, &token, right));
22051 case PM_TOKEN_KEYWORD_OR:
22052 case PM_TOKEN_PIPE_PIPE: {
22053 parser_lex(parser);
22055 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));
22056 return UP(pm_or_node_create(parser, node, &token, right));
22058 case PM_TOKEN_EQUAL_TILDE: {
22066 parser_lex(parser);
22067 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));
22070 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
22076 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
22083 bool interpolated =
false;
22084 size_t total_length = 0;
22088 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
22089 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
22091 interpolated =
true;
22096 if (!interpolated && total_length > 0) {
22097 void *memory =
xmalloc(total_length);
22098 if (!memory) abort();
22100 uint8_t *cursor = memory;
22103 size_t length = pm_string_length(unescaped);
22105 memcpy(cursor, pm_string_source(unescaped), length);
22110 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
22112 result = parse_interpolated_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
22113 pm_string_cleanup(&owned);
22115 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
22126 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
22128 if (name_data.match != NULL) {
22129 result = UP(name_data.match);
22135 case PM_TOKEN_UAMPERSAND:
22136 case PM_TOKEN_USTAR:
22137 case PM_TOKEN_USTAR_STAR:
22140 case PM_TOKEN_BANG_EQUAL:
22141 case PM_TOKEN_BANG_TILDE:
22142 case PM_TOKEN_EQUAL_EQUAL:
22143 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
22144 case PM_TOKEN_LESS_EQUAL_GREATER:
22145 case PM_TOKEN_CARET:
22146 case PM_TOKEN_PIPE:
22147 case PM_TOKEN_AMPERSAND:
22148 case PM_TOKEN_GREATER_GREATER:
22149 case PM_TOKEN_LESS_LESS:
22150 case PM_TOKEN_MINUS:
22151 case PM_TOKEN_PLUS:
22152 case PM_TOKEN_PERCENT:
22153 case PM_TOKEN_SLASH:
22154 case PM_TOKEN_STAR:
22155 case PM_TOKEN_STAR_STAR: {
22156 parser_lex(parser);
22158 switch (PM_NODE_TYPE(node)) {
22159 case PM_RESCUE_MODIFIER_NODE: {
22162 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22166 case PM_AND_NODE: {
22168 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22169 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22175 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22176 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22184 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));
22185 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
22187 case PM_TOKEN_GREATER:
22188 case PM_TOKEN_GREATER_EQUAL:
22189 case PM_TOKEN_LESS:
22190 case PM_TOKEN_LESS_EQUAL: {
22191 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
22192 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
22195 parser_lex(parser);
22196 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));
22197 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
22199 case PM_TOKEN_AMPERSAND_DOT:
22200 case PM_TOKEN_DOT: {
22201 parser_lex(parser);
22206 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
22207 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22208 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
22211 switch (PM_NODE_TYPE(node)) {
22212 case PM_RESCUE_MODIFIER_NODE: {
22215 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22219 case PM_AND_NODE: {
22221 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22222 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22228 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
22229 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22239 switch (parser->current.type) {
22240 case PM_CASE_OPERATOR:
22241 case PM_CASE_KEYWORD:
22242 case PM_TOKEN_CONSTANT:
22243 case PM_TOKEN_IDENTIFIER:
22244 case PM_TOKEN_METHOD_NAME: {
22245 parser_lex(parser);
22246 message = parser->previous;
22250 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
22251 message = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
22255 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22256 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
22259 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
22262 match1(parser, PM_TOKEN_COMMA)
22264 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22269 case PM_TOKEN_DOT_DOT:
22270 case PM_TOKEN_DOT_DOT_DOT: {
22271 parser_lex(parser);
22274 if (token_begins_expression_p(parser->current.type)) {
22275 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22278 return UP(pm_range_node_create(parser, node, &token, right));
22280 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
22282 parser_lex(parser);
22284 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));
22285 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
22287 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
22289 parser_lex(parser);
22291 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));
22292 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
22294 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
22295 parser_lex(parser);
22297 pm_statements_node_body_append(parser, statements, node,
true);
22299 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));
22300 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));
22302 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
22303 parser_lex(parser);
22305 pm_statements_node_body_append(parser, statements, node,
true);
22307 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));
22308 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));
22310 case PM_TOKEN_QUESTION_MARK: {
22311 context_push(parser, PM_CONTEXT_TERNARY);
22313 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22316 parser_lex(parser);
22318 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));
22320 if (parser->recovering) {
22328 pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
22330 context_pop(parser);
22331 pop_block_exits(parser, previous_block_exits);
22332 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
22335 accept1(parser, PM_TOKEN_NEWLINE);
22336 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
22339 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));
22341 context_pop(parser);
22342 pop_block_exits(parser, previous_block_exits);
22343 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
22345 case PM_TOKEN_COLON_COLON: {
22346 parser_lex(parser);
22349 switch (parser->current.type) {
22350 case PM_TOKEN_CONSTANT: {
22351 parser_lex(parser);
22355 (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
22356 ((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)))
22367 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22368 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
22371 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
22375 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22376 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22381 case PM_CASE_OPERATOR:
22382 case PM_CASE_KEYWORD:
22383 case PM_TOKEN_IDENTIFIER:
22384 case PM_TOKEN_METHOD_NAME: {
22385 parser_lex(parser);
22391 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22392 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
22395 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22396 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22401 case PM_TOKEN_PARENTHESIS_LEFT: {
22405 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22407 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
22410 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
22411 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
22415 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22416 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
22417 parser_lex(parser);
22418 accept1(parser, PM_TOKEN_NEWLINE);
22420 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));
22421 context_pop(parser);
22423 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
22425 case PM_TOKEN_BRACKET_LEFT: {
22426 parser_lex(parser);
22429 arguments.
opening_loc = TOK2LOC(parser, &parser->previous);
22431 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22432 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
22433 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22436 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
22440 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22441 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22442 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22449 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22450 block = parse_block(parser, (uint16_t) (depth + 1));
22451 pm_arguments_validate_block(parser, &arguments, block);
22452 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22453 block = parse_block(parser, (uint16_t) (depth + 1));
22456 if (block != NULL) {
22457 if (arguments.
block != NULL) {
22458 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
22460 arguments.
arguments = pm_arguments_node_create(parser);
22462 pm_arguments_node_arguments_append(parser->arena, arguments.
arguments, arguments.
block);
22465 arguments.
block = UP(block);
22468 return UP(pm_call_node_aref_create(parser, node, &arguments));
22470 case PM_TOKEN_KEYWORD_IN: {
22471 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22472 parser->pattern_matching_newlines =
true;
22475 parser->command_start =
false;
22476 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22477 parser_lex(parser);
22480 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));
22482 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22484 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
22486 case PM_TOKEN_EQUAL_GREATER: {
22487 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22488 parser->pattern_matching_newlines =
true;
22491 parser->command_start =
false;
22492 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22493 parser_lex(parser);
22496 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));
22498 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22500 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
22503 assert(
false &&
"unreachable");
22508#undef PM_PARSE_PATTERN_SINGLE
22509#undef PM_PARSE_PATTERN_TOP
22510#undef PM_PARSE_PATTERN_MULTI
22526 pm_binding_power_t left = pm_binding_powers[parser->current.type].
left;
22528 switch (PM_NODE_TYPE(node)) {
22529 case PM_MULTI_WRITE_NODE:
22530 case PM_RETURN_NODE:
22531 case PM_BREAK_NODE:
22533 return left > PM_BINDING_POWER_MODIFIER;
22534 case PM_CLASS_VARIABLE_WRITE_NODE:
22535 case PM_CONSTANT_PATH_WRITE_NODE:
22536 case PM_CONSTANT_WRITE_NODE:
22537 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22538 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22539 case PM_LOCAL_VARIABLE_WRITE_NODE:
22540 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
22541 case PM_CALL_NODE: {
22544 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
22545 return left > PM_BINDING_POWER_MODIFIER;
22551 if (pm_command_call_value_p(parser, node)) {
22552 return left > PM_BINDING_POWER_COMPOSITION;
22558 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22560 case PM_SUPER_NODE:
22561 case PM_YIELD_NODE:
22564 if (pm_command_call_value_p(parser, node)) {
22565 return left > PM_BINDING_POWER_COMPOSITION;
22570 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22575 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(parser, node);
22576 case PM_RESCUE_MODIFIER_NODE:
22580 if (left > PM_BINDING_POWER_MODIFIER) {
22583 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
22600parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
22601 if (PRISM_UNLIKELY(depth >= PRISM_DEPTH_MAXIMUM)) {
22602 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22603 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
22606 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
22611 switch (PM_NODE_TYPE(node)) {
22612 case PM_ERROR_RECOVERY_NODE:
22614 case PM_PRE_EXECUTION_NODE:
22616 case PM_POST_EXECUTION_NODE:
22617 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22618 case PM_ALIAS_METHOD_NODE:
22619 case PM_UNDEF_NODE:
22620 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
22625 case PM_SUPER_NODE:
22626 case PM_YIELD_NODE:
22628 if (parse_expression_terminator(parser, node)) {
22632 case PM_SYMBOL_NODE:
22633 if (pm_symbol_node_label_p(parser, node)) {
22644 pm_token_type_t current_token_type;
22647 current_token_type = parser->current.type,
22648 current_binding_powers = pm_binding_powers[current_token_type],
22649 binding_power <= current_binding_powers.
left &&
22650 current_binding_powers.
binary
22652 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
22653 if (parse_expression_terminator(parser, node))
return node;
22657 if (current_binding_powers.
nonassoc) {
22665 if (next_binding_powers.
nonassoc && next_binding_powers.
left == current_binding_powers.
left) {
22666 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));
22677 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22678 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22679 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));
22683 if (PM_BINDING_POWER_TERM <= next_binding_powers.
left) {
22686 }
else if (current_binding_powers.
left <= next_binding_powers.
left) {
22691 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
22700 switch (node->
type) {
22701 case PM_CALL_NODE: {
22715 cast->
block == NULL &&
22725 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
22728 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22733 case PM_CONSTANT_PATH_NODE:
22736 flags &= (uint8_t) ~PM_PARSE_ACCEPTS_COMMAND_CALL;
22741 if (context_terminator(parser->current_context->context, &parser->current)) {
22744 !next_binding_powers.
binary ||
22745 binding_power > next_binding_powers.
left ||
22746 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
22762 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
22763 if (statements == NULL) {
22764 statements = pm_statements_node_create(parser);
22768 pm_arguments_node_arguments_append(
22771 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
22774 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
22777 pm_parser_constant_id_constant(parser,
"print", 5)
22781 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
22782 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
22783 if (statements == NULL) {
22784 statements = pm_statements_node_create(parser);
22788 pm_arguments_node_arguments_append(
22791 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
22794 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
22795 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
22799 pm_parser_constant_id_constant(parser,
"$F", 2),
22803 pm_statements_node_body_prepend(parser->arena, statements, UP(write));
22807 pm_arguments_node_arguments_append(
22810 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
22813 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
22815 pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
22817 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
22819 UP(pm_true_node_synthesized_create(parser))
22822 pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
22823 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
22827 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
22829 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
22833 statements = wrapped_statements;
22847 if (parser->current_scope == NULL) {
22848 pm_parser_scope_push(parser,
true);
22852 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
22854 parser_lex(parser);
22857 if (statements != NULL && !parser->parsing_eval) {
22861 assert(statements->
body.
size > 0);
22862 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
22866 pm_locals_order(parser, &parser->current_scope->locals, &locals,
true);
22867 pm_parser_scope_pop(parser);
22872 statements = wrap_statements(parser, statements);
22874 flush_block_exits(parser, previous_block_exits);
22880 if (statements == NULL) {
22881 statements = pm_statements_node_create(parser);
22885 return UP(pm_program_node_create(parser, &locals, statements));
22902pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
22903 size_t little_length = strlen(little);
22905 for (
const char *max = big + big_length - little_length; big <= max; big++) {
22906 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
22913#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
22921pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
22922 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
22923 pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
22934 const char *switches = pm_strnstr(engine,
" -", length);
22935 if (switches == NULL)
return;
22938 options->shebang_callback(
22940 (
const uint8_t *) (switches + 1),
22941 length - ((
size_t) (switches - engine)) - 1,
22942 options->shebang_callback_data
22945 size_t encoding_length;
22946 if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
22947 const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
22948 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22951 parser->command_line = next_options.command_line;
22952 parser->frozen_string_literal = next_options.frozen_string_literal;
22960 assert(arena != NULL);
22961 assert(source != NULL);
22965 .metadata_arena = { 0 },
22967 .lex_state = PM_LEX_STATE_BEG,
22968 .enclosure_nesting = 0,
22969 .lambda_enclosure_nesting = -1,
22970 .brace_nesting = 0,
22971 .do_loop_stack = 0,
22972 .accepts_block_stack = 0,
22975 .stack = {{ .mode = PM_LEX_DEFAULT }},
22976 .current = &parser->lex_modes.stack[0],
22979 .end = source + size,
22980 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22981 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22982 .next_start = NULL,
22983 .heredoc_end = NULL,
22985 .comment_list = { 0 },
22986 .magic_comment_list = { 0 },
22987 .warning_list = { 0 },
22988 .error_list = { 0 },
22989 .current_scope = NULL,
22990 .current_context = NULL,
22991 .encoding = PM_ENCODING_UTF_8_ENTRY,
22992 .encoding_changed_callback = NULL,
22993 .encoding_comment_start = source,
22994 .lex_callback = { 0 },
22996 .constant_pool = { 0 },
22997 .line_offsets = { 0 },
22999 .current_string = PM_STRING_EMPTY,
23001 .explicit_encoding = NULL,
23003 .parsing_eval =
false,
23004 .partial_script =
false,
23005 .command_start =
true,
23006 .recovering =
false,
23007 .continuable =
true,
23008 .encoding_locked =
false,
23009 .encoding_changed =
false,
23010 .pattern_matching_newlines =
false,
23011 .in_keyword_arg =
false,
23012 .current_block_exits = NULL,
23013 .semantic_token_seen =
false,
23015 .warn_mismatched_indentation =
true
23023 if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
23024 if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
23031 uint32_t constant_size = ((uint32_t) size) / 120;
23032 pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size);
23037 size_t newline_size = size / 22;
23038 pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
23041 if (options != NULL) {
23043 parser->filepath = options->filepath;
23046 parser->start_line = options->line;
23049 size_t encoding_length = pm_string_length(&options->encoding);
23050 if (encoding_length > 0) {
23051 const uint8_t *encoding_source = pm_string_source(&options->encoding);
23052 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23056 parser->encoding_locked = options->encoding_locked;
23059 parser->frozen_string_literal = options->frozen_string_literal;
23062 parser->command_line = options->command_line;
23065 parser->version = options->version;
23068 parser->partial_script = options->partial_script;
23071 parser->parsing_eval = options->scopes_count > 0;
23072 if (parser->parsing_eval) parser->warn_mismatched_indentation =
false;
23074 for (
size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
23076 pm_parser_scope_push(parser, scope_index == 0);
23080 parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
23082 for (
size_t local_index = 0; local_index < scope->locals_count; local_index++) {
23083 const pm_string_t *local = pm_options_scope_local(scope, local_index);
23085 const uint8_t *source = pm_string_source(local);
23086 size_t length = pm_string_length(local);
23088 uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
23089 memcpy(allocated, source, length);
23090 pm_parser_local_add_owned(parser, allocated, length);
23097 if (parser->version == PM_OPTIONS_VERSION_UNSET) {
23098 parser->version = PM_OPTIONS_VERSION_LATEST;
23101 pm_accepts_block_stack_push(parser,
true);
23104 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
23105 parser->current.end += 3;
23106 parser->encoding_comment_start += 3;
23108 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
23109 parser->encoding = PM_ENCODING_UTF_8_ENTRY;
23110 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
23117 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
23134 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
23135 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
23137 if (length > 2 && parser->current.end[0] ==
'#' && parser->current.end[1] ==
'!') {
23138 const char *engine;
23140 if ((engine = pm_strnstr((
const char *) parser->start,
"ruby", length)) != NULL) {
23141 if (newline != NULL) {
23142 parser->encoding_comment_start = newline + 1;
23144 if (options == NULL || options->main_script) {
23145 pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
23149 if (options != NULL && options->main_script && options->shebang_callback != NULL) {
23150 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->start)));
23153 search_shebang =
false;
23154 }
else if (options != NULL && options->main_script && !parser->parsing_eval) {
23155 search_shebang =
true;
23161 if (search_shebang) {
23164 bool found_shebang =
false;
23168 const uint8_t *cursor = parser->start;
23172 const uint8_t *newline = next_newline(cursor, parser->end - cursor);
23174 while (newline != NULL) {
23175 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
23177 cursor = newline + 1;
23178 newline = next_newline(cursor, parser->end - cursor);
23180 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
23181 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
23182 const char *engine;
23183 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
23184 found_shebang =
true;
23186 if (newline != NULL) {
23187 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
23188 parser->encoding_comment_start = newline + 1;
23191 if (options != NULL && options->shebang_callback != NULL) {
23192 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
23200 if (found_shebang) {
23201 parser->previous = (
pm_token_t) { .
type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23202 parser->current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23204 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
23205 pm_line_offset_list_clear(&parser->line_offsets);
23212 parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
23225 if (parser == NULL) abort();
23227 pm_parser_init(arena, parser, source, size, options);
23236 pm_string_cleanup(&parser->filepath);
23237 pm_arena_cleanup(&parser->metadata_arena);
23239 while (parser->current_scope != NULL) {
23244 pm_parser_scope_pop(parser);
23247 while (parser->lex_modes.index >= PM_LEX_STACK_SIZE) {
23248 lex_mode_pop(parser);
23257 pm_parser_cleanup(parser);
23267pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
23269 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
23270 case PM_ERR_BEGIN_UPCASE_BRACE:
23271 case PM_ERR_CLASS_VARIABLE_BARE:
23272 case PM_ERR_END_UPCASE_BRACE:
23273 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
23274 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
23275 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
23276 case PM_ERR_EXPRESSION_NOT_WRITABLE:
23277 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
23278 case PM_ERR_FLOAT_PARSE:
23279 case PM_ERR_GLOBAL_VARIABLE_BARE:
23280 case PM_ERR_HASH_KEY:
23281 case PM_ERR_HEREDOC_IDENTIFIER:
23282 case PM_ERR_INSTANCE_VARIABLE_BARE:
23283 case PM_ERR_INVALID_BLOCK_EXIT:
23284 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
23285 case PM_ERR_INVALID_FLOAT_EXPONENT:
23286 case PM_ERR_INVALID_NUMBER_BINARY:
23287 case PM_ERR_INVALID_NUMBER_DECIMAL:
23288 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
23289 case PM_ERR_INVALID_NUMBER_OCTAL:
23290 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
23291 case PM_ERR_NO_LOCAL_VARIABLE:
23292 case PM_ERR_PARAMETER_ORDER:
23293 case PM_ERR_STATEMENT_UNDEF:
23294 case PM_ERR_VOID_EXPRESSION:
23337 if (parser->error_list.size == 0) {
23338 parser->continuable =
false;
23342 if (!parser->continuable)
return;
23344 size_t source_length = (size_t) (parser->end - parser->start);
23347 bool has_non_stray_error =
false;
23349 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)) {
23350 has_non_stray_error =
true;
23358 size_t non_stray_min_start = SIZE_MAX;
23361 size_t error_start = (size_t) error->location.start;
23362 size_t error_end = error_start + (size_t) error->location.length;
23363 bool at_eof = error_end >= source_length;
23366 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
23367 parser->continuable =
false;
23372 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
23373 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
23374 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
23383 if (non_stray_min_start < error_start)
continue;
23390 if (at_eof && error_start > 0) {
23392 if (error->location.length == 1) {
23393 const uint8_t *
byte = parser->start + error_start;
23394 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
23395 parser->continuable =
false;
23405 if (has_non_stray_error)
continue;
23412 if (error->location.length == 1) {
23413 const uint8_t *
byte = parser->start + error_start;
23414 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
23418 parser->continuable =
false;
23428 pm_node_t *node = parse_program(parser);
23429 pm_parse_continuable(parser);
23441 bool eof = pm_source_stream_read(source);
23446 while (!eof && tmp->error_list.size > 0) {
23447 eof = pm_source_stream_read(source);
23450 pm_arena_cleanup(arena);
23452 tmp =
pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
23460#undef PM_CASE_KEYWORD
23461#undef PM_CASE_OPERATOR
23462#undef PM_CASE_WRITABLE
23463#undef PM_STRING_EMPTY
23468#ifndef PRISM_EXCLUDE_SERIALIZATION
23472 pm_buffer_append_string(buffer,
"PRISM", 5);
23476 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23484 pm_serialize_header(buffer);
23485 pm_serialize_content(parser, node, buffer);
23486 pm_buffer_append_byte(buffer,
'\0');
23494pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23496 pm_options_read(&options, data);
23500 pm_parser_init(&arena, &parser, source, size, &options);
23504 pm_serialize_header(buffer);
23505 pm_serialize_content(&parser, node, buffer);
23506 pm_buffer_append_byte(buffer,
'\0');
23508 pm_parser_cleanup(&parser);
23509 pm_arena_cleanup(&arena);
23510 pm_options_cleanup(&options);
23522 pm_options_read(&options, data);
23524 pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
23525 pm_serialize_header(buffer);
23526 pm_serialize_content(parser, node, buffer);
23527 pm_buffer_append_byte(buffer,
'\0');
23530 pm_arena_cleanup(&arena);
23531 pm_options_cleanup(&options);
23545 pm_options_read(&options, data);
23549 pm_parser_init(&arena, &parser, source, size, &options);
23553 int8_t result = -1;
23554 if (parser.error_list.size > 0) {
23555 const char *encoding_name = parser.encoding->name;
23556 pm_buffer_append_string(buffer, encoding_name, strlen(encoding_name));
23557 pm_buffer_append_byte(buffer,
'\0');
23559 result = (int8_t) pm_errors_format(&parser, buffer, format_type);
23562 pm_parser_cleanup(&parser);
23563 pm_arena_cleanup(&arena);
23564 pm_options_cleanup(&options);
23573pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23575 pm_options_read(&options, data);
23579 pm_parser_init(&arena, &parser, source, size, &options);
23582 pm_serialize_header(buffer);
23583 pm_serialize_encoding(parser.encoding, buffer);
23584 pm_buffer_append_varsint(buffer, parser.start_line);
23585 pm_serialize_line_offset_list(&parser.line_offsets, buffer);
23586 pm_serialize_comment_list(&parser.comment_list, buffer);
23588 pm_parser_cleanup(&parser);
23589 pm_arena_cleanup(&arena);
23590 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.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
PM_NODE_ALIGNAS struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
PM_NODE_ALIGNAS struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
PM_NODE_ALIGNAS struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
pm_node_t base
The embedded base node.
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t content_loc
StringNode::content_loc.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
enum pm_string_t::@118 type
The type of the string.
size_t length
The length of the string in bytes of memory.
PM_NODE_ALIGNAS struct pm_arguments_node * arguments
SuperNode::arguments.
pm_location_t lparen_loc
SuperNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_node * block
SuperNode::block.
pm_location_t 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.