6#include "prism/internal/allocator.h"
7#include "prism/internal/arena.h"
8#include "prism/internal/bit.h"
9#include "prism/internal/buffer.h"
10#include "prism/internal/char.h"
11#include "prism/internal/comments.h"
12#include "prism/internal/constant_pool.h"
13#include "prism/internal/diagnostic.h"
14#include "prism/internal/encoding.h"
15#include "prism/internal/integer.h"
16#include "prism/internal/isinf.h"
17#include "prism/internal/line_offset_list.h"
18#include "prism/internal/list.h"
19#include "prism/internal/magic_comments.h"
20#include "prism/internal/memchr.h"
21#include "prism/internal/node.h"
22#include "prism/internal/oom.h"
23#include "prism/internal/options.h"
24#include "prism/internal/parser.h"
25#include "prism/internal/regexp.h"
26#include "prism/internal/serialize.h"
27#include "prism/internal/source.h"
28#include "prism/internal/static_literals.h"
29#include "prism/internal/stringy.h"
30#include "prism/internal/strncasecmp.h"
31#include "prism/internal/strpbrk.h"
32#include "prism/internal/tokens.h"
52#ifndef PRISM_DEPTH_MAXIMUM
53 #define PRISM_DEPTH_MAXIMUM 10000
60#define PM_CONCATENATE(left, right) left ## right
67#if defined(_Static_assert)
68# define PM_STATIC_ASSERT(line, condition, message) _Static_assert(condition, message)
70# define PM_STATIC_ASSERT(line, condition, message) typedef char PM_CONCATENATE(static_assert_, line)[(condition) ? 1 : -1]
85#define PM_TAB_WHITESPACE_SIZE 8
88#define MIN(a,b) (((a)<(b))?(a):(b))
89#define MAX(a,b) (((a)>(b))?(a):(b))
95#define U32(value_) ((uint32_t) (value_))
97#define FL PM_NODE_FLAGS
98#define UP PM_NODE_UPCAST
100#define PM_TOKEN_START(parser_, token_) U32((token_)->start - (parser_)->start)
101#define PM_TOKEN_END(parser_, token_) U32((token_)->end - (parser_)->start)
102#define PM_TOKEN_LENGTH(token_) U32((token_)->end - (token_)->start)
103#define PM_TOKENS_LENGTH(left_, right_) U32((right_)->end - (left_)->start)
105#define PM_NODE_START(node_) (UP(node_)->location.start)
106#define PM_NODE_LENGTH(node_) (UP(node_)->location.length)
107#define PM_NODE_END(node_) (UP(node_)->location.start + UP(node_)->location.length)
108#define PM_NODES_LENGTH(left_, right_) (PM_NODE_END(right_) - PM_NODE_START(left_))
110#define PM_TOKEN_NODE_LENGTH(parser_, token_, node_) (PM_NODE_END(node_) - PM_TOKEN_START(parser_, token_))
111#define PM_NODE_TOKEN_LENGTH(parser_, node_, token_) (PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
113#define PM_NODE_START_SET_NODE(left_, right_) (PM_NODE_START(left_) = PM_NODE_START(right_))
114#define PM_NODE_START_SET_TOKEN(parser_, node_, token_) (PM_NODE_START(node_) = PM_TOKEN_START(parser_, token_))
115#define PM_NODE_LENGTH_SET_NODE(left_, right_) (PM_NODE_LENGTH(left_) = PM_NODE_END(right_) - PM_NODE_START(left_))
116#define PM_NODE_LENGTH_SET_TOKEN(parser_, node_, token_) (PM_NODE_LENGTH(node_) = PM_TOKEN_END(parser_, token_) - PM_NODE_START(node_))
117#define PM_NODE_LENGTH_SET_LOCATION(node_, location_) (PM_NODE_LENGTH(node_) = PM_LOCATION_END(location_) - PM_NODE_START(node_))
127pm_location_init(uint32_t start, uint32_t length) {
132#define PM_LOCATION_INIT(start_, length_) pm_location_init((start_), (length_))
133#define PM_LOCATION_INIT_UNSET PM_LOCATION_INIT(0, 0)
134#define PM_LOCATION_INIT_TOKEN(parser_, token_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_))
135#define PM_LOCATION_INIT_NODE(node_) UP(node_)->location
137#define PM_LOCATION_INIT_TOKENS(parser_, left_, right_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, left_), PM_TOKENS_LENGTH(left_, right_))
138#define PM_LOCATION_INIT_NODES(left_, right_) PM_LOCATION_INIT(PM_NODE_START(left_), PM_NODES_LENGTH(left_, right_))
139#define PM_LOCATION_INIT_TOKEN_NODE(parser_, token_, node_) PM_LOCATION_INIT(PM_TOKEN_START(parser_, token_), PM_TOKEN_NODE_LENGTH(parser_, token_, node_))
140#define PM_LOCATION_INIT_NODE_TOKEN(parser_, node_, token_) PM_LOCATION_INIT(PM_NODE_START(node_), PM_NODE_TOKEN_LENGTH(parser_, node_, token_))
142#define TOK2LOC(parser_, token_) PM_LOCATION_INIT_TOKEN(parser_, token_)
143#define NTOK2LOC(parser_, token_) ((token_) == NULL ? PM_LOCATION_INIT_UNSET : TOK2LOC(parser_, token_))
144#define NTOK2PTR(token_) ((token_).start == NULL ? NULL : &(token_))
155lex_mode_incrementor(
const uint8_t start) {
172lex_mode_terminator(
const uint8_t start) {
196 parser->lex_modes.free = next->prev;
201 lex_mode.prev = parser->lex_modes.current;
203 parser->lex_modes.current = next;
210lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
211 uint8_t incrementor = lex_mode_incrementor(delimiter);
212 uint8_t terminator = lex_mode_terminator(delimiter);
218 .interpolation = interpolation,
221 .incrementor = incrementor,
222 .terminator = terminator
228 uint8_t *breakpoints = lex_mode.as.list.breakpoints;
229 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
230 memcpy(breakpoints,
"\\ \t\f\r\v\n",
sizeof(
"\\ \t\f\r\v\n") - 1);
235 if (terminator !=
'\0') {
236 breakpoints[index++] = terminator;
242 breakpoints[index++] =
'#';
246 if (incrementor !=
'\0') {
247 breakpoints[index++] = incrementor;
250 parser->explicit_encoding = NULL;
251 lex_mode_push(parser, lex_mode);
261 lex_mode_push_list(parser,
false,
'\0');
268lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
270 .mode = PM_LEX_REGEXP,
273 .incrementor = incrementor,
274 .terminator = terminator
281 uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
282 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
283 memcpy(breakpoints,
"\r\n\\#",
sizeof(
"\r\n\\#") - 1);
287 if (terminator !=
'\0') {
288 breakpoints[index++] = terminator;
292 if (incrementor !=
'\0') {
293 breakpoints[index++] = incrementor;
296 parser->explicit_encoding = NULL;
297 lex_mode_push(parser, lex_mode);
304lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
306 .mode = PM_LEX_STRING,
309 .interpolation = interpolation,
310 .label_allowed = label_allowed,
311 .incrementor = incrementor,
312 .terminator = terminator
318 uint8_t *breakpoints = lex_mode.as.string.breakpoints;
319 memset(breakpoints, 0, PM_STRPBRK_CACHE_SIZE);
320 memcpy(breakpoints,
"\r\n\\",
sizeof(
"\r\n\\") - 1);
325 if (terminator !=
'\0') {
326 breakpoints[index++] = terminator;
332 breakpoints[index++] =
'#';
337 if (incrementor !=
'\0') {
338 breakpoints[index++] = incrementor;
341 parser->explicit_encoding = NULL;
342 lex_mode_push(parser, lex_mode);
352 lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
364 if (popped == &parser->lex_modes.base) {
365 popped->mode = PM_LEX_DEFAULT;
367 parser->lex_modes.current = popped->prev;
368 popped->prev = parser->lex_modes.free;
369 parser->lex_modes.free = popped;
377lex_state_p(
const pm_parser_t *parser, pm_lex_state_t state) {
378 return parser->lex_state & state;
382 PM_IGNORED_NEWLINE_NONE = 0,
383 PM_IGNORED_NEWLINE_ALL,
384 PM_IGNORED_NEWLINE_PATTERN
385} pm_ignored_newline_type_t;
389 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);
392 return PM_IGNORED_NEWLINE_ALL;
393 }
else if ((parser->lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
394 return PM_IGNORED_NEWLINE_PATTERN;
396 return PM_IGNORED_NEWLINE_NONE;
402 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));
407 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
411lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
412 if (parser->current.end >= parser->end) {
415 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->current.end);
420 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
428 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
436lex_state_set(
pm_parser_t *parser, pm_lex_state_t state) {
437 parser->lex_state = state;
440#ifndef PM_DEBUG_LOGGING
445#define PM_DEBUG_LOGGING 0
451 fprintf(stderr,
"STATE: ");
454 if (parser->lex_state == PM_LEX_STATE_NONE) {
455 fprintf(stderr,
"NONE\n");
459#define CHECK_STATE(state) \
460 if (parser->lex_state & state) { \
461 if (!first) fprintf(stderr, "|"); \
462 fprintf(stderr, "%s", #state); \
466 CHECK_STATE(PM_LEX_STATE_BEG)
467 CHECK_STATE(PM_LEX_STATE_END)
468 CHECK_STATE(PM_LEX_STATE_ENDARG)
469 CHECK_STATE(PM_LEX_STATE_ENDFN)
470 CHECK_STATE(PM_LEX_STATE_ARG)
471 CHECK_STATE(PM_LEX_STATE_CMDARG)
472 CHECK_STATE(PM_LEX_STATE_MID)
473 CHECK_STATE(PM_LEX_STATE_FNAME)
474 CHECK_STATE(PM_LEX_STATE_DOT)
475 CHECK_STATE(PM_LEX_STATE_CLASS)
476 CHECK_STATE(PM_LEX_STATE_LABEL)
477 CHECK_STATE(PM_LEX_STATE_LABELED)
478 CHECK_STATE(PM_LEX_STATE_FITEM)
482 fprintf(stderr,
"\n");
486debug_lex_state_set(
pm_parser_t *parser, pm_lex_state_t state,
char const * caller_name,
int line_number) {
487 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
489 lex_state_set(parser, state);
490 fprintf(stderr,
"Now: ");
492 fprintf(stderr,
"\n");
495#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
503#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
506#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
509#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
512#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
515#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
518#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
521#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
531pm_parser_err(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
532 pm_diagnostic_list_append(&parser->metadata_arena, &parser->error_list, start, length, diag_id);
541 pm_parser_err(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
549pm_parser_err_current(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
550 pm_parser_err_token(parser, &parser->current, diag_id);
558pm_parser_err_previous(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
559 pm_parser_err_token(parser, &parser->previous, diag_id);
568 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
574#define PM_PARSER_ERR_FORMAT(parser_, start_, length_, diag_id_, ...) \
575 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->error_list, start_, length_, diag_id_, __VA_ARGS__)
581#define PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, ...) \
582 PM_PARSER_ERR_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
588#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser_, node_, diag_id_) \
589 PM_PARSER_ERR_NODE_FORMAT(parser_, node_, diag_id_, (int) PM_NODE_LENGTH(node_), (const char *) (parser_->start + PM_NODE_START(node_)))
595#define PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id, ...) \
596 PM_PARSER_ERR_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id, __VA_ARGS__)
602#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
603 PM_PARSER_ERR_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
609pm_parser_warn(
pm_parser_t *parser, uint32_t start, uint32_t length, pm_diagnostic_id_t diag_id) {
610 pm_diagnostic_list_append(&parser->metadata_arena, &parser->warning_list, start, length, diag_id);
619 pm_parser_warn(parser, PM_TOKEN_START(parser, token), PM_TOKEN_LENGTH(token), diag_id);
628 pm_parser_warn(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), diag_id);
635#define PM_PARSER_WARN_FORMAT(parser_, start_, length_, diag_id_, ...) \
636 pm_diagnostic_list_append_format(&(parser_)->metadata_arena, &(parser_)->warning_list, start_, length_, diag_id_, __VA_ARGS__)
642#define PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, ...) \
643 PM_PARSER_WARN_FORMAT(parser_, PM_TOKEN_START(parser_, token_), PM_TOKEN_LENGTH(token_), diag_id_, __VA_ARGS__)
649#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser_, token_, diag_id_) \
650 PM_PARSER_WARN_TOKEN_FORMAT(parser_, token_, diag_id_, (int) PM_TOKEN_LENGTH(token_), (const char *) (token_)->start)
656#define PM_PARSER_WARN_NODE_FORMAT(parser_, node_, diag_id_, ...) \
657 PM_PARSER_WARN_FORMAT(parser_, PM_NODE_START(node_), PM_NODE_LENGTH(node_), diag_id_, __VA_ARGS__)
665pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
666 PM_PARSER_ERR_FORMAT(
668 U32(ident_start - parser->start),
672 (
const char *) ident_start
683#define PM_LOCALS_REUSE_CAPACITY 16
689pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
694 parser->free_scopes = scope->previous;
700 if (scope->locals.capacity > 0 && scope->locals.capacity <= PM_LOCALS_REUSE_CAPACITY) {
701 locals.capacity = scope->locals.capacity;
702 locals.locals = scope->locals.locals;
703 memset(locals.locals, 0, locals.capacity *
sizeof(
pm_local_t));
710 .previous = parser->current_scope,
712 .parameters = PM_SCOPE_PARAMETERS_NONE,
713 .implicit_parameters = { 0 },
714 .shareable_constant = parser->current_scope == NULL ? PM_SCOPE_SHAREABLE_CONSTANT_NONE : parser->current_scope->shareable_constant,
718 parser->current_scope = scope;
730 if (scope->previous == NULL)
return true;
731 if (scope->closed)
return false;
732 }
while ((scope = scope->previous) != NULL);
734 assert(
false &&
"unreachable");
742pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
745 while (depth-- > 0) {
746 assert(scope != NULL);
747 scope = scope->previous;
754 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
755 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
756 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
757} pm_scope_forwarding_param_check_result_t;
759static pm_scope_forwarding_param_check_result_t
760pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
762 bool conflict =
false;
764 while (scope != NULL) {
765 if (scope->parameters & mask) {
768 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
770 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
777 if (scope->closed)
break;
778 scope = scope->previous;
781 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
786 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
787 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
790 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
791 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
793 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
794 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
801 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
802 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
805 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
806 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
808 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
809 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
816 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
817 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
820 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
825 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
826 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
833 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
834 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
837 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
838 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
840 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
841 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
850pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
851 return parser->current_scope->shareable_constant;
859pm_parser_scope_shareable_constant_set(
pm_parser_t *parser, pm_shareable_constant_value_t shareable_constant) {
863 scope->shareable_constant = shareable_constant;
864 }
while (!scope->closed && (scope = scope->previous) != NULL);
874#define PM_LOCALS_HASH_THRESHOLD 5
882 uint32_t next_capacity = locals->capacity == 0 ? 4 : (locals->capacity * 2);
883 assert(next_capacity > locals->capacity);
887 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
888 if (locals->size > 0) {
889 memcpy(next_locals, locals->locals, locals->size *
sizeof(
pm_local_t));
894 bool hash_needed = (locals->capacity <= PM_LOCALS_HASH_THRESHOLD);
895 uint32_t mask = next_capacity - 1;
897 for (uint32_t index = 0; index < locals->capacity; index++) {
900 if (local->name != PM_CONSTANT_ID_UNSET) {
901 if (hash_needed) local->hash = pm_constant_id_hash(local->name);
903 uint32_t hash = local->hash;
904 while (next_locals[hash & mask].name != PM_CONSTANT_ID_UNSET) hash++;
905 next_locals[hash & mask] = *local;
910 locals->locals = next_locals;
911 locals->capacity = next_capacity;
931 if (locals->size >= (locals->capacity / 4 * 3)) {
932 pm_locals_resize(arena, locals);
935 locals->bloom |= (1u << (name & 31));
937 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
938 for (uint32_t index = 0; index < locals->capacity; index++) {
941 if (local->name == PM_CONSTANT_ID_UNSET) {
944 .location = { .start = start, .length = length },
945 .index = locals->size++,
950 }
else if (local->name == name) {
955 uint32_t mask = locals->capacity - 1;
956 uint32_t hash = pm_constant_id_hash(name);
957 uint32_t initial_hash = hash;
960 pm_local_t *local = &locals->locals[hash & mask];
962 if (local->name == PM_CONSTANT_ID_UNSET) {
965 .location = { .start = start, .length = length },
966 .index = locals->size++,
971 }
else if (local->name == name) {
976 }
while ((hash & mask) != initial_hash);
979 assert(
false &&
"unreachable");
989 if (!(locals->bloom & (1u << (name & 31))))
return UINT32_MAX;
991 if (locals->capacity < PM_LOCALS_HASH_THRESHOLD) {
992 for (uint32_t index = 0; index < locals->size; index++) {
994 if (local->name == name)
return index;
997 uint32_t mask = locals->capacity - 1;
998 uint32_t hash = pm_constant_id_hash(name);
999 uint32_t initial_hash = hash & mask;
1002 pm_local_t *local = &locals->locals[hash & mask];
1004 if (local->name == PM_CONSTANT_ID_UNSET) {
1006 }
else if (local->name == name) {
1011 }
while ((hash & mask) != initial_hash);
1023 uint32_t index = pm_locals_find(locals, name);
1024 assert(index != UINT32_MAX);
1027 assert(local->reads < UINT32_MAX);
1038 uint32_t index = pm_locals_find(locals, name);
1039 assert(index != UINT32_MAX);
1042 assert(local->reads > 0);
1052 uint32_t index = pm_locals_find(locals, name);
1053 assert(index != UINT32_MAX);
1055 return locals->locals[index].reads;
1068 pm_constant_id_list_init_capacity(parser->arena, list, locals->size);
1073 uint32_t capacity = locals->capacity < PM_LOCALS_HASH_THRESHOLD ? locals->size : locals->capacity;
1077 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
1079 for (uint32_t index = 0; index < capacity; index++) {
1082 if (local->name != PM_CONSTANT_ID_UNSET) {
1083 pm_constant_id_list_insert(list, (
size_t) local->index, local->name);
1085 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))) {
1089 PM_PARSER_WARN_FORMAT(
1091 local->location.
start,
1093 PM_WARN_UNUSED_LOCAL_VARIABLE,
1111pm_parser_constant_id_raw(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1114 if (start == parser->constant_cache.start && end == parser->constant_cache.end) {
1115 return parser->constant_cache.id;
1118 pm_constant_id_t id = pm_constant_pool_insert_shared(&parser->metadata_arena, &parser->constant_pool, start, (
size_t) (end - start));
1120 parser->constant_cache.start = start;
1121 parser->constant_cache.end = end;
1122 parser->constant_cache.id = id;
1131pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1132 return pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, start, length);
1139pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1140 return pm_constant_pool_insert_constant(&parser->metadata_arena, &parser->constant_pool, (
const uint8_t *) start, length);
1148 return pm_parser_constant_id_raw(parser, token->start, token->end);
1155#define PM_CASE_VOID_VALUE PM_RETURN_NODE: case PM_BREAK_NODE: case PM_NEXT_NODE: \
1156 case PM_REDO_NODE: case PM_RETRY_NODE: case PM_MATCH_REQUIRED_NODE
1167 while (node != NULL) {
1168 switch (PM_NODE_TYPE(node)) {
1169 case PM_CASE_VOID_VALUE:
1170 return void_node != NULL ? void_node : node;
1171 case PM_MATCH_PREDICATE_NODE:
1173 case PM_BEGIN_NODE: {
1176 if (
cast->ensure_clause != NULL) {
1177 if (
cast->rescue_clause != NULL) {
1178 pm_node_t *vn = pm_check_value_expression(parser, UP(
cast->rescue_clause));
1179 if (vn != NULL)
return vn;
1182 if (
cast->statements != NULL) {
1183 pm_node_t *vn = pm_check_value_expression(parser, UP(
cast->statements));
1184 if (vn != NULL)
return vn;
1187 node = UP(
cast->ensure_clause);
1188 }
else if (
cast->rescue_clause != NULL) {
1190 if (
cast->else_clause == NULL || parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1191 if (
cast->statements == NULL)
return NULL;
1193 pm_node_t *vn = pm_check_value_expression(parser, UP(
cast->statements));
1194 if (vn == NULL)
return NULL;
1195 if (void_node == NULL) void_node = vn;
1198 for (
pm_rescue_node_t *rescue_clause =
cast->rescue_clause; rescue_clause != NULL; rescue_clause = rescue_clause->subsequent) {
1199 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1203 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1211 if (
cast->else_clause != NULL) {
1212 node = UP(
cast->else_clause);
1215 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1216 pm_node_t *vn = pm_check_value_expression(parser, node);
1217 if (vn != NULL)
return vn;
1223 node = UP(
cast->statements);
1228 case PM_CASE_NODE: {
1230 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1235 if (
cast->else_clause == NULL)
return NULL;
1239 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
1242 pm_node_t *vn = pm_check_value_expression(parser, UP(
cast->statements));
1243 if (vn == NULL)
return NULL;
1244 if (void_node == NULL) void_node = vn;
1247 node = UP(
cast->else_clause);
1250 case PM_CASE_MATCH_NODE: {
1252 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
1257 if (
cast->else_clause == NULL)
return NULL;
1261 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
1264 pm_node_t *vn = pm_check_value_expression(parser, UP(
cast->statements));
1265 if (vn == NULL)
return NULL;
1266 if (void_node == NULL) void_node = vn;
1269 node = UP(
cast->else_clause);
1272 case PM_ENSURE_NODE: {
1274 node = UP(
cast->statements);
1277 case PM_PARENTHESES_NODE: {
1279 node = UP(
cast->body);
1282 case PM_STATEMENTS_NODE: {
1286 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1) {
1289 switch (PM_NODE_TYPE(body_part)) {
1290 case PM_CASE_VOID_VALUE:
1291 if (void_node == NULL) {
1292 void_node = body_part;
1300 node =
cast->body.nodes[
cast->body.size - 1];
1305 if (
cast->statements == NULL ||
cast->subsequent == NULL) {
1308 pm_node_t *vn = pm_check_value_expression(parser, UP(
cast->statements));
1312 if (void_node == NULL) {
1315 node =
cast->subsequent;
1318 case PM_UNLESS_NODE: {
1320 if (
cast->statements == NULL ||
cast->else_clause == NULL) {
1323 pm_node_t *vn = pm_check_value_expression(parser, UP(
cast->statements));
1327 if (void_node == NULL) {
1330 node = UP(
cast->else_clause);
1333 case PM_ELSE_NODE: {
1335 node = UP(
cast->statements);
1346 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1350 for (uint32_t depth = 0; depth <
cast->depth; depth++) scope = scope->previous;
1352 pm_locals_read(&scope->locals,
cast->name);
1365 pm_node_t *void_node = pm_check_value_expression(parser, node);
1366 if (void_node != NULL) {
1367 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1376 const char *
type = NULL;
1379 switch (PM_NODE_TYPE(node)) {
1380 case PM_BACK_REFERENCE_READ_NODE:
1381 case PM_CLASS_VARIABLE_READ_NODE:
1382 case PM_GLOBAL_VARIABLE_READ_NODE:
1383 case PM_INSTANCE_VARIABLE_READ_NODE:
1384 case PM_LOCAL_VARIABLE_READ_NODE:
1385 case PM_NUMBERED_REFERENCE_READ_NODE:
1386 type =
"a variable";
1389 case PM_CALL_NODE: {
1391 if (
cast->call_operator_loc.length > 0 ||
cast->message_loc.length == 0)
break;
1393 const pm_constant_t *message = pm_constant_pool_id_to_constant(&parser->constant_pool,
cast->name);
1394 switch (message->length) {
1396 switch (message->start[0]) {
1407 type = (
const char *) message->start;
1413 switch (message->start[1]) {
1415 if (message->start[0] ==
'<' || message->start[0] ==
'>' || message->start[0] ==
'!' || message->start[0] ==
'=') {
1416 type = (
const char *) message->start;
1421 if (message->start[0] ==
'+' || message->start[0] ==
'-') {
1422 type = (
const char *) message->start;
1427 if (message->start[0] ==
'*') {
1428 type = (
const char *) message->start;
1435 if (memcmp(message->start,
"<=>", 3) == 0) {
1444 case PM_CONSTANT_PATH_NODE:
1448 case PM_CONSTANT_READ_NODE:
1449 type =
"a constant";
1452 case PM_DEFINED_NODE:
1461 case PM_IMAGINARY_NODE:
1462 case PM_INTEGER_NODE:
1463 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1464 case PM_INTERPOLATED_STRING_NODE:
1465 case PM_RATIONAL_NODE:
1466 case PM_REGULAR_EXPRESSION_NODE:
1467 case PM_SOURCE_ENCODING_NODE:
1468 case PM_SOURCE_FILE_NODE:
1469 case PM_SOURCE_LINE_NODE:
1470 case PM_STRING_NODE:
1471 case PM_SYMBOL_NODE:
1479 case PM_RANGE_NODE: {
1482 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1505 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1516 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1517 for (
size_t index = 0; index < size; index++) {
1518 pm_void_statement_check(parser, node->
body.
nodes[index]);
1528 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1529 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1530 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1531} pm_conditional_predicate_type_t;
1537pm_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) {
1539 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1540 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1542 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1543 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1545 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1555pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1556 switch (PM_NODE_TYPE(node)) {
1557 case PM_ARRAY_NODE: {
1558 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1561 for (
size_t index = 0; index <
cast->elements.size; index++) {
1562 if (!pm_conditional_predicate_warn_write_literal_p(
cast->elements.nodes[index]))
return false;
1567 case PM_HASH_NODE: {
1568 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1571 for (
size_t index = 0; index <
cast->elements.size; index++) {
1573 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1576 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1583 case PM_IMAGINARY_NODE:
1584 case PM_INTEGER_NODE:
1586 case PM_RATIONAL_NODE:
1587 case PM_REGULAR_EXPRESSION_NODE:
1588 case PM_SOURCE_ENCODING_NODE:
1589 case PM_SOURCE_FILE_NODE:
1590 case PM_SOURCE_LINE_NODE:
1591 case PM_STRING_NODE:
1592 case PM_SYMBOL_NODE:
1606 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1607 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);
1625 switch (PM_NODE_TYPE(node)) {
1628 pm_conditional_predicate(parser,
cast->left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1629 pm_conditional_predicate(parser,
cast->right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1634 pm_conditional_predicate(parser,
cast->left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1635 pm_conditional_predicate(parser,
cast->right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1638 case PM_PARENTHESES_NODE: {
1641 if ((
cast->body != NULL) && PM_NODE_TYPE_P(
cast->body, PM_STATEMENTS_NODE)) {
1643 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1648 case PM_BEGIN_NODE: {
1650 if (
cast->statements != NULL) {
1656 case PM_RANGE_NODE: {
1659 if (
cast->left != NULL) pm_conditional_predicate(parser,
cast->left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1660 if (
cast->right != NULL) pm_conditional_predicate(parser,
cast->right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1668 node->
type = PM_FLIP_FLOP_NODE;
1672 case PM_REGULAR_EXPRESSION_NODE:
1677 node->
type = PM_MATCH_LAST_LINE_NODE;
1679 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1680 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1684 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1689 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1691 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1692 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1696 case PM_INTEGER_NODE:
1697 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1698 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1699 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1702 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1705 case PM_STRING_NODE:
1706 case PM_SOURCE_FILE_NODE:
1707 case PM_INTERPOLATED_STRING_NODE:
1708 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1710 case PM_SYMBOL_NODE:
1711 case PM_INTERPOLATED_SYMBOL_NODE:
1712 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1714 case PM_SOURCE_LINE_NODE:
1715 case PM_SOURCE_ENCODING_NODE:
1717 case PM_RATIONAL_NODE:
1718 case PM_IMAGINARY_NODE:
1719 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1721 case PM_CLASS_VARIABLE_WRITE_NODE:
1724 case PM_CONSTANT_WRITE_NODE:
1727 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1730 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1733 case PM_LOCAL_VARIABLE_WRITE_NODE:
1736 case PM_MULTI_WRITE_NODE:
1772 if (arguments->
block != NULL) {
1773 uint32_t end = PM_NODE_END(arguments->
block);
1776 uint32_t arguments_end = PM_LOCATION_END(&arguments->
closing_loc);
1777 if (arguments_end > end) {
1820 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1834char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1835 if (n <= 0)
return 0;
1837 if (parser->encoding_changed) {
1840 if ((width = parser->encoding->alpha_char(b, n)) != 0) {
1842 }
else if (*b ==
'_') {
1844 }
else if (*b >= 0x80) {
1845 return parser->encoding->char_width(b, n);
1849 }
else if (*b < 0x80) {
1850 return (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHABETIC_BIT ? 1 : 0) || (*b ==
'_');
1852 return pm_encoding_utf_8_char_width(b, n);
1861char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1864 }
else if (*b < 0x80) {
1865 return (*b ==
'_') || (pm_encoding_unicode_table[*b] & PRISM_ENCODING_ALPHANUMERIC_BIT ? 1 : 0);
1867 return pm_encoding_utf_8_char_width(b, n);
1884#if defined(PRISM_HAS_NEON)
1885#include <arm_neon.h>
1888scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1889 const uint8_t *cursor = start;
1896 static const uint8_t low_lut_data[16] = {
1897 0x15, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F,
1898 0x1F, 0x1F, 0x1E, 0x0A, 0x0A, 0x0A, 0x0A, 0x0E
1900 static const uint8_t high_lut_data[16] = {
1901 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10,
1902 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1904 const uint8x16_t low_lut = vld1q_u8(low_lut_data);
1905 const uint8x16_t high_lut = vld1q_u8(high_lut_data);
1906 const uint8x16_t mask_0f = vdupq_n_u8(0x0F);
1908 while (cursor + 16 <= end) {
1909 uint8x16_t v = vld1q_u8(cursor);
1911 uint8x16_t lo_class = vqtbl1q_u8(low_lut, vandq_u8(v, mask_0f));
1912 uint8x16_t hi_class = vqtbl1q_u8(high_lut, vshrq_n_u8(v, 4));
1913 uint8x16_t ident = vandq_u8(lo_class, hi_class);
1916 if (vminvq_u8(ident) != 0) {
1922 uint8x16_t is_zero = vceqq_u8(ident, vdupq_n_u8(0));
1923 uint64_t lo = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 0);
1926 cursor += pm_ctzll(lo) / 8;
1928 uint64_t hi = vgetq_lane_u64(vreinterpretq_u64_u8(is_zero), 1);
1929 cursor += 8 + pm_ctzll(hi) / 8;
1932 return (
size_t) (cursor - start);
1935 return (
size_t) (cursor - start);
1938#elif defined(PRISM_HAS_SSE2)
1939#include <emmintrin.h>
1942scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1943 const uint8_t *cursor = start;
1945 while (cursor + 16 <= end) {
1946 __m128i v = _mm_loadu_si128((
const __m128i *) cursor);
1947 __m128i zero = _mm_setzero_si128();
1954 __m128i lowered = _mm_or_si128(v, _mm_set1_epi8(0x20));
1955 __m128i letter = _mm_and_si128(
1956 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x61), lowered), zero),
1957 _mm_cmpeq_epi8(_mm_subs_epu8(lowered, _mm_set1_epi8(0x7A)), zero));
1959 __m128i digit = _mm_and_si128(
1960 _mm_cmpeq_epi8(_mm_subs_epu8(_mm_set1_epi8(0x30), v), zero),
1961 _mm_cmpeq_epi8(_mm_subs_epu8(v, _mm_set1_epi8(0x39)), zero));
1963 __m128i underscore = _mm_cmpeq_epi8(v, _mm_set1_epi8(0x5F));
1965 __m128i ident = _mm_or_si128(_mm_or_si128(letter, digit), underscore);
1966 int mask = _mm_movemask_epi8(ident);
1968 if (mask == 0xFFFF) {
1973 cursor += pm_ctzll((uint64_t) (~mask & 0xFFFF));
1974 return (
size_t) (cursor - start);
1977 return (
size_t) (cursor - start);
1984#elif defined(PRISM_HAS_SWAR)
1996scan_identifier_ascii(
const uint8_t *start,
const uint8_t *end) {
1997 static const uint64_t ones = 0x0101010101010101ULL;
1998 static const uint64_t highs = 0x8080808080808080ULL;
1999 const uint8_t *cursor = start;
2001 while (cursor + 8 <= end) {
2003 memcpy(&word, cursor, 8);
2006 if (word & highs)
break;
2008 uint64_t digit = ((word | highs) - ones * 0x30) & ((ones * 0x39 | highs) - word) & highs;
2015 uint64_t lowered = word | (ones * 0x20);
2016 uint64_t letter = ((lowered | highs) - ones * 0x61) & ((ones * 0x7A | highs) - lowered) & highs;
2021 uint64_t xor_us = word ^ (ones * 0x5F);
2022 uint64_t underscore = (xor_us - ones) & ~xor_us & highs;
2024 uint64_t ident = digit | letter | underscore;
2026 if (ident == highs) {
2033 uint64_t not_ident = ~ident & highs;
2034 cursor += pm_ctzll(not_ident) / 8;
2035 return (
size_t) (cursor - start);
2038 return (
size_t) (cursor - start);
2045#define scan_identifier_ascii(start, end) ((size_t) 0)
2055char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
2058 }
else if (parser->encoding_changed) {
2061 if ((width = parser->encoding->alnum_char(b, n)) != 0) {
2063 }
else if (*b ==
'_') {
2065 }
else if (*b >= 0x80) {
2066 return parser->encoding->char_width(b, n);
2071 return char_is_identifier_utf8(b, n);
2078#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
2079#define PUNCT(idx) ( \
2080 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
2081 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
2082 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
2083 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
2084 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
2087const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
2092static PRISM_INLINE bool
2093char_is_global_name_punctuation(const uint8_t b) {
2094 const unsigned int i = (const unsigned int) b;
2095 if (i <= 0x20 || 0x7e < i) return false;
2097 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
2100static PRISM_INLINE bool
2101token_is_setter_name(pm_token_t *token) {
2103 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
2104 ((token->type == PM_TOKEN_IDENTIFIER) &&
2105 (token->end - token->start >= 2) &&
2106 (token->end[-1] == '='))
2114pm_local_is_keyword(const char *source, size_t length) {
2115#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
2119 switch (source[0]) {
2120 case 'd': KEYWORD("do"); return false;
2121 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
2122 case 'o': KEYWORD("or"); return false;
2123 default: return false;
2126 switch (source[0]) {
2127 case 'a': KEYWORD("and"); return false;
2128 case 'd': KEYWORD("def"); return false;
2129 case 'e': KEYWORD("end"); return false;
2130 case 'f': KEYWORD("for"); return false;
2131 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
2132 default: return false;
2135 switch (source[0]) {
2136 case 'c': KEYWORD("case"); return false;
2137 case 'e': KEYWORD("else"); return false;
2138 case 'n': KEYWORD("next"); return false;
2139 case 'r': KEYWORD("redo"); return false;
2140 case 's': KEYWORD("self"); return false;
2141 case 't': KEYWORD("then"); KEYWORD("true"); return false;
2142 case 'w': KEYWORD("when"); return false;
2143 default: return false;
2146 switch (source[0]) {
2147 case 'a': KEYWORD("alias"); return false;
2148 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
2149 case 'c': KEYWORD("class"); return false;
2150 case 'e': KEYWORD("elsif"); return false;
2151 case 'f': KEYWORD("false"); return false;
2152 case 'r': KEYWORD("retry"); return false;
2153 case 's': KEYWORD("super"); return false;
2154 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
2155 case 'w': KEYWORD("while"); return false;
2156 case 'y': KEYWORD("yield"); return false;
2157 default: return false;
2160 switch (source[0]) {
2161 case 'e': KEYWORD("ensure"); return false;
2162 case 'm': KEYWORD("module"); return false;
2163 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
2164 case 'u': KEYWORD("unless"); return false;
2165 default: return false;
2168 KEYWORD("__LINE__");
2169 KEYWORD("__FILE__");
2172 KEYWORD("__ENCODING__");
2181/******************************************************************************/
2182/* Node flag handling functions */
2183/******************************************************************************/
2188static PRISM_INLINE void
2189pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
2190 node->flags |= flag;
2196static PRISM_INLINE void
2197pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
2198 node->flags &= (pm_node_flags_t) ~flag;
2204static PRISM_INLINE void
2205pm_node_flag_set_repeated_parameter(pm_node_t *node) {
2206 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
2207 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
2208 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
2209 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
2210 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
2211 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
2212 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
2213 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
2215 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
2218/******************************************************************************/
2219/* Node creation functions */
2220/******************************************************************************/
2227#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)
2232static PRISM_INLINE pm_node_flags_t
2233pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
2234 pm_node_flags_t flags = 0;
2236 if (closing->type == PM_TOKEN_REGEXP_END) {
2237 pm_buffer_t unknown_flags = { 0 };
2239 // The closing delimiter is normally a single byte, so the options
2240 // follow it. A `\r\n` newline delimiter is two bytes, however, so we
2241 // skip past it to avoid misreading the trailing `\n` as an option.
2242 const uint8_t *flag = closing->start + 1;
2243 if ((closing->end - closing->start) >= 2 && closing->start[0] == '\r' && closing->start[1] == '\n') {
2247 for (; flag < closing->end; flag++) {
2249 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
2250 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
2251 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
2252 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
2254 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
2255 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
2256 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
2257 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
2259 default: pm_buffer_append_byte(&unknown_flags, *flag);
2263 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
2264 if (unknown_flags_length != 0) {
2265 const char *word = unknown_flags_length >= 2 ? "options" : "option";
2266 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
2268 pm_buffer_cleanup(&unknown_flags);
2274#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
2276static pm_statements_node_t *
2277pm_statements_node_create(pm_parser_t *parser);
2280pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
2283pm_statements_node_body_length(pm_statements_node_t *node);
2289static PRISM_INLINE void
2290pm_integer_arena_move(pm_arena_t *arena, pm_integer_t *integer) {
2291 if (integer->values != NULL) {
2292 size_t byte_size = integer->length * sizeof(uint32_t);
2293 uint32_t *old_values = integer->values;
2294 integer->values = (uint32_t *) pm_arena_memdup(arena, old_values, byte_size, PRISM_ALIGNOF(uint32_t));
2302static pm_error_recovery_node_t *
2303pm_error_recovery_node_create(pm_parser_t *parser, uint32_t start, uint32_t length) {
2304 return pm_error_recovery_node_new(
2308 ((pm_location_t) { .start = start, .length = length }),
2316static pm_error_recovery_node_t *
2317pm_error_recovery_node_create_unexpected(pm_parser_t *parser, pm_node_t *unexpected) {
2318 return pm_error_recovery_node_new(
2322 unexpected->location,
2330static pm_alias_global_variable_node_t *
2331pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2332 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2334 return pm_alias_global_variable_node_new(
2338 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2341 TOK2LOC(parser, keyword)
2348static pm_alias_method_node_t *
2349pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
2350 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
2352 return pm_alias_method_node_new(
2356 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, old_name),
2359 TOK2LOC(parser, keyword)
2366static pm_alternation_pattern_node_t *
2367pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2368 return pm_alternation_pattern_node_new(
2372 PM_LOCATION_INIT_NODES(left, right),
2375 TOK2LOC(parser, operator)
2382static pm_and_node_t *
2383pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2384 pm_assert_value_expression(parser, left);
2386 return pm_and_node_new(
2390 PM_LOCATION_INIT_NODES(left, right),
2393 TOK2LOC(parser, operator)
2400static pm_arguments_node_t *
2401pm_arguments_node_create(pm_parser_t *parser) {
2402 return pm_arguments_node_new(
2406 PM_LOCATION_INIT_UNSET,
2407 ((pm_node_list_t) { 0 })
2415pm_arguments_node_size(pm_arguments_node_t *node) {
2416 return node->arguments.size;
2423pm_arguments_node_arguments_append(pm_arena_t *arena, pm_arguments_node_t *node, pm_node_t *argument) {
2424 if (pm_arguments_node_size(node) == 0) {
2425 PM_NODE_START_SET_NODE(node, argument);
2428 if (PM_NODE_END(node) < PM_NODE_END(argument)) {
2429 PM_NODE_LENGTH_SET_NODE(node, argument);
2432 pm_node_list_append_inline(arena, &node->arguments, argument);
2434 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2435 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2436 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2438 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2446static pm_array_node_t *
2447pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2448 if (opening == NULL) {
2449 return pm_array_node_new(
2452 PM_NODE_FLAG_STATIC_LITERAL,
2453 PM_LOCATION_INIT_UNSET,
2454 ((pm_node_list_t) { 0 }),
2455 ((pm_location_t) { 0 }),
2456 ((pm_location_t) { 0 })
2459 return pm_array_node_new(
2462 PM_NODE_FLAG_STATIC_LITERAL,
2463 PM_LOCATION_INIT_TOKEN(parser, opening),
2464 ((pm_node_list_t) { 0 }),
2465 TOK2LOC(parser, opening),
2466 TOK2LOC(parser, opening)
2474static PRISM_INLINE void
2475pm_array_node_elements_append(pm_arena_t *arena, pm_array_node_t *node, pm_node_t *element) {
2476 if (!node->elements.size && !node->opening_loc.length) {
2477 PM_NODE_START_SET_NODE(node, element);
2480 pm_node_list_append_inline(arena, &node->elements, element);
2481 PM_NODE_LENGTH_SET_NODE(node, element);
2483 // If the element is not a static literal, then the array is not a static
2484 // literal. Turn that flag off.
2485 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)) {
2486 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2489 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2490 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2498pm_array_node_close_set(const pm_parser_t *parser, pm_array_node_t *node, const pm_token_t *closing) {
2499 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == 0);
2500 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2501 node->closing_loc = TOK2LOC(parser, closing);
2508static pm_array_pattern_node_t *
2509pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2510 pm_array_pattern_node_t *node = pm_array_pattern_node_new(
2514 PM_LOCATION_INIT_NODES(nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2516 ((pm_node_list_t) { 0 }),
2518 ((pm_node_list_t) { 0 }),
2519 ((pm_location_t) { 0 }),
2520 ((pm_location_t) { 0 })
2523 // For now we're going to just copy over each pointer manually. This could be
2524 // much more efficient, as we could instead resize the node list.
2525 bool found_rest = false;
2528 PM_NODE_LIST_FOREACH(nodes, index, child) {
2529 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2532 } else if (found_rest) {
2533 pm_node_list_append_inline(parser->arena, &node->posts, child);
2535 pm_node_list_append_inline(parser->arena, &node->requireds, child);
2545static pm_array_pattern_node_t *
2546pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2547 return pm_array_pattern_node_new(
2551 PM_LOCATION_INIT_NODE(rest),
2553 ((pm_node_list_t) { 0 }),
2555 ((pm_node_list_t) { 0 }),
2556 ((pm_location_t) { 0 }),
2557 ((pm_location_t) { 0 })
2565static pm_array_pattern_node_t *
2566pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2567 return pm_array_pattern_node_new(
2571 PM_LOCATION_INIT_NODE_TOKEN(parser, constant, closing),
2573 ((pm_node_list_t) { 0 }),
2575 ((pm_node_list_t) { 0 }),
2576 TOK2LOC(parser, opening),
2577 TOK2LOC(parser, closing)
2585static pm_array_pattern_node_t *
2586pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2587 return pm_array_pattern_node_new(
2591 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2593 ((pm_node_list_t) { 0 }),
2595 ((pm_node_list_t) { 0 }),
2596 TOK2LOC(parser, opening),
2597 TOK2LOC(parser, closing)
2601static PRISM_INLINE void
2602pm_array_pattern_node_requireds_append(pm_arena_t *arena, pm_array_pattern_node_t *node, pm_node_t *inner) {
2603 pm_node_list_append_inline(arena, &node->requireds, inner);
2609static pm_assoc_node_t *
2610pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2613 if (value != NULL && PM_NODE_END(value) > PM_NODE_END(key)) {
2614 end = PM_NODE_END(value);
2615 } else if (operator != NULL) {
2616 end = PM_TOKEN_END(parser, operator);
2618 end = PM_NODE_END(key);
2621 // Hash string keys will be frozen, so we can mark them as frozen here so
2622 // that the compiler picks them up and also when we check for static literal
2623 // on the keys it gets factored in.
2624 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2625 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2628 // If the key and value of this assoc node are both static literals, then
2629 // we can mark this node as a static literal.
2630 pm_node_flags_t flags = 0;
2632 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2633 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)
2635 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2638 return pm_assoc_node_new(
2642 ((pm_location_t) { .start = PM_NODE_START(key), .length = U32(end - PM_NODE_START(key)) }),
2645 NTOK2LOC(parser, operator)
2652static pm_assoc_splat_node_t *
2653pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2654 assert(operator->type == PM_TOKEN_USTAR_STAR);
2656 return pm_assoc_splat_node_new(
2660 (value == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, value),
2662 TOK2LOC(parser, operator)
2669static pm_back_reference_read_node_t *
2670pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2671 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2673 return pm_back_reference_read_node_new(
2677 PM_LOCATION_INIT_TOKEN(parser, name),
2678 pm_parser_constant_id_token(parser, name)
2685static pm_begin_node_t *
2686pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2687 uint32_t start = begin_keyword == NULL ? 0 : PM_TOKEN_START(parser, begin_keyword);
2688 uint32_t end = statements == NULL ? (begin_keyword == NULL ? 0 : PM_TOKEN_END(parser, begin_keyword)) : PM_NODE_END(statements);
2690 return pm_begin_node_new(
2694 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2695 NTOK2LOC(parser, begin_keyword),
2700 ((pm_location_t) { 0 })
2708pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2709 if (node->begin_keyword_loc.length == 0) {
2710 PM_NODE_START_SET_NODE(node, rescue_clause);
2712 PM_NODE_LENGTH_SET_NODE(node, rescue_clause);
2713 node->rescue_clause = rescue_clause;
2720pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2721 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2722 PM_NODE_START_SET_NODE(node, else_clause);
2724 PM_NODE_LENGTH_SET_NODE(node, else_clause);
2725 node->else_clause = else_clause;
2732pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2733 if ((node->begin_keyword_loc.length == 0) && PM_NODE_START(node) == 0) {
2734 PM_NODE_START_SET_NODE(node, ensure_clause);
2736 PM_NODE_LENGTH_SET_NODE(node, ensure_clause);
2737 node->ensure_clause = ensure_clause;
2744pm_begin_node_end_keyword_set(const pm_parser_t *parser, pm_begin_node_t *node, const pm_token_t *end_keyword) {
2745 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == 0);
2746 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
2747 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
2753static pm_block_argument_node_t *
2754pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2755 assert(operator->type == PM_TOKEN_UAMPERSAND);
2757 return pm_block_argument_node_new(
2761 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
2763 TOK2LOC(parser, operator)
2770static pm_block_node_t *
2771pm_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) {
2772 return pm_block_node_new(
2776 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
2780 TOK2LOC(parser, opening),
2781 TOK2LOC(parser, closing)
2788static pm_block_parameter_node_t *
2789pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2790 assert(operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2792 return pm_block_parameter_node_new(
2796 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
2797 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
2798 NTOK2LOC(parser, name),
2799 TOK2LOC(parser, operator)
2806static pm_block_parameters_node_t *
2807pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2809 if (opening != NULL) {
2810 start = PM_TOKEN_START(parser, opening);
2811 } else if (parameters != NULL) {
2812 start = PM_NODE_START(parameters);
2818 if (parameters != NULL) {
2819 end = PM_NODE_END(parameters);
2820 } else if (opening != NULL) {
2821 end = PM_TOKEN_END(parser, opening);
2826 return pm_block_parameters_node_new(
2830 ((pm_location_t) { .start = start, .length = U32(end - start) }),
2832 ((pm_node_list_t) { 0 }),
2833 NTOK2LOC(parser, opening),
2834 ((pm_location_t) { 0 })
2842pm_block_parameters_node_closing_set(const pm_parser_t *parser, pm_block_parameters_node_t *node, const pm_token_t *closing) {
2843 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == 0);
2844 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
2845 node->closing_loc = TOK2LOC(parser, closing);
2851static pm_block_local_variable_node_t *
2852pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2853 return pm_block_local_variable_node_new(
2857 PM_LOCATION_INIT_TOKEN(parser, name),
2858 pm_parser_constant_id_token(parser, name)
2866pm_block_parameters_node_append_local(pm_arena_t *arena, pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2867 pm_node_list_append_inline(arena, &node->locals, UP(local));
2869 if (PM_NODE_LENGTH(node) == 0) {
2870 PM_NODE_START_SET_NODE(node, local);
2873 PM_NODE_LENGTH_SET_NODE(node, local);
2879static pm_break_node_t *
2880pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2881 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2883 return pm_break_node_new(
2887 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
2889 TOK2LOC(parser, keyword)
2893// There are certain flags that we want to use internally but don't want to
2894// expose because they are not relevant beyond parsing. Therefore we'll define
2895// them here and not define them in config.yml/a header file.
2896static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2898static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2899static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2900static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2907static pm_call_node_t *
2908pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2909 return pm_call_node_new(
2913 PM_LOCATION_INIT_UNSET,
2915 ((pm_location_t) { 0 }),
2917 ((pm_location_t) { 0 }),
2918 ((pm_location_t) { 0 }),
2920 ((pm_location_t) { 0 }),
2921 ((pm_location_t) { 0 }),
2930static PRISM_INLINE pm_node_flags_t
2931pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2932 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2939static pm_call_node_t *
2940pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2941 pm_assert_value_expression(parser, receiver);
2943 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2944 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2945 flags |= PM_CALL_NODE_FLAGS_INDEX;
2948 pm_call_node_t *node = pm_call_node_create(parser, flags);
2950 PM_NODE_START_SET_NODE(node, receiver);
2952 const pm_location_t *end = pm_arguments_end(arguments);
2953 assert(end != NULL && "unreachable");
2954 PM_NODE_LENGTH_SET_LOCATION(node, end);
2956 node->receiver = receiver;
2957 node->message_loc.start = arguments->opening_loc.start;
2958 node->message_loc.length = (arguments->closing_loc.start + arguments->closing_loc.length) - arguments->opening_loc.start;
2960 node->opening_loc = arguments->opening_loc;
2961 node->arguments = arguments->arguments;
2962 node->closing_loc = arguments->closing_loc;
2963 node->block = arguments->block;
2965 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2972static pm_call_node_t *
2973pm_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) {
2974 pm_assert_value_expression(parser, receiver);
2975 pm_assert_value_expression(parser, argument);
2977 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2979 PM_NODE_START_SET_NODE(node, PM_NODE_START(receiver) < PM_NODE_START(argument) ? receiver : argument);
2980 PM_NODE_LENGTH_SET_NODE(node, PM_NODE_END(receiver) > PM_NODE_END(argument) ? receiver : argument);
2982 node->receiver = receiver;
2983 node->message_loc = TOK2LOC(parser, operator);
2985 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2986 pm_arguments_node_arguments_append(parser->arena, arguments, argument);
2987 node->arguments = arguments;
2989 node->name = pm_parser_constant_id_token(parser, operator);
2993static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
2998static pm_call_node_t *
2999pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
3000 pm_assert_value_expression(parser, receiver);
3002 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3004 PM_NODE_START_SET_NODE(node, receiver);
3005 const pm_location_t *end = pm_arguments_end(arguments);
3007 PM_NODE_LENGTH_SET_TOKEN(parser, node, message);
3009 PM_NODE_LENGTH_SET_LOCATION(node, end);
3012 node->receiver = receiver;
3013 node->call_operator_loc = TOK2LOC(parser, operator);
3014 node->message_loc = TOK2LOC(parser, message);
3015 node->opening_loc = arguments->opening_loc;
3016 node->arguments = arguments->arguments;
3017 node->closing_loc = arguments->closing_loc;
3018 node->block = arguments->block;
3020 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3021 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3028 node->name = pm_parser_constant_id_raw(parser, message->start, parse_operator_symbol_name(message));
3035static pm_call_node_t *
3036pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
3037 pm_call_node_t *node = pm_call_node_create(parser, 0);
3038 node->base.location = (pm_location_t) { .start = 0, .length = U32(parser->end - parser->start) };
3040 node->receiver = receiver;
3041 node->arguments = arguments;
3043 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
3051static pm_call_node_t *
3052pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
3053 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3055 PM_NODE_START_SET_TOKEN(parser, node, message);
3056 const pm_location_t *end = pm_arguments_end(arguments);
3057 assert(end != NULL && "unreachable");
3058 PM_NODE_LENGTH_SET_LOCATION(node, end);
3060 node->message_loc = TOK2LOC(parser, message);
3061 node->opening_loc = arguments->opening_loc;
3062 node->arguments = arguments->arguments;
3063 node->closing_loc = arguments->closing_loc;
3064 node->block = arguments->block;
3066 node->name = pm_parser_constant_id_token(parser, message);
3074static pm_call_node_t *
3075pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
3076 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3078 node->base.location = (pm_location_t) { 0 };
3079 node->arguments = arguments;
3088static pm_call_node_t *
3089pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
3090 pm_assert_value_expression(parser, receiver);
3091 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
3093 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
3095 PM_NODE_START_SET_TOKEN(parser, node, message);
3096 if (arguments->closing_loc.length > 0) {
3097 PM_NODE_LENGTH_SET_LOCATION(node, &arguments->closing_loc);
3099 assert(receiver != NULL);
3100 PM_NODE_LENGTH_SET_NODE(node, receiver);
3103 node->receiver = receiver;
3104 node->message_loc = TOK2LOC(parser, message);
3105 node->opening_loc = arguments->opening_loc;
3106 node->arguments = arguments->arguments;
3107 node->closing_loc = arguments->closing_loc;
3109 node->name = pm_parser_constant_id_constant(parser, "!", 1);
3116static pm_call_node_t *
3117pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
3118 pm_assert_value_expression(parser, receiver);
3120 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3122 PM_NODE_START_SET_NODE(node, receiver);
3123 const pm_location_t *end = pm_arguments_end(arguments);
3124 assert(end != NULL && "unreachable");
3125 PM_NODE_LENGTH_SET_LOCATION(node, end);
3127 node->receiver = receiver;
3128 node->call_operator_loc = TOK2LOC(parser, operator);
3129 node->opening_loc = arguments->opening_loc;
3130 node->arguments = arguments->arguments;
3131 node->closing_loc = arguments->closing_loc;
3132 node->block = arguments->block;
3134 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
3135 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
3138 node->name = pm_parser_constant_id_constant(parser, "call", 4);
3145static pm_call_node_t *
3146pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
3147 pm_assert_value_expression(parser, receiver);
3149 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
3151 PM_NODE_START_SET_TOKEN(parser, node, operator);
3152 PM_NODE_LENGTH_SET_NODE(node, receiver);
3154 node->receiver = receiver;
3155 node->message_loc = TOK2LOC(parser, operator);
3157 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
3165static pm_call_node_t *
3166pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
3167 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
3169 node->base.location = TOK2LOC(parser, message);
3170 node->message_loc = TOK2LOC(parser, message);
3172 node->name = pm_parser_constant_id_token(parser, message);
3180static PRISM_INLINE bool
3181pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
3183 (node->message_loc.length > 0) &&
3184 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '!') &&
3185 (parser->start[node->message_loc.start + node->message_loc.length - 1] != '?') &&
3186 char_is_identifier_start(parser, parser->start + node->message_loc.start, (ptrdiff_t) node->message_loc.length) &&
3187 (node->opening_loc.length == 0) &&
3188 (node->arguments == NULL) &&
3189 (node->block == NULL)
3197pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
3198 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
3200 if (write_constant->length > 0) {
3201 size_t length = write_constant->length - 1;
3203 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
3204 memcpy(memory, write_constant->start, length);
3206 *read_name = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, memory, length);
3208 // We can get here if the message was missing because of a syntax error.
3209 *read_name = pm_parser_constant_id_constant(parser, "", 0);
3216static pm_call_and_write_node_t *
3217pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3218 assert(target->block == NULL);
3219 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3221 pm_call_and_write_node_t *node = pm_call_and_write_node_new(
3225 PM_LOCATION_INIT_NODES(target, value),
3227 target->call_operator_loc,
3228 target->message_loc,
3231 TOK2LOC(parser, operator),
3235 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3237 // The target is no longer necessary because we've reused its children.
3238 // It is arena-allocated so no explicit free is needed.
3248pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
3249 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
3250 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
3252 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
3253 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
3254 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
3260 if (block != NULL) {
3261 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
3269static pm_index_and_write_node_t *
3270pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3271 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3273 pm_index_arguments_check(parser, target->arguments, target->block);
3275 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3277 pm_index_and_write_node_t *node = pm_index_and_write_node_new(
3281 PM_LOCATION_INIT_NODES(target, value),
3283 target->call_operator_loc,
3284 target->opening_loc,
3286 target->closing_loc,
3287 (pm_block_argument_node_t *) target->block,
3288 TOK2LOC(parser, operator),
3292 // The target is no longer necessary because we've reused its children.
3293 // It is arena-allocated so no explicit free is needed.
3301static pm_call_operator_write_node_t *
3302pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3303 assert(target->block == NULL);
3305 pm_call_operator_write_node_t *node = pm_call_operator_write_node_new(
3309 PM_LOCATION_INIT_NODES(target, value),
3311 target->call_operator_loc,
3312 target->message_loc,
3315 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3316 TOK2LOC(parser, operator),
3320 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3322 // The target is no longer necessary because we've reused its children.
3323 // It is arena-allocated so no explicit free is needed.
3331static pm_index_operator_write_node_t *
3332pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3333 pm_index_arguments_check(parser, target->arguments, target->block);
3335 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3337 pm_index_operator_write_node_t *node = pm_index_operator_write_node_new(
3341 PM_LOCATION_INIT_NODES(target, value),
3343 target->call_operator_loc,
3344 target->opening_loc,
3346 target->closing_loc,
3347 (pm_block_argument_node_t *) target->block,
3348 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
3349 TOK2LOC(parser, operator),
3353 // The target is no longer necessary because we've reused its children.
3354 // It is arena-allocated so no explicit free is needed.
3362static pm_call_or_write_node_t *
3363pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3364 assert(target->block == NULL);
3365 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3367 pm_call_or_write_node_t *node = pm_call_or_write_node_new(
3371 PM_LOCATION_INIT_NODES(target, value),
3373 target->call_operator_loc,
3374 target->message_loc,
3377 TOK2LOC(parser, operator),
3381 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3383 // The target is no longer necessary because we've reused its children.
3384 // It is arena-allocated so no explicit free is needed.
3392static pm_index_or_write_node_t *
3393pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3394 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3396 pm_index_arguments_check(parser, target->arguments, target->block);
3398 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3400 pm_index_or_write_node_t *node = pm_index_or_write_node_new(
3404 PM_LOCATION_INIT_NODES(target, value),
3406 target->call_operator_loc,
3407 target->opening_loc,
3409 target->closing_loc,
3410 (pm_block_argument_node_t *) target->block,
3411 TOK2LOC(parser, operator),
3415 // The target is no longer necessary because we've reused its children.
3416 // It is arena-allocated so no explicit free is needed.
3425static pm_call_target_node_t *
3426pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3427 pm_call_target_node_t *node = pm_call_target_node_new(
3431 PM_LOCATION_INIT_NODE(target),
3433 target->call_operator_loc,
3438 /* It is possible to get here where we have parsed an invalid syntax tree
3439 * where the call operator was not present. In that case we will have a
3440 * problem because it is a required location. In this case we need to fill
3441 * it in with a fake location so that the syntax tree remains valid. */
3442 if (node->call_operator_loc.length == 0) {
3443 node->call_operator_loc = target->base.location;
3446 // The target is no longer necessary because we've reused its children.
3447 // It is arena-allocated so no explicit free is needed.
3456static pm_index_target_node_t *
3457pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3458 pm_index_arguments_check(parser, target->arguments, target->block);
3459 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3461 pm_index_target_node_t *node = pm_index_target_node_new(
3464 FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE,
3465 PM_LOCATION_INIT_NODE(target),
3467 target->opening_loc,
3469 target->closing_loc,
3470 (pm_block_argument_node_t *) target->block
3473 // The target is no longer necessary because we've reused its children.
3474 // It is arena-allocated so no explicit free is needed.
3482static pm_capture_pattern_node_t *
3483pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3484 return pm_capture_pattern_node_new(
3488 PM_LOCATION_INIT_NODES(value, target),
3491 TOK2LOC(parser, operator)
3498static pm_case_node_t *
3499pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3500 return pm_case_node_new(
3504 PM_LOCATION_INIT_TOKENS(parser, case_keyword, end_keyword == NULL ? case_keyword : end_keyword),
3506 ((pm_node_list_t) { 0 }),
3508 TOK2LOC(parser, case_keyword),
3509 NTOK2LOC(parser, end_keyword)
3517pm_case_node_condition_append(pm_arena_t *arena, pm_case_node_t *node, pm_node_t *condition) {
3518 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3520 pm_node_list_append_inline(arena, &node->conditions, condition);
3521 PM_NODE_LENGTH_SET_NODE(node, condition);
3528pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3529 node->else_clause = else_clause;
3530 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3537pm_case_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_node_t *node, const pm_token_t *end_keyword) {
3538 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3539 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3545static pm_case_match_node_t *
3546pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate) {
3547 return pm_case_match_node_new(
3551 PM_LOCATION_INIT_TOKEN(parser, case_keyword),
3553 ((pm_node_list_t) { 0 }),
3555 TOK2LOC(parser, case_keyword),
3556 ((pm_location_t) { 0 })
3564pm_case_match_node_condition_append(pm_arena_t *arena, pm_case_match_node_t *node, pm_node_t *condition) {
3565 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3567 pm_node_list_append_inline(arena, &node->conditions, condition);
3568 PM_NODE_LENGTH_SET_NODE(node, condition);
3575pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3576 node->else_clause = else_clause;
3577 PM_NODE_LENGTH_SET_NODE(node, else_clause);
3584pm_case_match_node_end_keyword_loc_set(const pm_parser_t *parser, pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3585 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
3586 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
3592static pm_class_node_t *
3593pm_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) {
3594 return pm_class_node_new(
3598 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
3600 TOK2LOC(parser, class_keyword),
3602 NTOK2LOC(parser, inheritance_operator),
3605 TOK2LOC(parser, end_keyword),
3606 pm_parser_constant_id_token(parser, name)
3613static pm_class_variable_and_write_node_t *
3614pm_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) {
3615 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3617 return pm_class_variable_and_write_node_new(
3621 PM_LOCATION_INIT_NODES(target, value),
3623 target->base.location,
3624 TOK2LOC(parser, operator),
3632static pm_class_variable_operator_write_node_t *
3633pm_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) {
3634 return pm_class_variable_operator_write_node_new(
3638 PM_LOCATION_INIT_NODES(target, value),
3640 target->base.location,
3641 TOK2LOC(parser, operator),
3643 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3650static pm_class_variable_or_write_node_t *
3651pm_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) {
3652 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3654 return pm_class_variable_or_write_node_new(
3658 PM_LOCATION_INIT_NODES(target, value),
3660 target->base.location,
3661 TOK2LOC(parser, operator),
3669static pm_class_variable_read_node_t *
3670pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3671 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3673 return pm_class_variable_read_node_new(
3677 PM_LOCATION_INIT_TOKEN(parser, token),
3678 pm_parser_constant_id_token(parser, token)
3688static PRISM_INLINE pm_node_flags_t
3689pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3690 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.length == 0) {
3699static pm_class_variable_write_node_t *
3700pm_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) {
3701 return pm_class_variable_write_node_new(
3704 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3705 PM_LOCATION_INIT_NODES(read_node, value),
3707 read_node->base.location,
3709 TOK2LOC(parser, operator)
3716static pm_constant_path_and_write_node_t *
3717pm_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) {
3718 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3720 return pm_constant_path_and_write_node_new(
3724 PM_LOCATION_INIT_NODES(target, value),
3726 TOK2LOC(parser, operator),
3734static pm_constant_path_operator_write_node_t *
3735pm_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) {
3736 return pm_constant_path_operator_write_node_new(
3740 PM_LOCATION_INIT_NODES(target, value),
3742 TOK2LOC(parser, operator),
3744 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3751static pm_constant_path_or_write_node_t *
3752pm_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) {
3753 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3755 return pm_constant_path_or_write_node_new(
3759 PM_LOCATION_INIT_NODES(target, value),
3761 TOK2LOC(parser, operator),
3769static pm_constant_path_node_t *
3770pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3771 pm_assert_value_expression(parser, parent);
3773 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3774 if (name_token->type == PM_TOKEN_CONSTANT) {
3775 name = pm_parser_constant_id_token(parser, name_token);
3778 return pm_constant_path_node_new(
3782 (parent == NULL) ? PM_LOCATION_INIT_TOKENS(parser, delimiter, name_token) : PM_LOCATION_INIT_NODE_TOKEN(parser, parent, name_token),
3785 TOK2LOC(parser, delimiter),
3786 TOK2LOC(parser, name_token)
3793static pm_constant_path_write_node_t *
3794pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3795 return pm_constant_path_write_node_new(
3798 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3799 PM_LOCATION_INIT_NODES(target, value),
3801 TOK2LOC(parser, operator),
3809static pm_constant_and_write_node_t *
3810pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3811 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3813 return pm_constant_and_write_node_new(
3817 PM_LOCATION_INIT_NODES(target, value),
3819 target->base.location,
3820 TOK2LOC(parser, operator),
3828static pm_constant_operator_write_node_t *
3829pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3830 return pm_constant_operator_write_node_new(
3834 PM_LOCATION_INIT_NODES(target, value),
3836 target->base.location,
3837 TOK2LOC(parser, operator),
3839 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
3846static pm_constant_or_write_node_t *
3847pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3848 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3850 return pm_constant_or_write_node_new(
3854 PM_LOCATION_INIT_NODES(target, value),
3856 target->base.location,
3857 TOK2LOC(parser, operator),
3865static pm_constant_read_node_t *
3866pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3867 assert(name->type == PM_TOKEN_CONSTANT || name->type == 0);
3869 return pm_constant_read_node_new(
3873 PM_LOCATION_INIT_TOKEN(parser, name),
3874 pm_parser_constant_id_token(parser, name)
3881static pm_constant_write_node_t *
3882pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3883 return pm_constant_write_node_new(
3886 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
3887 PM_LOCATION_INIT_NODES(target, value),
3889 target->base.location,
3891 TOK2LOC(parser, operator)
3899pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3900 switch (PM_NODE_TYPE(node)) {
3901 case PM_BEGIN_NODE: {
3902 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3903 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3906 case PM_PARENTHESES_NODE: {
3907 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3908 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3911 case PM_STATEMENTS_NODE: {
3912 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3913 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3918 case PM_IMAGINARY_NODE:
3919 case PM_INTEGER_NODE:
3920 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3921 case PM_INTERPOLATED_STRING_NODE:
3922 case PM_INTERPOLATED_SYMBOL_NODE:
3923 case PM_INTERPOLATED_X_STRING_NODE:
3924 case PM_RATIONAL_NODE:
3925 case PM_REGULAR_EXPRESSION_NODE:
3926 case PM_SOURCE_ENCODING_NODE:
3927 case PM_SOURCE_FILE_NODE:
3928 case PM_SOURCE_LINE_NODE:
3929 case PM_STRING_NODE:
3930 case PM_SYMBOL_NODE:
3931 case PM_X_STRING_NODE:
3932 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3942static pm_def_node_t *
3944 pm_parser_t *parser,
3945 pm_constant_id_t name,
3946 const pm_token_t *name_loc,
3947 pm_node_t *receiver,
3948 pm_parameters_node_t *parameters,
3950 pm_constant_id_list_t *locals,
3951 const pm_token_t *def_keyword,
3952 const pm_token_t *operator,
3953 const pm_token_t *lparen,
3954 const pm_token_t *rparen,
3955 const pm_token_t *equal,
3956 const pm_token_t *end_keyword
3958 if (receiver != NULL) {
3959 pm_def_node_receiver_check(parser, receiver);
3962 return pm_def_node_new(
3966 (end_keyword == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, def_keyword, body) : PM_LOCATION_INIT_TOKENS(parser, def_keyword, end_keyword),
3968 TOK2LOC(parser, name_loc),
3973 TOK2LOC(parser, def_keyword),
3974 NTOK2LOC(parser, operator),
3975 NTOK2LOC(parser, lparen),
3976 NTOK2LOC(parser, rparen),
3977 NTOK2LOC(parser, equal),
3978 NTOK2LOC(parser, end_keyword)
3985static pm_defined_node_t *
3986pm_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) {
3987 return pm_defined_node_new(
3991 (rparen == NULL) ? PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, value) : PM_LOCATION_INIT_TOKENS(parser, keyword, rparen),
3992 NTOK2LOC(parser, lparen),
3994 NTOK2LOC(parser, rparen),
3995 TOK2LOC(parser, keyword)
4002static pm_else_node_t *
4003pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4004 return pm_else_node_new(
4008 ((end_keyword == NULL) && (statements != NULL)) ? PM_LOCATION_INIT_TOKEN_NODE(parser, else_keyword, statements) : PM_LOCATION_INIT_TOKENS(parser, else_keyword, end_keyword),
4009 TOK2LOC(parser, else_keyword),
4011 NTOK2LOC(parser, end_keyword)
4018static pm_embedded_statements_node_t *
4019pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
4020 return pm_embedded_statements_node_new(
4024 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4025 TOK2LOC(parser, opening),
4027 TOK2LOC(parser, closing)
4034static pm_embedded_variable_node_t *
4035pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
4036 return pm_embedded_variable_node_new(
4040 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
4041 TOK2LOC(parser, operator),
4049static pm_ensure_node_t *
4050pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
4051 return pm_ensure_node_new(
4055 PM_LOCATION_INIT_TOKENS(parser, ensure_keyword, end_keyword),
4056 TOK2LOC(parser, ensure_keyword),
4058 TOK2LOC(parser, end_keyword)
4065static pm_false_node_t *
4066pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
4067 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
4069 return pm_false_node_new(
4072 PM_NODE_FLAG_STATIC_LITERAL,
4073 PM_LOCATION_INIT_TOKEN(parser, token)
4081static pm_find_pattern_node_t *
4082pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
4083 assert(nodes->size >= 2);
4084 pm_node_t *left = nodes->nodes[0];
4085 pm_node_t *right = nodes->nodes[nodes->size - 1];
4087 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
4088 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
4090 pm_find_pattern_node_t *node = pm_find_pattern_node_new(
4094 PM_LOCATION_INIT_NODES(left, right),
4096 (pm_splat_node_t *) left,
4097 ((pm_node_list_t) { 0 }),
4098 (pm_splat_node_t *) right,
4099 ((pm_location_t) { 0 }),
4100 ((pm_location_t) { 0 })
4103 // For now we're going to just copy over each pointer manually. This could be
4104 // much more efficient, as we could instead resize the node list to only point
4106 for (size_t index = 1; index < nodes->size - 1; index++) {
4107 pm_node_list_append_inline(parser->arena, &node->requireds, nodes->nodes[index]);
4118pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
4119 ptrdiff_t diff = token->end - token->start;
4120 if (diff <= 0) return 0.0;
4122 // First, get a buffer of the content.
4123 size_t length = (size_t) diff;
4124 const size_t buffer_size = sizeof(char) * (length + 1);
4125 char *buffer = xmalloc(buffer_size);
4126 if (buffer == NULL) PRISM_OOM();
4128 memcpy((void *) buffer, token->start, length);
4130 // Next, determine if we need to replace the decimal point because of
4131 // locale-specific options, and then normalize them if we have to.
4132 char decimal_point = *localeconv()->decimal_point;
4133 if (decimal_point != '.') {
4134 for (size_t index = 0; index < length; index++) {
4135 if (buffer[index] == '.') buffer[index] = decimal_point;
4140 * Next, handle underscores by removing them from the buffer in a single
4141 * pass to avoid quadratic-time copies.
4145 for (size_t read = 0; read < length; read++) {
4146 if (buffer[read] != '_') buffer[write++] = buffer[read];
4151 // Null-terminate the buffer so that strtod cannot read off the end.
4152 buffer[length] = '\0';
4154 // Now, call strtod to parse the value. Note that CRuby has their own
4155 // version of strtod which avoids locales. We're okay using the locale-aware
4156 // version because we've already validated through the parser that the token
4157 // is in a valid format.
4160 double value = strtod(buffer, &eptr);
4162 // This should never happen, because we've already checked that the token
4163 // is in a valid format. However it's good to be safe.
4164 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
4165 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, PM_ERR_FLOAT_PARSE);
4166 xfree_sized(buffer, buffer_size);
4170 // If errno is set, then it should only be ERANGE. At this point we need to
4171 // check if it's infinity (it should be).
4172 if (errno == ERANGE && PRISM_ISINF(value)) {
4174 const char *ellipsis;
4180 warn_width = (int) length;
4184 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);
4185 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
4188 // Finally we can free the buffer and return the value.
4189 xfree_sized(buffer, buffer_size);
4196static pm_float_node_t *
4197pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
4198 assert(token->type == PM_TOKEN_FLOAT);
4200 return pm_float_node_new(
4203 PM_NODE_FLAG_STATIC_LITERAL,
4204 PM_LOCATION_INIT_TOKEN(parser, token),
4205 pm_double_parse(parser, token)
4212static pm_imaginary_node_t *
4213pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4214 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
4216 return pm_imaginary_node_new(
4219 PM_NODE_FLAG_STATIC_LITERAL,
4220 PM_LOCATION_INIT_TOKEN(parser, token),
4221 UP(pm_float_node_create(parser, &((pm_token_t) {
4222 .type = PM_TOKEN_FLOAT,
4223 .start = token->start,
4224 .end = token->end - 1
4232static pm_rational_node_t *
4233pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
4234 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
4236 pm_rational_node_t *node = pm_rational_node_new(
4239 PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL,
4240 PM_LOCATION_INIT_TOKEN(parser, token),
4241 ((pm_integer_t) { 0 }),
4242 ((pm_integer_t) { 0 })
4245 const uint8_t *start = token->start;
4246 const uint8_t *end = token->end - 1; // r
4248 while (start < end && *start == '0') start++; // 0.1 -> .1
4249 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
4251 size_t length = (size_t) (end - start);
4253 node->denominator.value = 1;
4257 const uint8_t *point = memchr(start, '.', length);
4258 assert(point && "should have a decimal point");
4260 uint8_t *digits = xmalloc(length);
4261 if (digits == NULL) PRISM_OOM();
4263 memcpy(digits, start, (unsigned long) (point - start));
4264 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
4265 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
4267 size_t fract_length = 0;
4268 for (const uint8_t *fract = point; fract < end; ++fract) {
4269 if (*fract != '_') ++fract_length;
4272 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
4273 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
4274 xfree_sized(digits, length);
4276 pm_integers_reduce(&node->numerator, &node->denominator);
4277 pm_integer_arena_move(parser->arena, &node->numerator);
4278 pm_integer_arena_move(parser->arena, &node->denominator);
4286static pm_imaginary_node_t *
4287pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
4288 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
4290 return pm_imaginary_node_new(
4293 PM_NODE_FLAG_STATIC_LITERAL,
4294 PM_LOCATION_INIT_TOKEN(parser, token),
4295 UP(pm_float_node_rational_create(parser, &((pm_token_t) {
4296 .type = PM_TOKEN_FLOAT_RATIONAL,
4297 .start = token->start,
4298 .end = token->end - 1
4306static pm_for_node_t *
4308 pm_parser_t *parser,
4310 pm_node_t *collection,
4311 pm_statements_node_t *statements,
4312 const pm_token_t *for_keyword,
4313 const pm_token_t *in_keyword,
4314 const pm_token_t *do_keyword,
4315 const pm_token_t *end_keyword
4317 return pm_for_node_new(
4321 PM_LOCATION_INIT_TOKENS(parser, for_keyword, end_keyword),
4325 TOK2LOC(parser, for_keyword),
4326 TOK2LOC(parser, in_keyword),
4327 NTOK2LOC(parser, do_keyword),
4328 TOK2LOC(parser, end_keyword)
4335static pm_forwarding_arguments_node_t *
4336pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4337 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4339 return pm_forwarding_arguments_node_new(
4343 PM_LOCATION_INIT_TOKEN(parser, token)
4350static pm_forwarding_parameter_node_t *
4351pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4352 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4354 return pm_forwarding_parameter_node_new(
4358 PM_LOCATION_INIT_TOKEN(parser, token)
4365static pm_forwarding_super_node_t *
4366pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4367 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4368 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4370 pm_block_node_t *block = NULL;
4371 if (arguments->block != NULL) {
4372 block = (pm_block_node_t *) arguments->block;
4375 return pm_forwarding_super_node_new(
4379 (block == NULL) ? PM_LOCATION_INIT_TOKEN(parser, token) : PM_LOCATION_INIT_TOKEN_NODE(parser, token, block),
4380 PM_LOCATION_INIT_TOKEN(parser, token),
4389static pm_hash_pattern_node_t *
4390pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4391 return pm_hash_pattern_node_new(
4395 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
4397 ((pm_node_list_t) { 0 }),
4399 TOK2LOC(parser, opening),
4400 TOK2LOC(parser, closing)
4407static pm_hash_pattern_node_t *
4408pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4412 if (elements->size > 0) {
4414 start = MIN(PM_NODE_START(rest), PM_NODE_START(elements->nodes[0]));
4415 end = MAX(PM_NODE_END(rest), PM_NODE_END(elements->nodes[elements->size - 1]));
4417 start = PM_NODE_START(elements->nodes[0]);
4418 end = PM_NODE_END(elements->nodes[elements->size - 1]);
4421 assert(rest != NULL);
4422 start = PM_NODE_START(rest);
4423 end = PM_NODE_END(rest);
4426 pm_hash_pattern_node_t *node = pm_hash_pattern_node_new(
4430 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4432 ((pm_node_list_t) { 0 }),
4434 ((pm_location_t) { 0 }),
4435 ((pm_location_t) { 0 })
4438 pm_node_list_concat(parser->arena, &node->elements, elements);
4445static pm_constant_id_t
4446pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4447 switch (PM_NODE_TYPE(target)) {
4448 case PM_GLOBAL_VARIABLE_READ_NODE:
4449 return ((pm_global_variable_read_node_t *) target)->name;
4450 case PM_BACK_REFERENCE_READ_NODE:
4451 return ((pm_back_reference_read_node_t *) target)->name;
4452 case PM_NUMBERED_REFERENCE_READ_NODE:
4453 // This will only ever happen in the event of a syntax error, but we
4454 // still need to provide something for the node.
4455 return pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
4457 assert(false && "unreachable");
4458 return (pm_constant_id_t) -1;
4465static pm_global_variable_and_write_node_t *
4466pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4467 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4469 return pm_global_variable_and_write_node_new(
4473 PM_LOCATION_INIT_NODES(target, value),
4474 pm_global_variable_write_name(parser, target),
4476 TOK2LOC(parser, operator),
4484static pm_global_variable_operator_write_node_t *
4485pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4486 return pm_global_variable_operator_write_node_new(
4490 PM_LOCATION_INIT_NODES(target, value),
4491 pm_global_variable_write_name(parser, target),
4493 TOK2LOC(parser, operator),
4495 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4502static pm_global_variable_or_write_node_t *
4503pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4504 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4506 return pm_global_variable_or_write_node_new(
4510 PM_LOCATION_INIT_NODES(target, value),
4511 pm_global_variable_write_name(parser, target),
4513 TOK2LOC(parser, operator),
4521static pm_global_variable_read_node_t *
4522pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4523 return pm_global_variable_read_node_new(
4527 PM_LOCATION_INIT_TOKEN(parser, name),
4528 pm_parser_constant_id_token(parser, name)
4535static pm_global_variable_read_node_t *
4536pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4537 return pm_global_variable_read_node_new(
4541 PM_LOCATION_INIT_UNSET,
4549static pm_global_variable_write_node_t *
4550pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4551 return pm_global_variable_write_node_new(
4554 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4555 PM_LOCATION_INIT_NODES(target, value),
4556 pm_global_variable_write_name(parser, target),
4559 TOK2LOC(parser, operator)
4566static pm_global_variable_write_node_t *
4567pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4568 return pm_global_variable_write_node_new(
4572 PM_LOCATION_INIT_UNSET,
4574 ((pm_location_t) { 0 }),
4576 ((pm_location_t) { 0 })
4583static pm_hash_node_t *
4584pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4585 assert(opening != NULL);
4587 return pm_hash_node_new(
4590 PM_NODE_FLAG_STATIC_LITERAL,
4591 PM_LOCATION_INIT_TOKEN(parser, opening),
4592 TOK2LOC(parser, opening),
4593 ((pm_node_list_t) { 0 }),
4594 ((pm_location_t) { 0 })
4601static PRISM_INLINE void
4602pm_hash_node_elements_append(pm_arena_t *arena, pm_hash_node_t *hash, pm_node_t *element) {
4603 pm_node_list_append_inline(arena, &hash->elements, element);
4605 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4606 if (static_literal) {
4607 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4608 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);
4609 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4610 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4613 if (!static_literal) {
4614 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4618static PRISM_INLINE void
4619pm_hash_node_closing_loc_set(const pm_parser_t *parser, pm_hash_node_t *hash, pm_token_t *token) {
4620 PM_NODE_LENGTH_SET_TOKEN(parser, hash, token);
4621 hash->closing_loc = TOK2LOC(parser, token);
4627static pm_if_node_t *
4628pm_if_node_create(pm_parser_t *parser,
4629 const pm_token_t *if_keyword,
4630 pm_node_t *predicate,
4631 const pm_token_t *then_keyword,
4632 pm_statements_node_t *statements,
4633 pm_node_t *subsequent,
4634 const pm_token_t *end_keyword
4636 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4638 uint32_t start = PM_TOKEN_START(parser, if_keyword);
4641 if (end_keyword != NULL) {
4642 end = PM_TOKEN_END(parser, end_keyword);
4643 } else if (subsequent != NULL) {
4644 end = PM_NODE_END(subsequent);
4645 } else if (pm_statements_node_body_length(statements) != 0) {
4646 end = PM_NODE_END(statements);
4648 end = PM_NODE_END(predicate);
4651 return pm_if_node_new(
4654 PM_NODE_FLAG_NEWLINE,
4655 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4656 TOK2LOC(parser, if_keyword),
4658 NTOK2LOC(parser, then_keyword),
4661 NTOK2LOC(parser, end_keyword)
4668static pm_if_node_t *
4669pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4670 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4672 pm_statements_node_t *statements = pm_statements_node_create(parser);
4673 pm_statements_node_body_append(parser, statements, statement, true);
4675 return pm_if_node_new(
4678 PM_NODE_FLAG_NEWLINE,
4679 PM_LOCATION_INIT_NODES(statement, predicate),
4680 TOK2LOC(parser, if_keyword),
4682 ((pm_location_t) { 0 }),
4685 ((pm_location_t) { 0 })
4692static pm_if_node_t *
4693pm_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) {
4694 pm_assert_value_expression(parser, predicate);
4695 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4697 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4698 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4700 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4701 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4703 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, NULL);
4704 return pm_if_node_new(
4707 PM_NODE_FLAG_NEWLINE,
4708 PM_LOCATION_INIT_NODES(predicate, false_expression),
4709 ((pm_location_t) { 0 }),
4711 TOK2LOC(parser, qmark),
4714 ((pm_location_t) { 0 })
4718static PRISM_INLINE void
4719pm_if_node_end_keyword_loc_set(const pm_parser_t *parser, pm_if_node_t *node, const pm_token_t *keyword) {
4720 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4721 node->end_keyword_loc = TOK2LOC(parser, keyword);
4724static PRISM_INLINE void
4725pm_else_node_end_keyword_loc_set(const pm_parser_t *parser, pm_else_node_t *node, const pm_token_t *keyword) {
4726 PM_NODE_LENGTH_SET_TOKEN(parser, node, keyword);
4727 node->end_keyword_loc = TOK2LOC(parser, keyword);
4733static pm_implicit_node_t *
4734pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4735 return pm_implicit_node_new(
4739 PM_LOCATION_INIT_NODE(value),
4747static pm_implicit_rest_node_t *
4748pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4749 assert(token->type == PM_TOKEN_COMMA);
4751 return pm_implicit_rest_node_new(
4755 PM_LOCATION_INIT_TOKEN(parser, token)
4762static pm_integer_node_t *
4763pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4764 assert(token->type == PM_TOKEN_INTEGER);
4766 pm_integer_node_t *node = pm_integer_node_new(
4769 base | PM_NODE_FLAG_STATIC_LITERAL,
4770 PM_LOCATION_INIT_TOKEN(parser, token),
4771 ((pm_integer_t) { 0 })
4774 if (parser->integer.lexed) {
4775 // The value was already computed during lexing.
4776 node->value.value = parser->integer.value;
4777 parser->integer.lexed = false;
4779 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4781 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4782 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4783 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4784 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4785 default: assert(false && "unreachable"); break;
4788 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4789 pm_integer_arena_move(parser->arena, &node->value);
4799static pm_imaginary_node_t *
4800pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4801 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4803 return pm_imaginary_node_new(
4806 PM_NODE_FLAG_STATIC_LITERAL,
4807 PM_LOCATION_INIT_TOKEN(parser, token),
4808 UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4809 .type = PM_TOKEN_INTEGER,
4810 .start = token->start,
4811 .end = token->end - 1
4820static pm_rational_node_t *
4821pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4822 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4824 pm_rational_node_t *node = pm_rational_node_new(
4827 base | PM_NODE_FLAG_STATIC_LITERAL,
4828 PM_LOCATION_INIT_TOKEN(parser, token),
4829 ((pm_integer_t) { 0 }),
4830 ((pm_integer_t) { .value = 1 })
4833 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4835 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4836 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4837 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4838 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4839 default: assert(false && "unreachable"); break;
4842 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4843 pm_integer_arena_move(parser->arena, &node->numerator);
4852static pm_imaginary_node_t *
4853pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4854 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4856 return pm_imaginary_node_new(
4859 PM_NODE_FLAG_STATIC_LITERAL,
4860 PM_LOCATION_INIT_TOKEN(parser, token),
4861 UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4862 .type = PM_TOKEN_INTEGER_RATIONAL,
4863 .start = token->start,
4864 .end = token->end - 1
4872static pm_in_node_t *
4873pm_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) {
4874 uint32_t start = PM_TOKEN_START(parser, in_keyword);
4877 if (statements != NULL) {
4878 end = PM_NODE_END(statements);
4879 } else if (then_keyword != NULL) {
4880 end = PM_TOKEN_END(parser, then_keyword);
4882 end = PM_NODE_END(pattern);
4885 return pm_in_node_new(
4889 ((pm_location_t) { .start = start, .length = U32(end - start) }),
4892 TOK2LOC(parser, in_keyword),
4893 NTOK2LOC(parser, then_keyword)
4900static pm_instance_variable_and_write_node_t *
4901pm_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) {
4902 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4904 return pm_instance_variable_and_write_node_new(
4908 PM_LOCATION_INIT_NODES(target, value),
4910 target->base.location,
4911 TOK2LOC(parser, operator),
4919static pm_instance_variable_operator_write_node_t *
4920pm_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) {
4921 return pm_instance_variable_operator_write_node_new(
4925 PM_LOCATION_INIT_NODES(target, value),
4927 target->base.location,
4928 TOK2LOC(parser, operator),
4930 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1)
4937static pm_instance_variable_or_write_node_t *
4938pm_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) {
4939 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4941 return pm_instance_variable_or_write_node_new(
4945 PM_LOCATION_INIT_NODES(target, value),
4947 target->base.location,
4948 TOK2LOC(parser, operator),
4956static pm_instance_variable_read_node_t *
4957pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4958 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4960 return pm_instance_variable_read_node_new(
4964 PM_LOCATION_INIT_TOKEN(parser, token),
4965 pm_parser_constant_id_token(parser, token)
4973static pm_instance_variable_write_node_t *
4974pm_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) {
4975 return pm_instance_variable_write_node_new(
4978 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
4979 PM_LOCATION_INIT_NODES(read_node, value),
4981 read_node->base.location,
4983 TOK2LOC(parser, operator)
4993pm_interpolated_node_append(pm_arena_t *arena, pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4994 switch (PM_NODE_TYPE(part)) {
4995 case PM_STRING_NODE:
4996 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4998 case PM_EMBEDDED_STATEMENTS_NODE: {
4999 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5000 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5002 if (embedded == NULL) {
5003 // If there are no statements or more than one statement, then
5004 // we lose the static literal flag.
5005 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5006 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5007 // If the embedded statement is a string, then we can keep the
5008 // static literal flag and mark the string as frozen.
5009 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
5010 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5011 // If the embedded statement is an interpolated string and it's
5012 // a static literal, then we can keep the static literal flag.
5014 // Otherwise we lose the static literal flag.
5015 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
5020 case PM_EMBEDDED_VARIABLE_NODE:
5021 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5024 assert(false && "unexpected node type");
5028 pm_node_list_append_inline(arena, parts, part);
5034static pm_interpolated_regular_expression_node_t *
5035pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
5036 return pm_interpolated_regular_expression_node_new(
5039 PM_NODE_FLAG_STATIC_LITERAL,
5040 PM_LOCATION_INIT_TOKEN(parser, opening),
5041 TOK2LOC(parser, opening),
5042 ((pm_node_list_t) { 0 }),
5043 TOK2LOC(parser, opening)
5047static PRISM_INLINE void
5048pm_interpolated_regular_expression_node_append(pm_arena_t *arena, pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
5049 if (PM_NODE_START(node) > PM_NODE_START(part)) {
5050 PM_NODE_START_SET_NODE(node, part);
5052 if (PM_NODE_END(node) < PM_NODE_END(part)) {
5053 PM_NODE_LENGTH_SET_NODE(node, part);
5056 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5059static PRISM_INLINE void
5060pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
5061 node->closing_loc = TOK2LOC(parser, closing);
5062 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5063 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
5089static PRISM_INLINE void
5090pm_interpolated_string_node_append(pm_parser_t *parser, pm_interpolated_string_node_t *node, pm_node_t *part) {
5091 pm_arena_t *arena = parser->arena;
5092#define CLEAR_FLAGS(node) \
5093 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))
5095#define MUTABLE_FLAGS(node) \
5096 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
5098 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5099 PM_NODE_START_SET_NODE(node, part);
5102 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5103 PM_NODE_LENGTH_SET_NODE(node, part);
5106 switch (PM_NODE_TYPE(part)) {
5107 case PM_STRING_NODE:
5108 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
5109 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
5110 // as long as this interpolation only consists of other string literals.
5111 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
5112 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
5114 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5116 case PM_INTERPOLATED_STRING_NODE:
5117 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
5118 // If the string that we're concatenating is a static literal,
5119 // then we can keep the static literal flag for this string.
5121 // Otherwise, we lose the static literal flag here and we should
5122 // also clear the mutability flags.
5126 case PM_EMBEDDED_STATEMENTS_NODE: {
5127 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
5128 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
5130 if (embedded == NULL) {
5131 // If we're embedding multiple statements or no statements, then
5132 // the string is not longer a static literal.
5134 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
5135 // If the embedded statement is a string, then we can make that
5136 // string as frozen and static literal, and not touch the static
5137 // literal status of this string.
5138 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
5140 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5141 MUTABLE_FLAGS(node);
5143 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
5144 // If the embedded statement is an interpolated string, but that
5145 // string is marked as static literal, then we can keep our
5146 // static literal status for this string.
5147 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
5148 MUTABLE_FLAGS(node);
5151 // In all other cases, we lose the static literal flag here and
5158 case PM_EMBEDDED_VARIABLE_NODE:
5159 // Embedded variables clear static literal, which means we also
5160 // should clear the mutability flags.
5163 case PM_X_STRING_NODE:
5164 case PM_INTERPOLATED_X_STRING_NODE:
5165 case PM_SYMBOL_NODE:
5166 case PM_INTERPOLATED_SYMBOL_NODE:
5167 // These will only happen in error cases. But we want to handle it
5168 // here so that we don't fail the assertion.
5170 pm_node_list_append_inline(arena, &node->parts, UP(pm_error_recovery_node_create_unexpected(parser, part)));
5172 case PM_ERROR_RECOVERY_NODE:
5176 assert(false && "unexpected node type");
5180 pm_node_list_append_inline(arena, &node->parts, part);
5189static pm_interpolated_string_node_t *
5190pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5191 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
5193 switch (parser->frozen_string_literal) {
5194 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
5195 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
5197 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
5198 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
5202 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5203 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5205 pm_interpolated_string_node_t *node = pm_interpolated_string_node_new(
5209 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5210 NTOK2LOC(parser, opening),
5211 ((pm_node_list_t) { 0 }),
5212 NTOK2LOC(parser, closing)
5215 if (parts != NULL) {
5217 PM_NODE_LIST_FOREACH(parts, index, part) {
5218 pm_interpolated_string_node_append(parser, node, part);
5229pm_interpolated_string_node_closing_set(const pm_parser_t *parser, pm_interpolated_string_node_t *node, const pm_token_t *closing) {
5230 node->closing_loc = TOK2LOC(parser, closing);
5231 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5235pm_interpolated_symbol_node_append(pm_arena_t *arena, pm_interpolated_symbol_node_t *node, pm_node_t *part) {
5236 if (node->parts.size == 0 && node->opening_loc.length == 0) {
5237 PM_NODE_START_SET_NODE(node, part);
5240 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5242 if (PM_NODE_END(part) > PM_NODE_END(node)) {
5243 PM_NODE_LENGTH_SET_NODE(node, part);
5248pm_interpolated_symbol_node_closing_loc_set(const pm_parser_t *parser, pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
5249 node->closing_loc = TOK2LOC(parser, closing);
5250 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5256static pm_interpolated_symbol_node_t *
5257pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
5258 uint32_t start = opening == NULL ? 0 : PM_TOKEN_START(parser, opening);
5259 uint32_t end = closing == NULL ? 0 : PM_TOKEN_END(parser, closing);
5261 pm_interpolated_symbol_node_t *node = pm_interpolated_symbol_node_new(
5264 PM_NODE_FLAG_STATIC_LITERAL,
5265 ((pm_location_t) { .start = start, .length = U32(end - start) }),
5266 NTOK2LOC(parser, opening),
5267 ((pm_node_list_t) { 0 }),
5268 NTOK2LOC(parser, closing)
5271 if (parts != NULL) {
5273 PM_NODE_LIST_FOREACH(parts, index, part) {
5274 pm_interpolated_symbol_node_append(parser->arena, node, part);
5284static pm_interpolated_x_string_node_t *
5285pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5286 return pm_interpolated_x_string_node_new(
5290 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5291 TOK2LOC(parser, opening),
5292 ((pm_node_list_t) { 0 }),
5293 TOK2LOC(parser, closing)
5297static PRISM_INLINE void
5298pm_interpolated_xstring_node_append(pm_arena_t *arena, pm_interpolated_x_string_node_t *node, pm_node_t *part) {
5299 pm_interpolated_node_append(arena, UP(node), &node->parts, part);
5300 PM_NODE_LENGTH_SET_NODE(node, part);
5303static PRISM_INLINE void
5304pm_interpolated_xstring_node_closing_set(const pm_parser_t *parser, pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
5305 node->closing_loc = TOK2LOC(parser, closing);
5306 PM_NODE_LENGTH_SET_TOKEN(parser, node, closing);
5312static pm_it_local_variable_read_node_t *
5313pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5314 return pm_it_local_variable_read_node_new(
5318 PM_LOCATION_INIT_TOKEN(parser, name)
5325static pm_it_parameters_node_t *
5326pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5327 return pm_it_parameters_node_new(
5331 PM_LOCATION_INIT_TOKENS(parser, opening, closing)
5338static pm_keyword_hash_node_t *
5339pm_keyword_hash_node_create(pm_parser_t *parser) {
5340 return pm_keyword_hash_node_new(
5343 PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS,
5344 PM_LOCATION_INIT_UNSET,
5345 ((pm_node_list_t) { 0 })
5353pm_keyword_hash_node_elements_append(pm_arena_t *arena, pm_keyword_hash_node_t *hash, pm_node_t *element) {
5354 // If the element being added is not an AssocNode or does not have a symbol
5355 // key, then we want to turn the SYMBOL_KEYS flag off.
5356 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5357 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5360 pm_node_list_append_inline(arena, &hash->elements, element);
5361 if (PM_NODE_LENGTH(hash) == 0) {
5362 PM_NODE_START_SET_NODE(hash, element);
5364 PM_NODE_LENGTH_SET_NODE(hash, element);
5370static pm_required_keyword_parameter_node_t *
5371pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5372 return pm_required_keyword_parameter_node_new(
5376 PM_LOCATION_INIT_TOKEN(parser, name),
5377 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5378 TOK2LOC(parser, name)
5385static pm_optional_keyword_parameter_node_t *
5386pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5387 return pm_optional_keyword_parameter_node_new(
5391 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5392 pm_parser_constant_id_raw(parser, name->start, name->end - 1),
5393 TOK2LOC(parser, name),
5401static pm_keyword_rest_parameter_node_t *
5402pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5403 return pm_keyword_rest_parameter_node_new(
5407 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
5408 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
5409 NTOK2LOC(parser, name),
5410 TOK2LOC(parser, operator)
5417static pm_lambda_node_t *
5418pm_lambda_node_create(
5419 pm_parser_t *parser,
5420 pm_constant_id_list_t *locals,
5421 const pm_token_t *operator,
5422 const pm_token_t *opening,
5423 const pm_token_t *closing,
5424 pm_node_t *parameters,
5427 return pm_lambda_node_new(
5431 PM_LOCATION_INIT_TOKENS(parser, operator, closing),
5433 TOK2LOC(parser, operator),
5434 TOK2LOC(parser, opening),
5435 TOK2LOC(parser, closing),
5444static pm_local_variable_and_write_node_t *
5445pm_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) {
5446 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));
5447 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5449 return pm_local_variable_and_write_node_new(
5453 PM_LOCATION_INIT_NODES(target, value),
5455 TOK2LOC(parser, operator),
5465static pm_local_variable_operator_write_node_t *
5466pm_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) {
5467 return pm_local_variable_operator_write_node_new(
5471 PM_LOCATION_INIT_NODES(target, value),
5473 TOK2LOC(parser, operator),
5476 pm_parser_constant_id_raw(parser, operator->start, operator->end - 1),
5484static pm_local_variable_or_write_node_t *
5485pm_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) {
5486 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));
5487 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5489 return pm_local_variable_or_write_node_new(
5493 PM_LOCATION_INIT_NODES(target, value),
5495 TOK2LOC(parser, operator),
5505static pm_local_variable_read_node_t *
5506pm_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) {
5507 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5509 return pm_local_variable_read_node_new(
5513 PM_LOCATION_INIT_TOKEN(parser, name),
5522static pm_local_variable_read_node_t *
5523pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5524 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5525 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5532static pm_local_variable_read_node_t *
5533pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5534 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5535 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5541static pm_local_variable_write_node_t *
5542pm_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) {
5543 return pm_local_variable_write_node_new(
5546 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5547 ((pm_location_t) { .start = name_loc->start, .length = PM_NODE_END(value) - name_loc->start }),
5552 TOK2LOC(parser, operator)
5559static PRISM_INLINE bool
5560pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5561 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5568static PRISM_INLINE bool
5569pm_token_is_numbered_parameter(const pm_parser_t *parser, uint32_t start, uint32_t length) {
5572 (parser->start[start] == '_') &&
5573 (parser->start[start + 1] != '0') &&
5574 pm_char_is_decimal_digit(parser->start[start + 1])
5582static PRISM_INLINE void
5583pm_refute_numbered_parameter(pm_parser_t *parser, uint32_t start, uint32_t length) {
5584 if (pm_token_is_numbered_parameter(parser, start, length)) {
5585 PM_PARSER_ERR_FORMAT(parser, start, length, PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + start);
5593static pm_local_variable_target_node_t *
5594pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5595 pm_refute_numbered_parameter(parser, location->start, location->length);
5597 return pm_local_variable_target_node_new(
5601 ((pm_location_t) { .start = location->start, .length = location->length }),
5610static pm_match_predicate_node_t *
5611pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5612 pm_assert_value_expression(parser, value);
5614 return pm_match_predicate_node_new(
5618 PM_LOCATION_INIT_NODES(value, pattern),
5621 TOK2LOC(parser, operator)
5628static pm_match_required_node_t *
5629pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5630 pm_assert_value_expression(parser, value);
5632 return pm_match_required_node_new(
5636 PM_LOCATION_INIT_NODES(value, pattern),
5639 TOK2LOC(parser, operator)
5646static pm_match_write_node_t *
5647pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5648 return pm_match_write_node_new(
5652 PM_LOCATION_INIT_NODE(call),
5654 ((pm_node_list_t) { 0 })
5661static pm_module_node_t *
5662pm_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) {
5663 pm_constant_id_list_t module_locals = { .ids = NULL, .size = 0, .capacity = 0 };
5664 if (locals != NULL) module_locals = *locals;
5666 return pm_module_node_new(
5670 PM_LOCATION_INIT_TOKENS(parser, module_keyword, end_keyword),
5672 TOK2LOC(parser, module_keyword),
5675 TOK2LOC(parser, end_keyword),
5676 pm_parser_constant_id_token(parser, name)
5683static pm_multi_target_node_t *
5684pm_multi_target_node_create(pm_parser_t *parser) {
5685 return pm_multi_target_node_new(
5689 PM_LOCATION_INIT_UNSET,
5690 ((pm_node_list_t) { 0 }),
5692 ((pm_node_list_t) { 0 }),
5693 ((pm_location_t) { 0 }),
5694 ((pm_location_t) { 0 })
5702pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5703 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5704 if (node->rest == NULL) {
5705 node->rest = target;
5707 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5708 pm_node_list_append_inline(parser->arena, &node->rights, target);
5710 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5711 if (node->rest == NULL) {
5712 node->rest = target;
5714 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5715 pm_node_list_append_inline(parser->arena, &node->rights, target);
5717 } else if (node->rest == NULL) {
5718 pm_node_list_append_inline(parser->arena, &node->lefts, target);
5720 pm_node_list_append_inline(parser->arena, &node->rights, target);
5723 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_START(node) > PM_NODE_START(target))) {
5724 PM_NODE_START_SET_NODE(node, target);
5727 if (PM_NODE_LENGTH(node) == 0 || (PM_NODE_END(node) < PM_NODE_END(target))) {
5728 PM_NODE_LENGTH_SET_NODE(node, target);
5736pm_multi_target_node_opening_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *lparen) {
5737 PM_NODE_START_SET_TOKEN(parser, node, lparen);
5738 PM_NODE_LENGTH_SET_TOKEN(parser, node, lparen);
5739 node->lparen_loc = TOK2LOC(parser, lparen);
5746pm_multi_target_node_closing_set(const pm_parser_t *parser, pm_multi_target_node_t *node, const pm_token_t *rparen) {
5747 PM_NODE_LENGTH_SET_TOKEN(parser, node, rparen);
5748 node->rparen_loc = TOK2LOC(parser, rparen);
5754static pm_multi_write_node_t *
5755pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5756 /* The target is no longer necessary because we have reused its children. It
5757 * is arena-allocated so no explicit free is needed. */
5758 return pm_multi_write_node_new(
5761 pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY),
5762 PM_LOCATION_INIT_NODES(target, value),
5768 TOK2LOC(parser, operator),
5776static pm_next_node_t *
5777pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5778 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5780 return pm_next_node_new(
5784 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
5786 TOK2LOC(parser, keyword)
5793static pm_nil_node_t *
5794pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5795 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5797 return pm_nil_node_new(
5800 PM_NODE_FLAG_STATIC_LITERAL,
5801 PM_LOCATION_INIT_TOKEN(parser, token)
5808static pm_no_block_parameter_node_t *
5809pm_no_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5810 assert(operator->type == PM_TOKEN_AMPERSAND || operator->type == PM_TOKEN_UAMPERSAND);
5811 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5813 return pm_no_block_parameter_node_new(
5817 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5818 TOK2LOC(parser, operator),
5819 TOK2LOC(parser, keyword)
5826static pm_no_keywords_parameter_node_t *
5827pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5828 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5829 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5831 return pm_no_keywords_parameter_node_new(
5835 PM_LOCATION_INIT_TOKENS(parser, operator, keyword),
5836 TOK2LOC(parser, operator),
5837 TOK2LOC(parser, keyword)
5844static pm_numbered_parameters_node_t *
5845pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing, uint8_t maximum) {
5846 return pm_numbered_parameters_node_new(
5850 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
5862pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5867#define NTH_REF_MAX ((uint64_t) (uint32_t) (INT_MAX >> 1))
5869 const uint8_t *start = token->start + 1;
5870 ptrdiff_t diff = token->end - start;
5873 size_t length = (size_t) diff;
5876 for (size_t idx = 0; idx < length; ++idx) {
5877 value = value * 10 + (uint64_t) (start[idx] - '0');
5879 if (value > NTH_REF_MAX) {
5880 PM_PARSER_WARN_FORMAT(parser, U32(start - parser->start), U32(length), PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5886 return (uint32_t) value;
5894static pm_numbered_reference_read_node_t *
5895pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5896 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5898 return pm_numbered_reference_read_node_new(
5902 PM_LOCATION_INIT_TOKEN(parser, name),
5903 pm_numbered_reference_read_node_number(parser, name)
5910static pm_optional_parameter_node_t *
5911pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5912 return pm_optional_parameter_node_new(
5916 PM_LOCATION_INIT_TOKEN_NODE(parser, name, value),
5917 pm_parser_constant_id_token(parser, name),
5918 TOK2LOC(parser, name),
5919 TOK2LOC(parser, operator),
5927static pm_or_node_t *
5928pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5929 pm_assert_value_expression(parser, left);
5931 return pm_or_node_new(
5935 PM_LOCATION_INIT_NODES(left, right),
5938 TOK2LOC(parser, operator)
5945static pm_parameters_node_t *
5946pm_parameters_node_create(pm_parser_t *parser) {
5947 return pm_parameters_node_new(
5951 PM_LOCATION_INIT_UNSET,
5952 ((pm_node_list_t) { 0 }),
5953 ((pm_node_list_t) { 0 }),
5955 ((pm_node_list_t) { 0 }),
5956 ((pm_node_list_t) { 0 }),
5966pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5967 if ((params->base.location.length == 0) || PM_NODE_START(params) > PM_NODE_START(param)) {
5968 PM_NODE_START_SET_NODE(params, param);
5971 if ((params->base.location.length == 0) || (PM_NODE_END(params) < PM_NODE_END(param))) {
5972 PM_NODE_LENGTH_SET_NODE(params, param);
5980pm_parameters_node_requireds_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
5981 pm_parameters_node_location_set(params, param);
5982 pm_node_list_append_inline(arena, ¶ms->requireds, param);
5989pm_parameters_node_optionals_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
5990 pm_parameters_node_location_set(params, UP(param));
5991 pm_node_list_append_inline(arena, ¶ms->optionals, UP(param));
5998pm_parameters_node_posts_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
5999 pm_parameters_node_location_set(params, param);
6000 pm_node_list_append_inline(arena, ¶ms->posts, param);
6007pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6008 pm_parameters_node_location_set(params, param);
6009 params->rest = param;
6016pm_parameters_node_keywords_append(pm_arena_t *arena, pm_parameters_node_t *params, pm_node_t *param) {
6017 pm_parameters_node_location_set(params, param);
6018 pm_node_list_append_inline(arena, ¶ms->keywords, param);
6025pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
6026 assert(params->keyword_rest == NULL);
6027 pm_parameters_node_location_set(params, param);
6028 params->keyword_rest = param;
6035pm_parameters_node_block_set(pm_parameters_node_t *params, pm_node_t *param) {
6036 assert(params->block == NULL);
6037 pm_parameters_node_location_set(params, param);
6038 params->block = param;
6044static pm_program_node_t *
6045pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
6046 return pm_program_node_new(
6050 PM_LOCATION_INIT_NODE(statements),
6059static pm_parentheses_node_t *
6060pm_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) {
6061 return pm_parentheses_node_new(
6065 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6067 TOK2LOC(parser, opening),
6068 TOK2LOC(parser, closing)
6075static pm_pinned_expression_node_t *
6076pm_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) {
6077 return pm_pinned_expression_node_new(
6081 PM_LOCATION_INIT_TOKENS(parser, operator, rparen),
6083 TOK2LOC(parser, operator),
6084 TOK2LOC(parser, lparen),
6085 TOK2LOC(parser, rparen)
6092static pm_pinned_variable_node_t *
6093pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
6094 return pm_pinned_variable_node_new(
6098 PM_LOCATION_INIT_TOKEN_NODE(parser, operator, variable),
6100 TOK2LOC(parser, operator)
6107static pm_post_execution_node_t *
6108pm_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) {
6109 return pm_post_execution_node_new(
6113 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6115 TOK2LOC(parser, keyword),
6116 TOK2LOC(parser, opening),
6117 TOK2LOC(parser, closing)
6124static pm_pre_execution_node_t *
6125pm_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) {
6126 return pm_pre_execution_node_new(
6130 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
6132 TOK2LOC(parser, keyword),
6133 TOK2LOC(parser, opening),
6134 TOK2LOC(parser, closing)
6141static pm_range_node_t *
6142pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
6143 pm_assert_value_expression(parser, left);
6144 pm_assert_value_expression(parser, right);
6145 pm_node_flags_t flags = 0;
6147 // Indicate that this node is an exclusive range if the operator is `...`.
6148 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
6149 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
6152 // Indicate that this node is a static literal (i.e., can be compiled with
6153 // a putobject in CRuby) if the left and right are implicit nil, explicit
6154 // nil, or integers.
6156 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
6157 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
6159 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6162 uint32_t start = left == NULL ? PM_TOKEN_START(parser, operator) : PM_NODE_START(left);
6163 uint32_t end = right == NULL ? PM_TOKEN_END(parser, operator) : PM_NODE_END(right);
6165 return pm_range_node_new(
6169 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6172 TOK2LOC(parser, operator)
6179static pm_redo_node_t *
6180pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
6181 assert(token->type == PM_TOKEN_KEYWORD_REDO);
6183 return pm_redo_node_new(
6187 PM_LOCATION_INIT_TOKEN(parser, token)
6195static pm_regular_expression_node_t *
6196pm_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) {
6197 return pm_regular_expression_node_new(
6200 pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL,
6201 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6202 TOK2LOC(parser, opening),
6203 TOK2LOC(parser, content),
6204 TOK2LOC(parser, closing),
6212static PRISM_INLINE pm_regular_expression_node_t *
6213pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6214 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6220static pm_required_parameter_node_t *
6221pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
6222 return pm_required_parameter_node_new(
6226 PM_LOCATION_INIT_TOKEN(parser, token),
6227 pm_parser_constant_id_token(parser, token)
6234static pm_rescue_modifier_node_t *
6235pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
6236 return pm_rescue_modifier_node_new(
6240 PM_LOCATION_INIT_NODES(expression, rescue_expression),
6242 TOK2LOC(parser, keyword),
6250static pm_rescue_node_t *
6251pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6252 return pm_rescue_node_new(
6256 PM_LOCATION_INIT_TOKEN(parser, keyword),
6257 TOK2LOC(parser, keyword),
6258 ((pm_node_list_t) { 0 }),
6259 ((pm_location_t) { 0 }),
6261 ((pm_location_t) { 0 }),
6267static PRISM_INLINE void
6268pm_rescue_node_operator_set(const pm_parser_t *parser, pm_rescue_node_t *node, const pm_token_t *operator) {
6269 node->operator_loc = TOK2LOC(parser, operator);
6276pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
6277 node->reference = reference;
6278 PM_NODE_LENGTH_SET_NODE(node, reference);
6285pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
6286 node->statements = statements;
6287 if (pm_statements_node_body_length(statements) > 0) {
6288 PM_NODE_LENGTH_SET_NODE(node, statements);
6296pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6297 node->subsequent = subsequent;
6298 PM_NODE_LENGTH_SET_NODE(node, subsequent);
6305pm_rescue_node_exceptions_append(pm_arena_t *arena, pm_rescue_node_t *node, pm_node_t *exception) {
6306 pm_node_list_append_inline(arena, &node->exceptions, exception);
6307 PM_NODE_LENGTH_SET_NODE(node, exception);
6313static pm_rest_parameter_node_t *
6314pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6315 return pm_rest_parameter_node_new(
6319 (name == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKENS(parser, operator, name),
6320 name == NULL ? 0 : pm_parser_constant_id_token(parser, name),
6321 NTOK2LOC(parser, name),
6322 TOK2LOC(parser, operator)
6329static pm_retry_node_t *
6330pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6331 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6333 return pm_retry_node_new(
6337 PM_LOCATION_INIT_TOKEN(parser, token)
6344static pm_return_node_t *
6345pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6346 return pm_return_node_new(
6350 (arguments == NULL) ? PM_LOCATION_INIT_TOKEN(parser, keyword) : PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, arguments),
6351 TOK2LOC(parser, keyword),
6359static pm_self_node_t *
6360pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6361 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6363 return pm_self_node_new(
6367 PM_LOCATION_INIT_TOKEN(parser, token)
6374static pm_shareable_constant_node_t *
6375pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6376 return pm_shareable_constant_node_new(
6379 (pm_node_flags_t) value,
6380 PM_LOCATION_INIT_NODE(write),
6388static pm_singleton_class_node_t *
6389pm_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) {
6390 return pm_singleton_class_node_new(
6394 PM_LOCATION_INIT_TOKENS(parser, class_keyword, end_keyword),
6396 TOK2LOC(parser, class_keyword),
6397 TOK2LOC(parser, operator),
6400 TOK2LOC(parser, end_keyword)
6407static pm_source_encoding_node_t *
6408pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6409 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6411 return pm_source_encoding_node_new(
6414 PM_NODE_FLAG_STATIC_LITERAL,
6415 PM_LOCATION_INIT_TOKEN(parser, token)
6422static pm_source_file_node_t*
6423pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6424 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6426 pm_node_flags_t flags = 0;
6428 switch (parser->frozen_string_literal) {
6429 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6430 flags |= PM_STRING_FLAGS_MUTABLE;
6432 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6433 flags |= PM_STRING_FLAGS_FROZEN;
6434 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
6435 flags |= PM_NODE_FLAG_STATIC_LITERAL;
6440 return pm_source_file_node_new(
6444 PM_LOCATION_INIT_TOKEN(parser, file_keyword),
6452static pm_source_line_node_t *
6453pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6454 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6456 return pm_source_line_node_new(
6459 PM_NODE_FLAG_STATIC_LITERAL,
6460 PM_LOCATION_INIT_TOKEN(parser, token)
6467static pm_splat_node_t *
6468pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6469 return pm_splat_node_new(
6473 (expression == NULL) ? PM_LOCATION_INIT_TOKEN(parser, operator) : PM_LOCATION_INIT_TOKEN_NODE(parser, operator, expression),
6474 TOK2LOC(parser, operator),
6482static pm_statements_node_t *
6483pm_statements_node_create(pm_parser_t *parser) {
6484 return pm_statements_node_new(
6488 PM_LOCATION_INIT_UNSET,
6489 ((pm_node_list_t) { 0 })
6497pm_statements_node_body_length(pm_statements_node_t *node) {
6498 return node && node->body.size;
6505static PRISM_INLINE void
6506pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6507 if (pm_statements_node_body_length(node) == 0 || PM_NODE_START(statement) < PM_NODE_START(node)) {
6508 PM_NODE_START_SET_NODE(node, statement);
6511 if (PM_NODE_END(statement) > PM_NODE_END(node)) {
6512 PM_NODE_LENGTH_SET_NODE(node, statement);
6520pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6521 pm_statements_node_body_update(node, statement);
6523 if (node->body.size > 0) {
6524 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6526 switch (PM_NODE_TYPE(previous)) {
6531 case PM_RETURN_NODE:
6532 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6539 pm_node_list_append_inline(parser->arena, &node->body, statement);
6540 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6547pm_statements_node_body_prepend(pm_arena_t *arena, pm_statements_node_t *node, pm_node_t *statement) {
6548 pm_statements_node_body_update(node, statement);
6549 pm_node_list_prepend(arena, &node->body, statement);
6550 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6556static PRISM_INLINE pm_string_node_t *
6557pm_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) {
6558 pm_node_flags_t flags = 0;
6560 switch (parser->frozen_string_literal) {
6561 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6562 flags = PM_STRING_FLAGS_MUTABLE;
6564 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6565 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6569 uint32_t start = PM_TOKEN_START(parser, opening == NULL ? content : opening);
6570 uint32_t end = PM_TOKEN_END(parser, closing == NULL ? content : closing);
6572 return pm_string_node_new(
6576 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6577 NTOK2LOC(parser, opening),
6578 TOK2LOC(parser, content),
6579 NTOK2LOC(parser, closing),
6587static pm_string_node_t *
6588pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6589 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6596static pm_string_node_t *
6597pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6598 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6599 parser->current_string = PM_STRING_EMPTY;
6606static pm_super_node_t *
6607pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6608 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6610 const pm_location_t *end = pm_arguments_end(arguments);
6611 assert(end != NULL && "unreachable");
6613 return pm_super_node_new(
6617 ((pm_location_t) { .start = PM_TOKEN_START(parser, keyword), .length = PM_LOCATION_END(end) - PM_TOKEN_START(parser, keyword) }),
6618 TOK2LOC(parser, keyword),
6619 arguments->opening_loc,
6620 arguments->arguments,
6621 arguments->closing_loc,
6631pm_ascii_only_p(const pm_string_t *contents) {
6632 const size_t length = pm_string_length(contents);
6633 const uint8_t *source = pm_string_source(contents);
6635 for (size_t index = 0; index < length; index++) {
6636 if (source[index] & 0x80) return false;
6646parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6647 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6648 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6651 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6664parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6665 const pm_encoding_t *encoding = parser->encoding;
6667 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6668 size_t width = encoding->char_width(cursor, end - cursor);
6671 pm_parser_err(parser, PM_TOKEN_START(parser, location), PM_TOKEN_LENGTH(location), PM_ERR_INVALID_SYMBOL);
6688static PRISM_INLINE pm_node_flags_t
6689parse_symbol_encoding(pm_parser_t *parser, const pm_encoding_t *explicit_encoding, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6690 if (explicit_encoding != NULL) {
6691 // A Symbol may optionally have its encoding explicitly set. This will
6692 // happen if an escape sequence results in a non-ASCII code point.
6693 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6694 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6695 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6696 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6697 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6698 } else if (validate) {
6699 parse_symbol_encoding_validate_other(parser, location, contents);
6701 } else if (pm_ascii_only_p(contents)) {
6702 // Ruby stipulates that all source files must use an ASCII-compatible
6703 // encoding. Thus, all symbols appearing in source are eligible for
6704 // "downgrading" to US-ASCII.
6705 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6706 } else if (validate) {
6707 parse_symbol_encoding_validate_other(parser, location, contents);
6717static pm_symbol_node_t *
6718pm_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) {
6719 uint32_t start = opening == NULL ? PM_TOKEN_START(parser, value) : PM_TOKEN_START(parser, opening);
6720 uint32_t end = closing == NULL ? PM_TOKEN_END(parser, value) : PM_TOKEN_END(parser, closing);
6722 return pm_symbol_node_new(
6725 PM_NODE_FLAG_STATIC_LITERAL | flags,
6726 ((pm_location_t) { .start = start, .length = U32(end - start) }),
6727 NTOK2LOC(parser, opening),
6728 NTOK2LOC(parser, value),
6729 NTOK2LOC(parser, closing),
6737static PRISM_INLINE pm_symbol_node_t *
6738pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6739 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6745static pm_symbol_node_t *
6746pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6747 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));
6748 parser->current_string = PM_STRING_EMPTY;
6755static pm_symbol_node_t *
6756pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6757 assert(token->type == PM_TOKEN_LABEL);
6759 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6760 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6761 pm_symbol_node_t *node = pm_symbol_node_create(parser, NULL, &label, &closing);
6763 assert((label.end - label.start) >= 0);
6764 pm_string_shared_init(&node->unescaped, label.start, label.end);
6765 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, parser->explicit_encoding, &label, &node->unescaped, false));
6773static pm_symbol_node_t *
6774pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6775 pm_symbol_node_t *node = pm_symbol_node_new(
6778 PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING,
6779 PM_LOCATION_INIT_UNSET,
6780 ((pm_location_t) { 0 }),
6781 ((pm_location_t) { 0 }),
6782 ((pm_location_t) { 0 }),
6783 ((pm_string_t) { 0 })
6786 pm_string_init(&node->unescaped, (const uint8_t *) content, strlen(content));
6794pm_symbol_node_label_p(const pm_parser_t *parser, const pm_node_t *node) {
6795 const pm_location_t *location = NULL;
6797 switch (PM_NODE_TYPE(node)) {
6798 case PM_SYMBOL_NODE: {
6799 const pm_symbol_node_t *cast = (pm_symbol_node_t *) node;
6800 if (cast->closing_loc.length > 0) {
6801 location = &cast->closing_loc;
6805 case PM_INTERPOLATED_SYMBOL_NODE: {
6806 const pm_interpolated_symbol_node_t *cast = (pm_interpolated_symbol_node_t *) node;
6807 if (cast->closing_loc.length > 0) {
6808 location = &cast->closing_loc;
6816 return (location != NULL) && (parser->start[PM_LOCATION_END(location) - 1] == ':');
6822static pm_symbol_node_t *
6823pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6824 pm_symbol_node_t *new_node = pm_symbol_node_new(
6827 PM_NODE_FLAG_STATIC_LITERAL,
6828 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
6829 TOK2LOC(parser, opening),
6831 TOK2LOC(parser, closing),
6835 pm_token_t content = {
6836 .type = PM_TOKEN_IDENTIFIER,
6837 .start = parser->start + node->content_loc.start,
6838 .end = parser->start + node->content_loc.start + node->content_loc.length
6841 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, parser->explicit_encoding, &content, &node->unescaped, true));
6843 /* The old node is arena-allocated so no explicit free is needed. */
6850static pm_string_node_t *
6851pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6852 pm_node_flags_t flags = 0;
6854 switch (parser->frozen_string_literal) {
6855 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6856 flags = PM_STRING_FLAGS_MUTABLE;
6858 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6859 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6863 pm_string_node_t *new_node = pm_string_node_new(
6867 PM_LOCATION_INIT_NODE(node),
6874 /* The old node is arena-allocated so no explicit free is needed. */
6881static pm_true_node_t *
6882pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6883 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6885 return pm_true_node_new(
6888 PM_NODE_FLAG_STATIC_LITERAL,
6889 PM_LOCATION_INIT_TOKEN(parser, token)
6896static pm_true_node_t *
6897pm_true_node_synthesized_create(pm_parser_t *parser) {
6898 return pm_true_node_new(
6901 PM_NODE_FLAG_STATIC_LITERAL,
6902 PM_LOCATION_INIT_UNSET
6909static pm_undef_node_t *
6910pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6911 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6913 return pm_undef_node_new(
6917 PM_LOCATION_INIT_TOKEN(parser, token),
6918 ((pm_node_list_t) { 0 }),
6919 TOK2LOC(parser, token)
6927pm_undef_node_append(pm_arena_t *arena, pm_undef_node_t *node, pm_node_t *name) {
6928 PM_NODE_LENGTH_SET_NODE(node, name);
6929 pm_node_list_append_inline(arena, &node->names, name);
6935static pm_unless_node_t *
6936pm_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) {
6937 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6938 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6940 return pm_unless_node_new(
6943 PM_NODE_FLAG_NEWLINE,
6944 PM_LOCATION_INIT_TOKEN_NODE(parser, keyword, end),
6945 TOK2LOC(parser, keyword),
6947 NTOK2LOC(parser, then_keyword),
6950 ((pm_location_t) { 0 })
6957static pm_unless_node_t *
6958pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6959 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6961 pm_statements_node_t *statements = pm_statements_node_create(parser);
6962 pm_statements_node_body_append(parser, statements, statement, true);
6964 return pm_unless_node_new(
6967 PM_NODE_FLAG_NEWLINE,
6968 PM_LOCATION_INIT_NODES(statement, predicate),
6969 TOK2LOC(parser, unless_keyword),
6971 ((pm_location_t) { 0 }),
6974 ((pm_location_t) { 0 })
6978static PRISM_INLINE void
6979pm_unless_node_end_keyword_loc_set(const pm_parser_t *parser, pm_unless_node_t *node, const pm_token_t *end_keyword) {
6980 node->end_keyword_loc = TOK2LOC(parser, end_keyword);
6981 PM_NODE_LENGTH_SET_TOKEN(parser, node, end_keyword);
6990pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
6991 assert(parser->current_block_exits != NULL);
6993 // All of the block exits that we want to remove should be within the
6994 // statements, and since we are modifying the statements, we shouldn't have
6995 // to check the end location.
6996 uint32_t start = statements->base.location.start;
6998 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
6999 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
7000 if (block_exit->location.start < start) break;
7002 // Implicitly remove from the list by lowering the size.
7003 parser->current_block_exits->size--;
7010static pm_until_node_t *
7011pm_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) {
7012 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7014 return pm_until_node_new(
7018 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7019 TOK2LOC(parser, keyword),
7020 NTOK2LOC(parser, do_keyword),
7021 TOK2LOC(parser, closing),
7030static pm_until_node_t *
7031pm_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) {
7032 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7033 pm_loop_modifier_block_exits(parser, statements);
7035 return pm_until_node_new(
7039 PM_LOCATION_INIT_NODES(statements, predicate),
7040 TOK2LOC(parser, keyword),
7041 ((pm_location_t) { 0 }),
7042 ((pm_location_t) { 0 }),
7051static pm_when_node_t *
7052pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
7053 return pm_when_node_new(
7057 PM_LOCATION_INIT_TOKEN(parser, keyword),
7058 TOK2LOC(parser, keyword),
7059 ((pm_node_list_t) { 0 }),
7060 ((pm_location_t) { 0 }),
7069pm_when_node_conditions_append(pm_arena_t *arena, pm_when_node_t *node, pm_node_t *condition) {
7070 PM_NODE_LENGTH_SET_NODE(node, condition);
7071 pm_node_list_append_inline(arena, &node->conditions, condition);
7077static PRISM_INLINE void
7078pm_when_node_then_keyword_loc_set(const pm_parser_t *parser, pm_when_node_t *node, const pm_token_t *then_keyword) {
7079 PM_NODE_LENGTH_SET_TOKEN(parser, node, then_keyword);
7080 node->then_keyword_loc = TOK2LOC(parser, then_keyword);
7087pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
7088 if (PM_NODE_END(statements) > PM_NODE_END(node)) {
7089 PM_NODE_LENGTH_SET_NODE(node, statements);
7092 node->statements = statements;
7098static pm_while_node_t *
7099pm_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) {
7100 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7102 return pm_while_node_new(
7106 PM_LOCATION_INIT_TOKENS(parser, keyword, closing),
7107 TOK2LOC(parser, keyword),
7108 NTOK2LOC(parser, do_keyword),
7109 TOK2LOC(parser, closing),
7118static pm_while_node_t *
7119pm_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) {
7120 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
7121 pm_loop_modifier_block_exits(parser, statements);
7123 return pm_while_node_new(
7127 PM_LOCATION_INIT_NODES(statements, predicate),
7128 TOK2LOC(parser, keyword),
7129 ((pm_location_t) { 0 }),
7130 ((pm_location_t) { 0 }),
7139static pm_while_node_t *
7140pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7141 return pm_while_node_new(
7145 PM_LOCATION_INIT_UNSET,
7146 ((pm_location_t) { 0 }),
7147 ((pm_location_t) { 0 }),
7148 ((pm_location_t) { 0 }),
7158static pm_x_string_node_t *
7159pm_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) {
7160 return pm_x_string_node_new(
7163 PM_STRING_FLAGS_FROZEN,
7164 PM_LOCATION_INIT_TOKENS(parser, opening, closing),
7165 TOK2LOC(parser, opening),
7166 TOK2LOC(parser, content),
7167 TOK2LOC(parser, closing),
7175static PRISM_INLINE pm_x_string_node_t *
7176pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7177 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7183static pm_yield_node_t *
7184pm_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) {
7185 uint32_t start = PM_TOKEN_START(parser, keyword);
7188 if (rparen_loc->length > 0) {
7189 end = PM_LOCATION_END(rparen_loc);
7190 } else if (arguments != NULL) {
7191 end = PM_NODE_END(arguments);
7192 } else if (lparen_loc->length > 0) {
7193 end = PM_LOCATION_END(lparen_loc);
7195 end = PM_TOKEN_END(parser, keyword);
7198 return pm_yield_node_new(
7202 ((pm_location_t) { .start = start, .length = U32(end - start) }),
7203 TOK2LOC(parser, keyword),
7215pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7216 pm_scope_t *scope = parser->current_scope;
7219 while (scope != NULL) {
7220 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7221 if (scope->closed) break;
7223 scope = scope->previous;
7235static PRISM_INLINE int
7236pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7237 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7243static PRISM_INLINE void
7244pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7245 pm_locals_write(&parser->scratch_arena, &parser->current_scope->locals, constant_id, U32(start - parser->start), U32(end - start), reads);
7251static pm_constant_id_t
7252pm_parser_local_add_raw(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7253 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
7254 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7261static PRISM_INLINE pm_constant_id_t
7262pm_parser_local_add_location(pm_parser_t *parser, pm_location_t *location, uint32_t reads) {
7263 return pm_parser_local_add_raw(parser, parser->start + location->start, parser->start + location->start + location->length, reads);
7269static PRISM_INLINE pm_constant_id_t
7270pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7271 return pm_parser_local_add_raw(parser, token->start, token->end, reads);
7277static pm_constant_id_t
7278pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7279 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7280 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7287static pm_constant_id_t
7288pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7289 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7290 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7302pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7303 // We want to check whether the parameter name is a numbered parameter or
7305 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, name), PM_TOKEN_LENGTH(name));
7307 // Otherwise we'll fetch the constant id for the parameter name and check
7308 // whether it's already in the current scope.
7309 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7311 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7312 // Add an error if the parameter doesn't start with _ and has been seen before
7313 if ((name->start < name->end) && (*name->start != '_')) {
7314 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7325pm_parser_scope_pop(pm_parser_t *parser) {
7326 pm_scope_t *scope = parser->current_scope;
7327 parser->current_scope = scope->previous;
7328 scope->previous = parser->free_scopes;
7329 parser->free_scopes = scope;
7332/******************************************************************************/
7334/******************************************************************************/
7339static PRISM_INLINE void
7340pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7341 *stack = (*stack << 1) | (value & 1);
7347static PRISM_INLINE void
7348pm_state_stack_pop(pm_state_stack_t *stack) {
7355static PRISM_INLINE bool
7356pm_state_stack_p(const pm_state_stack_t *stack) {
7360static PRISM_INLINE void
7361pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7362 // Use the negation of the value to prevent stack overflow.
7363 pm_state_stack_push(&parser->accepts_block_stack, !value);
7366static PRISM_INLINE void
7367pm_accepts_block_stack_pop(pm_parser_t *parser) {
7368 pm_state_stack_pop(&parser->accepts_block_stack);
7371static PRISM_INLINE bool
7372pm_accepts_block_stack_p(pm_parser_t *parser) {
7373 return !pm_state_stack_p(&parser->accepts_block_stack);
7376static PRISM_INLINE void
7377pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7378 pm_state_stack_push(&parser->do_loop_stack, value);
7381static PRISM_INLINE void
7382pm_do_loop_stack_pop(pm_parser_t *parser) {
7383 pm_state_stack_pop(&parser->do_loop_stack);
7386static PRISM_INLINE bool
7387pm_do_loop_stack_p(pm_parser_t *parser) {
7388 return pm_state_stack_p(&parser->do_loop_stack);
7420static PRISM_INLINE void
7421pm_enclosure_frame_push(pm_parser_t *parser) {
7422 pm_do_loop_stack_push(parser, false);
7423 pm_accepts_block_stack_push(parser, true);
7426static PRISM_INLINE void
7427pm_enclosure_frame_pop(pm_parser_t *parser) {
7428 pm_do_loop_stack_pop(parser);
7429 pm_accepts_block_stack_pop(parser);
7432/******************************************************************************/
7433/* Lexer check helpers */
7434/******************************************************************************/
7440static PRISM_INLINE uint8_t
7441peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7442 if (cursor < parser->end) {
7454static PRISM_INLINE uint8_t
7455peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7456 return peek_at(parser, parser->current.end + offset);
7463static PRISM_INLINE uint8_t
7464peek(const pm_parser_t *parser) {
7465 return peek_at(parser, parser->current.end);
7472static PRISM_INLINE bool
7473match(pm_parser_t *parser, uint8_t value) {
7474 if (peek(parser) == value) {
7475 parser->current.end++;
7485static PRISM_INLINE size_t
7486match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7487 if (peek_at(parser, cursor) == '\n') {
7490 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7501static PRISM_INLINE size_t
7502match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7503 return match_eol_at(parser, parser->current.end + offset);
7511static PRISM_INLINE size_t
7512match_eol(pm_parser_t *parser) {
7513 return match_eol_at(parser, parser->current.end);
7519static PRISM_INLINE const uint8_t *
7520next_newline(const uint8_t *cursor, ptrdiff_t length) {
7521 assert(length >= 0);
7523 // Note that it's okay for us to use memchr here to look for \n because none
7524 // of the encodings that we support have \n as a component of a multi-byte
7526 return memchr(cursor, '\n', (size_t) length);
7532static PRISM_INLINE bool
7533ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7534 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));
7542parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7543 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7545 if (encoding != NULL) {
7546 if (parser->encoding != encoding) {
7547 parser->encoding = encoding;
7548 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7551 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7563parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7564 const uint8_t *cursor = parser->current.start + 1;
7565 const uint8_t *end = parser->current.end;
7567 bool separator = false;
7569 if (end - cursor <= 6) return;
7570 switch (cursor[6]) {
7571 case 'C': case 'c': cursor += 6; continue;
7572 case 'O': case 'o': cursor += 5; continue;
7573 case 'D': case 'd': cursor += 4; continue;
7574 case 'I': case 'i': cursor += 3; continue;
7575 case 'N': case 'n': cursor += 2; continue;
7576 case 'G': case 'g': cursor += 1; continue;
7583 if (pm_char_is_whitespace(*cursor)) break;
7586 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7592 if (++cursor >= end) return;
7593 } while (pm_char_is_whitespace(*cursor));
7595 if (separator) break;
7596 if (*cursor != '=' && *cursor != ':') return;
7602 const uint8_t *value_start = cursor;
7603 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7605 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7606 // If we were unable to parse the encoding value, then we've got an
7607 // issue because we didn't understand the encoding that the user was
7608 // trying to use. In this case we'll keep using the default encoding but
7609 // add an error to the parser to indicate an unsuccessful parse.
7610 pm_parser_err(parser, U32(value_start - parser->start), U32(cursor - value_start), PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7615 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7616 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7617 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7618} pm_magic_comment_boolean_value_t;
7624static pm_magic_comment_boolean_value_t
7625parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7626 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7627 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7628 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7629 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7631 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7635static PRISM_INLINE bool
7636pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7637 return b == '\'' || b == '"' || b == ':' || b == ';';
7646parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7650 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor + 1,
'*', (
size_t) (end - cursor - 1), parser->encoding_changed, parser->encoding)) != NULL) {
7651 if (cursor[-1] ==
'-' && cursor + 1 < end && cursor[1] ==
'-') {
7666parser_magic_comment_key_p(
const uint8_t *key,
size_t key_length,
const char *name) {
7667 assert(name[key_length] ==
'\0');
7669 for (
size_t index = 0; index < key_length; index++) {
7670 uint8_t
byte = key[index];
7671 if (
byte ==
'-')
byte =
'_';
7672 if (
'A' <=
byte &&
byte <=
'Z')
byte |= 0x20;
7673 if (
byte != (uint8_t) name[index])
return false;
7690parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7693 const uint8_t *start = parser->current.start + 1;
7694 const uint8_t *end = parser->current.end;
7695 if (end - start <= 7)
return false;
7697 const uint8_t *cursor;
7698 bool indicator =
false;
7700 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7703 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7715 if (pm_memchr(start,
':', (
size_t) (end - start), parser->encoding_changed, parser->encoding) == NULL) {
7721 start += pm_strspn_whitespace(start, end - start);
7725 while (cursor < end) {
7727 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7730 const uint8_t *key_start = cursor;
7731 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7733 const uint8_t *key_end = cursor;
7734 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7735 if (cursor == end)
break;
7737 if (*cursor ==
':') {
7740 if (!indicator)
return false;
7744 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7745 if (cursor == end)
break;
7747 const uint8_t *value_start;
7748 const uint8_t *value_end;
7750 if (*cursor ==
'"') {
7751 value_start = ++cursor;
7752 for (; cursor < end && *cursor !=
'"'; cursor++) {
7753 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7756 if (cursor < end && *cursor ==
'"') cursor++;
7758 value_start = cursor;
7759 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7764 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7766 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7767 if (cursor != end)
return false;
7772 const size_t key_length = (size_t) (key_end - key_start);
7773 uint32_t value_length = (uint32_t) (value_end - value_start);
7775 switch (key_length) {
7780 if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7781 if (parser_magic_comment_key_p(key_start, key_length,
"coding")) {
7782 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7790 if (parser->current.start == parser->encoding_comment_start && !parser->encoding_locked) {
7791 if (parser_magic_comment_key_p(key_start, key_length,
"encoding")) {
7792 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7797 if (parser_magic_comment_key_p(key_start, key_length,
"warn_indent")) {
7798 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7799 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7800 PM_PARSER_WARN_TOKEN_FORMAT(
7803 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7807 (
const char *) value_start
7810 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7811 parser->warn_mismatched_indentation =
false;
7813 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7814 parser->warn_mismatched_indentation =
true;
7820 if (parser_magic_comment_key_p(key_start, key_length,
"frozen_string_literal")) {
7823 if (semantic_token_seen) {
7824 pm_parser_warn_token(parser, &parser->current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7826 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7827 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7828 PM_PARSER_WARN_TOKEN_FORMAT(
7831 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7833 "frozen_string_literal",
7835 (
const char *) value_start
7838 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7841 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7849 if (parser_magic_comment_key_p(key_start, key_length,
"shareable_constant_value")) {
7850 const uint8_t *cursor = parser->current.start;
7851 while ((cursor > parser->start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7853 if (!((cursor == parser->start) || (cursor[-1] ==
'\n'))) {
7854 pm_parser_warn_token(parser, &parser->current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7855 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7856 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7857 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7858 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7859 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7860 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7861 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7862 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7864 PM_PARSER_WARN_TOKEN_FORMAT(
7867 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7869 "shareable_constant_value",
7871 (
const char *) value_start
7893static const uint32_t context_terminators[] = {
7894 [PM_CONTEXT_NONE] = 0,
7895 [PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7896 [PM_CONTEXT_BEGIN_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7897 [PM_CONTEXT_BEGIN_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7898 [PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7899 [PM_CONTEXT_BLOCK_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7900 [PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7901 [PM_CONTEXT_BLOCK_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7902 [PM_CONTEXT_BLOCK_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7903 [PM_CONTEXT_BLOCK_PARAMETERS] = (1U << PM_TOKEN_PIPE),
7904 [PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7905 [PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7906 [PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7907 [PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7908 [PM_CONTEXT_CLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7909 [PM_CONTEXT_CLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7910 [PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7911 [PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7912 [PM_CONTEXT_DEF_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7913 [PM_CONTEXT_DEF_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7914 [PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7915 [PM_CONTEXT_DEF_PARAMS] = (1U << PM_TOKEN_EOF),
7916 [PM_CONTEXT_DEFINED] = (1U << PM_TOKEN_EOF),
7917 [PM_CONTEXT_DEFAULT_PARAMS] = (1U << PM_TOKEN_COMMA) | (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7918 [PM_CONTEXT_ELSE] = (1U << PM_TOKEN_KEYWORD_END),
7919 [PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7920 [PM_CONTEXT_EMBEXPR] = (1U << PM_TOKEN_EMBEXPR_END),
7921 [PM_CONTEXT_FOR] = (1U << PM_TOKEN_KEYWORD_END),
7922 [PM_CONTEXT_FOR_INDEX] = (1U << PM_TOKEN_KEYWORD_IN),
7923 [PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7924 [PM_CONTEXT_LAMBDA_BRACES] = (1U << PM_TOKEN_BRACE_RIGHT),
7925 [PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7926 [PM_CONTEXT_LAMBDA_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7927 [PM_CONTEXT_LAMBDA_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7928 [PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7929 [PM_CONTEXT_LOOP_PREDICATE] = (1U << PM_TOKEN_KEYWORD_DO) | (1U << PM_TOKEN_KEYWORD_THEN),
7930 [PM_CONTEXT_MAIN] = (1U << PM_TOKEN_EOF),
7931 [PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7932 [PM_CONTEXT_MODULE_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7933 [PM_CONTEXT_MODULE_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7934 [PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7935 [PM_CONTEXT_MULTI_TARGET] = (1U << PM_TOKEN_EOF),
7936 [PM_CONTEXT_PARENS] = (1U << PM_TOKEN_PARENTHESIS_RIGHT),
7937 [PM_CONTEXT_POSTEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7938 [PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7939 [PM_CONTEXT_PREEXE] = (1U << PM_TOKEN_BRACE_RIGHT),
7940 [PM_CONTEXT_RESCUE_MODIFIER] = (1U << PM_TOKEN_EOF),
7941 [PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7942 [PM_CONTEXT_SCLASS_ENSURE] = (1U << PM_TOKEN_KEYWORD_END),
7943 [PM_CONTEXT_SCLASS_ELSE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_END),
7944 [PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7945 [PM_CONTEXT_TERNARY] = (1U << PM_TOKEN_EOF),
7946 [PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7947 [PM_CONTEXT_UNTIL] = (1U << PM_TOKEN_KEYWORD_END),
7948 [PM_CONTEXT_WHILE] = (1U << PM_TOKEN_KEYWORD_END),
7952context_terminator(pm_context_t context,
pm_token_t *token) {
7953 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7964 while (context_node != NULL) {
7965 if (context_terminator(context_node->context, token))
return context_node->context;
7966 context_node = context_node->prev;
7969 return PM_CONTEXT_NONE;
7972PM_STATIC_ASSERT(__LINE__, PM_CONTEXT_MAXIMUM <= 64,
"Expected every context to fit in the context mask.");
7975context_push(
pm_parser_t *parser, pm_context_t context) {
7977 if (context_node != NULL) {
7978 parser->free_contexts = context_node->prev;
7987 .mask = (previous == NULL ? 0 : previous->mask) | ((uint64_t) 1 << context)
7990 parser->current_context = context_node;
7997 parser->current_context = context_node->prev;
7998 context_node->prev = parser->free_contexts;
7999 parser->free_contexts = context_node;
8003context_p(
const pm_parser_t *parser, pm_context_t context) {
8004 return parser->current_context != NULL && (parser->current_context->mask & ((uint64_t) 1 << context)) != 0;
8011 while (context_node != NULL) {
8012 switch (context_node->context) {
8013 case PM_CONTEXT_DEF:
8014 case PM_CONTEXT_DEF_PARAMS:
8015 case PM_CONTEXT_DEF_ENSURE:
8016 case PM_CONTEXT_DEF_RESCUE:
8017 case PM_CONTEXT_DEF_ELSE:
8019 case PM_CONTEXT_CLASS:
8020 case PM_CONTEXT_CLASS_ENSURE:
8021 case PM_CONTEXT_CLASS_RESCUE:
8022 case PM_CONTEXT_CLASS_ELSE:
8023 case PM_CONTEXT_MODULE:
8024 case PM_CONTEXT_MODULE_ENSURE:
8025 case PM_CONTEXT_MODULE_RESCUE:
8026 case PM_CONTEXT_MODULE_ELSE:
8027 case PM_CONTEXT_SCLASS:
8028 case PM_CONTEXT_SCLASS_ENSURE:
8029 case PM_CONTEXT_SCLASS_RESCUE:
8030 case PM_CONTEXT_SCLASS_ELSE:
8033 context_node = context_node->prev;
8045context_human(pm_context_t context) {
8047 case PM_CONTEXT_NONE:
8048 case PM_CONTEXT_MAXIMUM:
8049 assert(
false &&
"unreachable");
8051 case PM_CONTEXT_BEGIN:
return "begin statement";
8052 case PM_CONTEXT_BLOCK_BRACES:
return "'{'..'}' block";
8053 case PM_CONTEXT_BLOCK_KEYWORDS:
return "'do'..'end' block";
8054 case PM_CONTEXT_BLOCK_PARAMETERS:
return "'|'..'|' block parameter";
8055 case PM_CONTEXT_CASE_WHEN:
return "'when' clause";
8056 case PM_CONTEXT_CASE_IN:
return "'in' clause";
8057 case PM_CONTEXT_CLASS:
return "class definition";
8058 case PM_CONTEXT_DEF:
return "method definition";
8059 case PM_CONTEXT_DEF_PARAMS:
return "method parameters";
8060 case PM_CONTEXT_DEFAULT_PARAMS:
return "parameter default value";
8061 case PM_CONTEXT_DEFINED:
return "'defined?' expression";
8062 case PM_CONTEXT_ELSE:
8063 case PM_CONTEXT_BEGIN_ELSE:
8064 case PM_CONTEXT_BLOCK_ELSE:
8065 case PM_CONTEXT_CLASS_ELSE:
8066 case PM_CONTEXT_DEF_ELSE:
8067 case PM_CONTEXT_LAMBDA_ELSE:
8068 case PM_CONTEXT_MODULE_ELSE:
8069 case PM_CONTEXT_SCLASS_ELSE:
return "'else' clause";
8070 case PM_CONTEXT_ELSIF:
return "'elsif' clause";
8071 case PM_CONTEXT_EMBEXPR:
return "embedded expression";
8072 case PM_CONTEXT_BEGIN_ENSURE:
8073 case PM_CONTEXT_BLOCK_ENSURE:
8074 case PM_CONTEXT_CLASS_ENSURE:
8075 case PM_CONTEXT_DEF_ENSURE:
8076 case PM_CONTEXT_LAMBDA_ENSURE:
8077 case PM_CONTEXT_MODULE_ENSURE:
8078 case PM_CONTEXT_SCLASS_ENSURE:
return "'ensure' clause";
8079 case PM_CONTEXT_FOR:
return "for loop";
8080 case PM_CONTEXT_FOR_INDEX:
return "for loop index";
8081 case PM_CONTEXT_IF:
return "if statement";
8082 case PM_CONTEXT_LAMBDA_BRACES:
return "'{'..'}' lambda block";
8083 case PM_CONTEXT_LAMBDA_DO_END:
return "'do'..'end' lambda block";
8084 case PM_CONTEXT_LOOP_PREDICATE:
return "loop predicate";
8085 case PM_CONTEXT_MAIN:
return "top level context";
8086 case PM_CONTEXT_MODULE:
return "module definition";
8087 case PM_CONTEXT_MULTI_TARGET:
return "multiple targets";
8088 case PM_CONTEXT_PARENS:
return "parentheses";
8089 case PM_CONTEXT_POSTEXE:
return "'END' block";
8090 case PM_CONTEXT_PREDICATE:
return "predicate";
8091 case PM_CONTEXT_PREEXE:
return "'BEGIN' block";
8092 case PM_CONTEXT_BEGIN_RESCUE:
8093 case PM_CONTEXT_BLOCK_RESCUE:
8094 case PM_CONTEXT_CLASS_RESCUE:
8095 case PM_CONTEXT_DEF_RESCUE:
8096 case PM_CONTEXT_LAMBDA_RESCUE:
8097 case PM_CONTEXT_MODULE_RESCUE:
8098 case PM_CONTEXT_RESCUE_MODIFIER:
8099 case PM_CONTEXT_SCLASS_RESCUE:
return "'rescue' clause";
8100 case PM_CONTEXT_SCLASS:
return "singleton class definition";
8101 case PM_CONTEXT_TERNARY:
return "ternary expression";
8102 case PM_CONTEXT_UNLESS:
return "unless statement";
8103 case PM_CONTEXT_UNTIL:
return "until statement";
8104 case PM_CONTEXT_WHILE:
return "while statement";
8107 assert(
false &&
"unreachable");
8116pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
8117 if (invalid != NULL) {
8118 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
8119 pm_parser_err(parser, U32(invalid - parser->start), 1, diag_id);
8124pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8125 const uint8_t *invalid = NULL;
8126 size_t length = pm_strspn_binary_number(
string, parser->end -
string, &invalid);
8127 pm_strspn_number_validate(parser,
string, length, invalid);
8132pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8133 const uint8_t *invalid = NULL;
8134 size_t length = pm_strspn_octal_number(
string, parser->end -
string, &invalid);
8135 pm_strspn_number_validate(parser,
string, length, invalid);
8140pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8141 const uint8_t *invalid = NULL;
8142 size_t length = pm_strspn_decimal_number(
string, parser->end -
string, &invalid);
8143 pm_strspn_number_validate(parser,
string, length, invalid);
8148pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
8149 const uint8_t *invalid = NULL;
8150 size_t length = pm_strspn_hexadecimal_number(
string, parser->end -
string, &invalid);
8151 pm_strspn_number_validate(parser,
string, length, invalid);
8155static pm_token_type_t
8156lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
8157 pm_token_type_t
type = PM_TOKEN_INTEGER;
8161 if (peek(parser) ==
'.') {
8162 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8163 parser->current.end += 2;
8164 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8165 type = PM_TOKEN_FLOAT;
8175 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
8176 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
8177 parser->current.end += 2;
8179 if (pm_char_is_decimal_digit(peek(parser))) {
8180 parser->current.end++;
8181 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8183 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
8185 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8186 parser->current.end++;
8187 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8193 type = PM_TOKEN_FLOAT;
8199static pm_token_type_t
8200lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8201 pm_token_type_t
type = PM_TOKEN_INTEGER;
8204 if (peek_offset(parser, -1) ==
'0') {
8205 switch (*parser->current.end) {
8209 parser->current.end++;
8210 if (pm_char_is_decimal_digit(peek(parser))) {
8211 parser->current.end += pm_strspn_decimal_number_validate(parser, parser->current.end);
8214 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8222 parser->current.end++;
8223 if (pm_char_is_binary_digit(peek(parser))) {
8224 parser->current.end += pm_strspn_binary_number_validate(parser, parser->current.end);
8227 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8230 parser->integer.base = PM_INTEGER_BASE_FLAGS_BINARY;
8236 parser->current.end++;
8237 if (pm_char_is_octal_digit(peek(parser))) {
8238 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8241 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8244 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8257 parser->current.end += pm_strspn_octal_number_validate(parser, parser->current.end);
8258 parser->integer.base = PM_INTEGER_BASE_FLAGS_OCTAL;
8264 parser->current.end++;
8265 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8266 parser->current.end += pm_strspn_hexadecimal_number_validate(parser, parser->current.end);
8269 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8272 parser->integer.base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8277 type = lex_optional_float_suffix(parser, seen_e);
8284 type = lex_optional_float_suffix(parser, seen_e);
8293 const uint8_t *cursor = parser->current.end;
8294 const uint8_t *end = parser->end;
8295 uint64_t value = (uint64_t) (cursor[-1] -
'0');
8297 bool has_underscore =
false;
8298 bool prev_underscore =
false;
8299 const uint8_t *invalid = NULL;
8301 while (cursor < end) {
8302 uint8_t c = *cursor;
8303 if (c >=
'0' && c <=
'9') {
8304 if (value <= UINT32_MAX) value = value * 10 + (uint64_t) (c -
'0');
8305 prev_underscore =
false;
8307 }
else if (c ==
'_') {
8308 has_underscore =
true;
8309 if (prev_underscore && invalid == NULL) invalid = cursor;
8310 prev_underscore =
true;
8317 if (has_underscore) {
8318 if (prev_underscore && invalid == NULL) invalid = cursor - 1;
8319 pm_strspn_number_validate(parser, parser->current.end, (
size_t) (cursor - parser->current.end), invalid);
8322 if (value <= UINT32_MAX) {
8323 parser->integer.value = (uint32_t) value;
8324 parser->integer.lexed =
true;
8327 parser->current.end = cursor;
8335 uint8_t next = peek(parser);
8336 if (next ==
'.' || next ==
'e' || next ==
'E') {
8337 type = lex_optional_float_suffix(parser, seen_e);
8341 if (
type != PM_TOKEN_INTEGER) {
8342 parser->integer.lexed =
false;
8351 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8352 const uint8_t *fraction_start = parser->current.end;
8353 const uint8_t *fraction_end = parser->current.end + 2;
8354 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->end - fraction_end);
8355 pm_parser_err(parser, U32(fraction_start - parser->start), U32(fraction_end - fraction_start), PM_ERR_INVALID_NUMBER_FRACTION);
8361static pm_token_type_t
8363 pm_token_type_t
type = PM_TOKEN_INTEGER;
8364 parser->integer.base = PM_INTEGER_BASE_FLAGS_DECIMAL;
8365 parser->integer.lexed =
false;
8367 if (parser->current.end < parser->end) {
8368 bool seen_e =
false;
8369 type = lex_numeric_prefix(parser, &seen_e);
8371 const uint8_t *end = parser->current.end;
8372 pm_token_type_t suffix_type =
type;
8374 if (
type == PM_TOKEN_INTEGER) {
8375 if (match(parser,
'r')) {
8376 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8378 if (match(parser,
'i')) {
8379 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8381 }
else if (match(parser,
'i')) {
8382 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8385 if (!seen_e && match(parser,
'r')) {
8386 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8388 if (match(parser,
'i')) {
8389 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8391 }
else if (match(parser,
'i')) {
8392 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8396 const uint8_t b = peek(parser);
8397 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8398 parser->current.end = end;
8407static pm_token_type_t
8409 if (parser->current.end >= parser->end) {
8410 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8411 return PM_TOKEN_GLOBAL_VARIABLE;
8416 bool allow_multiple =
true;
8418 switch (*parser->current.end) {
8435 parser->current.end++;
8436 return PM_TOKEN_GLOBAL_VARIABLE;
8442 parser->current.end++;
8443 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8446 parser->current.end++;
8449 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8451 parser->current.end += width;
8452 }
while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8455 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;
8456 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->current, diag_id);
8459 return PM_TOKEN_GLOBAL_VARIABLE;
8471 parser->current.end += pm_strspn_decimal_digit(parser->current.end, parser->end - parser->current.end);
8472 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8475 parser->current.end++;
8476 allow_multiple =
false;
8481 if ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0) {
8483 parser->current.end += width;
8484 }
while (allow_multiple && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) > 0);
8485 }
else if (pm_char_is_whitespace(peek(parser))) {
8488 pm_parser_err_token(parser, &parser->current, PM_ERR_GLOBAL_VARIABLE_BARE);
8492 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;
8493 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
8494 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);
8497 return PM_TOKEN_GLOBAL_VARIABLE;
8515 pm_lex_state_t state;
8518 pm_token_type_t
type;
8522 pm_token_type_t modifier_type;
8528#define PM_KEYWORD_LENGTH_MAXIMUM 12
8534#define PM_KEYWORD_PACK(first, middle, last, length) \
8535 ((uint32_t) (first) | ((uint32_t) (middle) << 8) | ((uint32_t) (last) << 16) | ((uint32_t) (length) << 24))
8541#define PM_KEYWORD_SLOT_BITS 6
8556#define PM_KEYWORD_SLOT(packed) ((uint32_t) ((uint32_t) (packed) * 0x75f796ddU) >> (32 - PM_KEYWORD_SLOT_BITS))
8562#define PM_KEYWORD(name, first, middle, last, state, type, modifier_type) \
8563 [PM_KEYWORD_SLOT(PM_KEYWORD_PACK(first, middle, last, sizeof(name) - 1))] = { name, PM_KEYWORD_PACK(first, middle, last, sizeof(name) - 1), state, type, modifier_type }
8570static const pm_keyword_t pm_keywords[1 << PM_KEYWORD_SLOT_BITS] = {
8571 PM_KEYWORD(
"do",
'd',
'o',
'o', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF),
8572 PM_KEYWORD(
"if",
'i',
'f',
'f', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IF, PM_TOKEN_KEYWORD_IF_MODIFIER),
8573 PM_KEYWORD(
"in",
'i',
'n',
'n', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF),
8574 PM_KEYWORD(
"or",
'o',
'r',
'r', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_OR, PM_TOKEN_EOF),
8575 PM_KEYWORD(
"and",
'a',
'n',
'd', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF),
8576 PM_KEYWORD(
"def",
'd',
'e',
'f', PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF),
8577 PM_KEYWORD(
"end",
'e',
'n',
'd', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF),
8578 PM_KEYWORD(
"END",
'E',
'N',
'D', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF),
8579 PM_KEYWORD(
"for",
'f',
'o',
'r', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF),
8580 PM_KEYWORD(
"nil",
'n',
'i',
'l', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF),
8581 PM_KEYWORD(
"not",
'n',
'o',
't', PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_NOT, PM_TOKEN_EOF),
8582 PM_KEYWORD(
"case",
'c',
's',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF),
8583 PM_KEYWORD(
"else",
'e',
's',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF),
8584 PM_KEYWORD(
"next",
'n',
'x',
't', PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF),
8585 PM_KEYWORD(
"redo",
'r',
'd',
'o', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF),
8586 PM_KEYWORD(
"self",
's',
'l',
'f', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF),
8587 PM_KEYWORD(
"then",
't',
'e',
'n', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF),
8588 PM_KEYWORD(
"true",
't',
'u',
'e', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF),
8589 PM_KEYWORD(
"when",
'w',
'e',
'n', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_EOF),
8590 PM_KEYWORD(
"alias",
'a',
'i',
's', PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_ALIAS, PM_TOKEN_EOF),
8591 PM_KEYWORD(
"begin",
'b',
'g',
'n', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF),
8592 PM_KEYWORD(
"BEGIN",
'B',
'G',
'N', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF),
8593 PM_KEYWORD(
"break",
'b',
'e',
'k', PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF),
8594 PM_KEYWORD(
"class",
'c',
'a',
's', PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF),
8595 PM_KEYWORD(
"elsif",
'e',
's',
'f', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF),
8596 PM_KEYWORD(
"false",
'f',
'l',
'e', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF),
8597 PM_KEYWORD(
"retry",
'r',
't',
'y', PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF),
8598 PM_KEYWORD(
"super",
's',
'p',
'r', PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF),
8599 PM_KEYWORD(
"undef",
'u',
'd',
'f', PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_UNDEF, PM_TOKEN_EOF),
8600 PM_KEYWORD(
"until",
'u',
't',
'l', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNTIL, PM_TOKEN_KEYWORD_UNTIL_MODIFIER),
8601 PM_KEYWORD(
"while",
'w',
'i',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHILE, PM_TOKEN_KEYWORD_WHILE_MODIFIER),
8602 PM_KEYWORD(
"yield",
'y',
'e',
'd', PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_YIELD, PM_TOKEN_EOF),
8603 PM_KEYWORD(
"ensure",
'e',
'u',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF),
8604 PM_KEYWORD(
"module",
'm',
'u',
'e', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF),
8605 PM_KEYWORD(
"rescue",
'r',
'c',
'e', PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_RESCUE_MODIFIER),
8606 PM_KEYWORD(
"return",
'r',
'u',
'n', PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF),
8607 PM_KEYWORD(
"unless",
'u',
'e',
's', PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNLESS, PM_TOKEN_KEYWORD_UNLESS_MODIFIER),
8608 PM_KEYWORD(
"defined?",
'd',
'n',
'?', PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF),
8609 PM_KEYWORD(
"__LINE__",
'_',
'N',
'_', PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF),
8610 PM_KEYWORD(
"__FILE__",
'_',
'L',
'_', PM_LEX_STATE_END, PM_TOKEN_KEYWORD___FILE__, PM_TOKEN_EOF),
8611 PM_KEYWORD(
"__ENCODING__",
'_',
'D',
'_', PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)
8621pm_keyword_find(
const uint8_t *start,
const uint8_t *end) {
8622 ptrdiff_t width = end - start;
8623 if (width < 2 || width > PM_KEYWORD_LENGTH_MAXIMUM)
return NULL;
8625 size_t uwidth = (size_t) width;
8626 uint32_t packed = PM_KEYWORD_PACK(start[0], start[uwidth >> 1], start[uwidth - 1], uwidth);
8628 const pm_keyword_t *keyword = &pm_keywords[PM_KEYWORD_SLOT(packed)];
8629 return (keyword->packed == packed && memcmp(start + 1, keyword->name + 1, uwidth - 2) == 0) ? keyword : NULL;
8637pm_keyword_p(
const uint8_t *start,
const uint8_t *end) {
8638 return pm_keyword_find(start, end) != NULL;
8641static pm_token_type_t
8642lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8644 const uint8_t *end = parser->end;
8645 const uint8_t *current_start = parser->current.start;
8646 const uint8_t *current_end = parser->current.end;
8647 bool encoding_changed = parser->encoding_changed;
8649 if (encoding_changed) {
8651 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8652 current_end += width;
8656 current_end += scan_identifier_ascii(current_end, end);
8660 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8661 current_end += width;
8665 parser->current.end = current_end;
8669 bool method_name =
false;
8671 if (current_end < end) {
8672 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8678 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8679 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8683 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8684 (void) match(parser,
':');
8688 parser->explicit_encoding = NULL;
8689 return PM_TOKEN_LABEL;
8693 }
else if (lex_state_p(parser, PM_LEX_STATE_FNAME) && peek_offset(parser, 1) !=
'~' && peek_offset(parser, 1) !=
'>' && (peek_offset(parser, 1) !=
'=' || peek_offset(parser, 2) ==
'>') && match(parser,
'=')) {
8696 return PM_TOKEN_IDENTIFIER;
8698 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8699 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8703 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8704 (void) match(parser,
':');
8708 parser->explicit_encoding = NULL;
8709 return PM_TOKEN_LABEL;
8713 if (parser->lex_state != PM_LEX_STATE_DOT) {
8717 pm_lex_state_t previous_lex_state = parser->lex_state;
8718 const pm_keyword_t *keyword = pm_keyword_find(current_start, current_end);
8720 if (keyword != NULL) {
8721 if (previous_lex_state & PM_LEX_STATE_FNAME) {
8722 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8724 lex_state_set(parser, keyword->state);
8725 if (keyword->state == PM_LEX_STATE_BEG) {
8726 parser->command_start =
true;
8729 if ((keyword->modifier_type != PM_TOKEN_EOF) && !(previous_lex_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8730 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8731 return keyword->modifier_type;
8735 if (keyword->type == PM_TOKEN_KEYWORD_DO) {
8740 if (previous_lex_state & PM_LEX_STATE_FNAME) {
8741 return PM_TOKEN_KEYWORD_DO;
8743 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
8754 parser->lambda_enclosure_nesting = -1;
8755 return PM_TOKEN_KEYWORD_DO_LAMBDA;
8757 if (pm_do_loop_stack_p(parser)) {
8758 return PM_TOKEN_KEYWORD_DO_LOOP;
8760 if (!pm_accepts_block_stack_p(parser)) {
8761 return PM_TOKEN_KEYWORD_DO_BLOCK;
8763 return PM_TOKEN_KEYWORD_DO;
8766 return keyword->type;
8771 return PM_TOKEN_METHOD_NAME;
8774 if (encoding_changed) {
8775 return parser->encoding->isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8781 if (*current_start < 0x80) {
8782 return (*current_start >=
'A' && *current_start <=
'Z') ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8784 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8793 return (parser->current.start == parser->start) || (parser->current.start[-1] ==
'\n');
8810static pm_token_type_t
8811lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8814 if (pound + 1 >= parser->end) {
8815 parser->current.end = pound + 1;
8816 return PM_TOKEN_STRING_CONTENT;
8825 if (pound + 2 >= parser->end) {
8826 parser->current.end = pound + 1;
8827 return PM_TOKEN_STRING_CONTENT;
8832 const uint8_t *variable = pound + 2;
8833 if (*variable ==
'@' && pound + 3 < parser->end) variable++;
8835 if (char_is_identifier_start(parser, variable, parser->end - variable)) {
8839 if (pound > parser->current.start) {
8840 parser->current.end = pound;
8841 return PM_TOKEN_STRING_CONTENT;
8846 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8847 parser->current.end = pound + 1;
8848 return PM_TOKEN_EMBVAR;
8854 parser->current.end = pound + 1;
8860 if (pound + 2 >= parser->end) {
8861 parser->current.end = pound + 1;
8862 return PM_TOKEN_STRING_CONTENT;
8868 const uint8_t *check = pound + 2;
8870 if (pound[2] ==
'-') {
8871 if (pound + 3 >= parser->end) {
8872 parser->current.end = pound + 2;
8873 return PM_TOKEN_STRING_CONTENT;
8884 char_is_identifier_start(parser, check, parser->end - check) ||
8885 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8890 if (pound > parser->current.start) {
8891 parser->current.end = pound;
8892 return PM_TOKEN_STRING_CONTENT;
8897 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8898 parser->current.end = pound + 1;
8899 return PM_TOKEN_EMBVAR;
8904 parser->current.end = pound + 1;
8910 if (pound > parser->current.start) {
8911 parser->current.end = pound;
8912 return PM_TOKEN_STRING_CONTENT;
8915 parser->enclosure_nesting++;
8919 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8920 parser->current.end = pound + 2;
8921 parser->command_start =
true;
8922 pm_enclosure_frame_push(parser);
8923 return PM_TOKEN_EMBEXPR_BEGIN;
8928 parser->current.end = pound + 1;
8933static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8934static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8935static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8936static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8937static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8942static const bool ascii_printable_chars[] = {
8943 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8944 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8945 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8946 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8947 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8948 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8949 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8950 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8954char_is_ascii_printable(
const uint8_t b) {
8955 return (b < 0x80) && ascii_printable_chars[b];
8963escape_hexadecimal_digit(
const uint8_t value) {
8964 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8973escape_unicode(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const pm_location_t *error_location,
const uint8_t flags) {
8975 for (
size_t index = 0; index < length; index++) {
8976 if (index != 0) value <<= 4;
8977 value |= escape_hexadecimal_digit(
string[index]);
8982 if (value >= 0xD800 && value <= 0xDFFF) {
8983 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8986 }
else if (error_location != NULL) {
8987 pm_parser_err(parser, error_location->
start, error_location->
length, PM_ERR_ESCAPE_INVALID_UNICODE);
8989 pm_parser_err(parser, U32(
string - parser->start), U32(length), PM_ERR_ESCAPE_INVALID_UNICODE);
9001escape_byte(uint8_t value,
const uint8_t flags) {
9002 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
9003 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
9011escape_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) {
9015 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
9016 if (parser->explicit_encoding != NULL && parser->explicit_encoding != PM_ENCODING_UTF_8_ENTRY) {
9017 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9021 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(end - start), PM_ERR_MIXED_ENCODING, parser->explicit_encoding->name);
9025 parser->explicit_encoding = PM_ENCODING_UTF_8_ENTRY;
9028 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
9029 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9033 pm_parser_err(parser, U32(start - parser->start), U32(end - start), PM_ERR_ESCAPE_INVALID_UNICODE);
9036 pm_buffer_append_byte(buffer, 0xEF);
9037 pm_buffer_append_byte(buffer, 0xBF);
9038 pm_buffer_append_byte(buffer, 0xBD);
9049 if (parser->explicit_encoding != NULL && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
9050 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9054 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_MIXED_ENCODING, parser->encoding->name);
9058 parser->explicit_encoding = parser->encoding;
9061 pm_buffer_append_byte(buffer,
byte);
9081 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9082 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
9085 escape_write_byte_encoded(parser, buffer, flags,
byte);
9094 if (parser->encoding_changed) {
9095 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9097 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9101 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);
9102 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->current.end++, flags));
9103 }
else if (width > 1) {
9105 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
9106 pm_buffer_append_bytes(b, parser->current.end, width);
9107 parser->current.end += width;
9111 parser->current.end++;
9112 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9122escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
9123#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
9125 PM_PARSER_WARN_TOKEN_FORMAT(
9128 PM_WARN_INVALID_CHARACTER,
9149 switch (peeked = peek(parser)) {
9151 parser->current.end++;
9152 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
9156 parser->current.end++;
9157 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
9161 parser->current.end++;
9162 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
9166 parser->current.end++;
9167 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
9171 parser->current.end++;
9172 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
9176 parser->current.end++;
9177 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
9181 parser->current.end++;
9182 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
9186 parser->current.end++;
9187 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
9191 parser->current.end++;
9192 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
9196 parser->current.end++;
9197 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
9201 parser->current.end++;
9202 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
9205 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
9206 uint8_t value = (uint8_t) (*parser->current.end -
'0');
9207 parser->current.end++;
9209 if (pm_char_is_octal_digit(peek(parser))) {
9210 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9211 parser->current.end++;
9213 if (pm_char_is_octal_digit(peek(parser))) {
9214 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->current.end -
'0'));
9215 parser->current.end++;
9219 value = escape_byte(value, flags);
9220 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
9224 const uint8_t *start = parser->current.end - 1;
9226 parser->current.end++;
9227 uint8_t
byte = peek(parser);
9229 if (pm_char_is_hexadecimal_digit(
byte)) {
9230 uint8_t value = escape_hexadecimal_digit(
byte);
9231 parser->current.end++;
9233 byte = peek(parser);
9234 if (pm_char_is_hexadecimal_digit(
byte)) {
9235 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
9236 parser->current.end++;
9239 value = escape_byte(value, flags);
9240 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9241 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
9242 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
9244 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9248 escape_write_byte_encoded(parser, buffer, flags, value);
9250 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
9256 const uint8_t *start = parser->current.end - 1;
9257 parser->current.end++;
9259 if (parser->current.end == parser->end) {
9260 const uint8_t *start = parser->current.end - 2;
9261 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9262 }
else if (peek(parser) ==
'{') {
9263 const uint8_t *unicode_codepoints_start = parser->current.end - 2;
9264 parser->current.end++;
9268 if ((whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end)) > 0) {
9269 parser->current.end += whitespace;
9270 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
9275 parser->current.end += 2;
9281 const uint8_t *extra_codepoints_start = NULL;
9282 int codepoints_count = 0;
9284 while ((parser->current.end < parser->end) && (*parser->current.end !=
'}')) {
9285 const uint8_t *unicode_start = parser->current.end;
9286 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->current.end, parser->end - parser->current.end);
9288 if (hexadecimal_length > 6) {
9290 pm_parser_err(parser, U32(unicode_start - parser->start), U32(hexadecimal_length), PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
9291 }
else if (hexadecimal_length == 0) {
9294 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9299 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9301 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE);
9302 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->current), 0, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9308 parser->current.end += hexadecimal_length;
9310 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
9311 extra_codepoints_start = unicode_start;
9314 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL, flags);
9315 escape_write_unicode(parser, buffer, flags, unicode_start, parser->current.end, value);
9317 parser->current.end += pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
9322 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
9323 pm_parser_err(parser, U32(extra_codepoints_start - parser->start), U32(parser->current.end - 1 - extra_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
9326 if (parser->current.end == parser->end) {
9327 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);
9328 }
else if (peek(parser) ==
'}') {
9329 parser->current.end++;
9331 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9336 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9338 pm_parser_err(parser, U32(unicode_codepoints_start - parser->start), U32(parser->current.end - unicode_codepoints_start), PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
9342 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9343 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->current.end - unicode_codepoints_start));
9346 size_t length = pm_strspn_hexadecimal_digit(parser->current.end, MIN(parser->end - parser->current.end, 4));
9349 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9350 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9352 const uint8_t *start = parser->current.end - 2;
9353 PM_PARSER_ERR_FORMAT(parser, U32(start - parser->start), U32(parser->current.end - start), PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
9355 }
else if (length == 4) {
9356 uint32_t value = escape_unicode(parser, parser->current.end, 4, NULL, flags);
9358 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9359 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end + 4 - start));
9362 escape_write_unicode(parser, buffer, flags, start, parser->current.end + 4, value);
9363 parser->current.end += 4;
9365 parser->current.end += length;
9367 if (flags & PM_ESCAPE_FLAG_REGEXP) {
9371 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->current.end - start));
9373 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9381 parser->current.end++;
9382 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9383 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9386 if (parser->current.end == parser->end) {
9387 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9391 uint8_t peeked = peek(parser);
9394 parser->current.end++;
9395 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9399 parser->current.end++;
9401 if (match(parser,
'u') || match(parser,
'U')) {
9402 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9406 flags |= PM_ESCAPE_FLAG_CONTROL;
9407 goto escape_read_next;
9409 parser->current.end++;
9410 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9411 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9414 parser->current.end++;
9415 escape_read_warn(parser, flags, 0,
"\\t");
9416 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9419 if (!char_is_ascii_printable(peeked)) {
9420 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9424 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);
9425 parser->current.end++;
9426 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9432 parser->current.end++;
9433 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9434 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9437 if (peek(parser) !=
'-') {
9438 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9439 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_CONTROL);
9443 parser->current.end++;
9444 if (parser->current.end == parser->end) {
9445 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9449 uint8_t peeked = peek(parser);
9452 parser->current.end++;
9453 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
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 flags |= PM_ESCAPE_FLAG_CONTROL;
9465 goto escape_read_next;
9467 parser->current.end++;
9468 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9469 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9472 parser->current.end++;
9473 escape_read_warn(parser, flags, 0,
"\\t");
9474 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
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_CONTROL);
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_CONTROL));
9491 parser->current.end++;
9492 if (flags & PM_ESCAPE_FLAG_META) {
9493 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9496 if (peek(parser) !=
'-') {
9497 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9498 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9502 parser->current.end++;
9503 if (parser->current.end == parser->end) {
9504 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9508 uint8_t peeked = peek(parser);
9511 parser->current.end++;
9513 if (match(parser,
'u') || match(parser,
'U')) {
9514 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current), PM_ERR_INVALID_ESCAPE_CHARACTER);
9518 flags |= PM_ESCAPE_FLAG_META;
9519 goto escape_read_next;
9521 parser->current.end++;
9522 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9523 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9526 parser->current.end++;
9527 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9528 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9531 if (!char_is_ascii_printable(peeked)) {
9532 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9533 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9537 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);
9538 parser->current.end++;
9539 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9544 if (peek_offset(parser, 1) ==
'\n') {
9545 if (parser->heredoc_end == NULL) pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 2);
9546 parser->current.end += 2;
9547 escape_write_byte_encoded(parser, buffer, flags, escape_byte(
'\n', flags));
9553 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9554 size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9555 pm_parser_err(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current) + U32(width), PM_ERR_ESCAPE_INVALID_META);
9558 if (parser->current.end < parser->end) {
9559 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9561 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9593static pm_token_type_t
9595 if (lex_state_end_p(parser)) {
9596 lex_state_set(parser, PM_LEX_STATE_BEG);
9597 return PM_TOKEN_QUESTION_MARK;
9605 parser->explicit_encoding = NULL;
9607 if (parser->current.end >= parser->end) {
9608 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9609 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9610 return PM_TOKEN_CHARACTER_LITERAL;
9613 if (pm_char_is_whitespace(*parser->current.end)) {
9614 lex_state_set(parser, PM_LEX_STATE_BEG);
9615 return PM_TOKEN_QUESTION_MARK;
9618 lex_state_set(parser, PM_LEX_STATE_BEG);
9620 if (match(parser,
'\\')) {
9621 lex_state_set(parser, PM_LEX_STATE_END);
9624 pm_buffer_init(&buffer, 3);
9626 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9629 void *arena_data = pm_arena_memdup(parser->arena, buffer.value, buffer.length,
PRISM_ALIGNOF(uint8_t));
9630 pm_string_init(&parser->current_string, (
const uint8_t *) arena_data, buffer.length);
9631 pm_buffer_cleanup(&buffer);
9633 return PM_TOKEN_CHARACTER_LITERAL;
9635 size_t encoding_width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9640 !(parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end) || peek(parser) ==
'_') ||
9642 (parser->current.end + encoding_width >= parser->end) ||
9643 !char_is_identifier(parser, parser->current.end + encoding_width, parser->end - (parser->current.end + encoding_width))
9646 lex_state_set(parser, PM_LEX_STATE_END);
9647 parser->current.end += encoding_width;
9648 pm_string_shared_init(&parser->current_string, parser->current.start + 1, parser->current.end);
9649 return PM_TOKEN_CHARACTER_LITERAL;
9653 return PM_TOKEN_QUESTION_MARK;
9660static pm_token_type_t
9662 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9663 const uint8_t *end = parser->end;
9666 if ((width = char_is_identifier_start(parser, parser->current.end, end - parser->current.end)) > 0) {
9667 parser->current.end += width;
9669 while ((width = char_is_identifier(parser, parser->current.end, end - parser->current.end)) > 0) {
9670 parser->current.end += width;
9672 }
else if (parser->current.end < end && pm_char_is_decimal_digit(*parser->current.end)) {
9673 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9674 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) {
9675 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9678 size_t width = parser->encoding->char_width(parser->current.end, end - parser->current.end);
9679 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, (
int) ((parser->current.end + width) - parser->current.start), (
const char *) parser->current.start);
9681 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9682 pm_parser_err_token(parser, &parser->current, diag_id);
9687 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
9688 lex_mode_pop(parser);
9699 if (parser->lex_callback.callback) {
9700 parser->lex_callback.callback(parser, &parser->current, parser->lex_callback.data);
9713 .location = TOK2LOC(parser, &parser->current)
9724static pm_token_type_t
9727 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9729 if (newline == NULL) {
9730 parser->current.end = parser->end;
9732 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9733 parser->current.end = newline + 1;
9736 parser->current.type = PM_TOKEN_EMBDOC_BEGIN;
9737 parser_lex_callback(parser);
9740 const uint8_t *comment_start = parser->current.start;
9741 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9745 while (parser->current.end + 4 <= parser->end) {
9746 parser->current.start = parser->current.end;
9751 (memcmp(parser->current.end,
"=end", 4) == 0) &&
9753 (parser->current.end + 4 == parser->end) ||
9754 pm_char_is_whitespace(parser->current.end[4]) ||
9755 (parser->current.end[4] ==
'\0') ||
9756 (parser->current.end[4] ==
'\004') ||
9757 (parser->current.end[4] ==
'\032')
9760 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9762 if (newline == NULL) {
9763 parser->current.end = parser->end;
9765 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9766 parser->current.end = newline + 1;
9769 parser->current.type = PM_TOKEN_EMBDOC_END;
9770 parser_lex_callback(parser);
9772 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9773 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9775 return PM_TOKEN_EMBDOC_END;
9780 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
9782 if (newline == NULL) {
9783 parser->current.end = parser->end;
9785 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
9786 parser->current.end = newline + 1;
9789 parser->current.type = PM_TOKEN_EMBDOC_LINE;
9790 parser_lex_callback(parser);
9793 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9795 comment->location.
length = (uint32_t) (parser->current.end - comment_start);
9796 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
9798 return PM_TOKEN_EOF;
9808 parser->current.type = PM_TOKEN_IGNORED_NEWLINE;
9809 parser_lex_callback(parser);
9823 assert(parser->heredoc_end <= parser->end);
9824 parser->next_start = parser->heredoc_end;
9825 parser->heredoc_end = NULL;
9833 const uint8_t *cursor = parser->current.end;
9835 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9836 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9899 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9913 if (parser->encoding_changed) {
9914 width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
9916 width = pm_encoding_utf_8_char_width(parser->current.end, parser->end - parser->current.end);
9921 return (width == 0 ? 1 : width);
9929 size_t width = parser_char_width(parser);
9930 pm_buffer_append_bytes(&token_buffer->
buffer, parser->current.end, width);
9931 parser->current.end += width;
9936 size_t width = parser_char_width(parser);
9937 const uint8_t *start = parser->current.end;
9938 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, width);
9939 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, width);
9940 parser->current.end += width;
9952 size_t len = pm_buffer_length(&token_buffer->
buffer);
9953 void *arena_data = pm_arena_memdup(parser->arena, pm_buffer_value(&token_buffer->
buffer),
len,
PRISM_ALIGNOF(uint8_t));
9954 pm_string_init(&parser->current_string, (
const uint8_t *) arena_data,
len);
9955 pm_buffer_cleanup(&token_buffer->
buffer);
9960 pm_token_buffer_copy(parser, &token_buffer->
base);
9975 if (token_buffer->
cursor == NULL) {
9976 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9978 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->current.end - token_buffer->
cursor));
9979 pm_token_buffer_copy(parser, token_buffer);
9986 pm_string_shared_init(&parser->current_string, parser->current.start, parser->current.end);
9988 const uint8_t *cursor = token_buffer->
base.
cursor;
9989 size_t length = (size_t) (parser->current.end - cursor);
9990 pm_buffer_append_bytes(&token_buffer->
base.
buffer, cursor, length);
9991 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, cursor, length);
9992 pm_regexp_token_buffer_copy(parser, token_buffer);
9996#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
10008 const uint8_t *start;
10009 if (token_buffer->
cursor == NULL) {
10010 pm_buffer_init(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10011 start = parser->current.start;
10013 start = token_buffer->
cursor;
10016 const uint8_t *end = parser->current.end - 1;
10017 assert(end >= start);
10018 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
10020 token_buffer->
cursor = end;
10025 const uint8_t *start;
10027 pm_buffer_init(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10028 pm_buffer_init(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
10029 start = parser->current.start;
10034 const uint8_t *end = parser->current.end - 1;
10035 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
10036 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
10041#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
10048pm_heredoc_strspn_inline_whitespace(
pm_parser_t *parser,
const uint8_t **cursor, pm_heredoc_indent_t indent) {
10049 size_t whitespace = 0;
10052 case PM_HEREDOC_INDENT_NONE:
10057 case PM_HEREDOC_INDENT_DASH:
10059 *cursor += pm_strspn_inline_whitespace(*cursor, parser->end - *cursor);
10061 case PM_HEREDOC_INDENT_TILDE:
10064 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
10065 if (**cursor ==
'\t') {
10066 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
10085 size_t eol_length = match_eol(parser);
10088 if (parser->heredoc_end) {
10092 parser_flush_heredoc_end(parser);
10095 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + U32(eol_length));
10098 uint8_t delimiter = *parser->current.end;
10102 if (eol_length == 2) {
10103 delimiter = *(parser->current.end + 1);
10106 parser->current.end += eol_length;
10110 return *parser->current.end++;
10117#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
10127 assert(parser->current.end <= parser->end);
10128 parser->previous = parser->current;
10131 bool previous_command_start = parser->command_start;
10132 parser->command_start =
false;
10136 bool lexed_comment =
false;
10140 unsigned int semantic_token_seen = parser->semantic_token_seen;
10141 parser->semantic_token_seen =
true;
10149 switch (parser->lex_modes.current->mode) {
10150 case PM_LEX_DEFAULT:
10151 case PM_LEX_EMBEXPR:
10152 case PM_LEX_EMBVAR:
10161 if (parser->next_start != NULL) {
10162 parser->current.end = parser->next_start;
10163 parser->next_start = NULL;
10168 bool space_seen =
false;
10173 bool chomping =
true;
10180 static const uint8_t inline_whitespace[256] = {
10181 [
' '] = 1, [
'\t'] = 1, [
'\f'] = 1, [
'\v'] = 1
10183 const uint8_t *scan = parser->current.end;
10184 while (scan < parser->end && inline_whitespace[*scan]) scan++;
10185 if (scan > parser->current.end) {
10186 parser->current.end = scan;
10189 if (scan >= parser->end)
break;
10192 switch (*parser->current.end) {
10194 if (match_eol_offset(parser, 1)) {
10197 pm_parser_warn(parser, PM_TOKEN_END(parser, &parser->current), 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
10198 parser->current.end++;
10203 size_t eol_length = match_eol_offset(parser, 1);
10205 if (parser->heredoc_end) {
10206 parser->current.end = parser->heredoc_end;
10207 parser->heredoc_end = NULL;
10209 parser->current.end += eol_length + 1;
10210 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10213 }
else if (pm_char_is_inline_whitespace(*parser->current.end)) {
10214 parser->current.end += 2;
10228 parser->current.start = parser->current.end;
10232 if (parser->current.end >= parser->end) {
10236 if (parser->lex_modes.current->mode != PM_LEX_DEFAULT) {
10237 lex_mode_pop(parser);
10238 goto switch_lex_modes;
10246 if (parser->current.start > parser->start && (*(parser->current.start - 1) ==
'\n')) {
10247 parser->current.start -= 1;
10254 switch (*parser->current.end++) {
10258 parser->current.end--;
10262 const uint8_t *ending = next_newline(parser->current.end, parser->end - parser->current.end);
10263 parser->current.end = ending == NULL ? parser->end : ending;
10268 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
10269 pm_list_append(&parser->comment_list, (
pm_list_node_t *) comment);
10271 parser->current.type = PM_TOKEN_COMMENT;
10272 parser_lex_callback(parser);
10276 if (!parser_lex_magic_comment(parser, semantic_token_seen) && (parser->current.start == parser->encoding_comment_start)) {
10277 ptrdiff_t length = parser->current.end - parser->current.start;
10283 if (length >= 10 && !parser->encoding_locked) {
10284 parser_lex_magic_comment_encoding(parser);
10292 if (ending == NULL) {
10293 lexed_comment =
true;
10295 parser->current.start = ending;
10296 parser->current.end = ending + 1;
10302 parser->semantic_token_seen = semantic_token_seen & 0x1;
10303 size_t eol_length = match_eol_at(parser, parser->current.end - 1);
10315 if (!lexed_comment) {
10316 parser->current.end += eol_length - 1;
10319 if (parser->heredoc_end == NULL) {
10320 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
10324 if (parser->heredoc_end) {
10325 parser_flush_heredoc_end(parser);
10330 switch (lex_state_ignored_p(parser)) {
10331 case PM_IGNORED_NEWLINE_NONE:
10333 case PM_IGNORED_NEWLINE_PATTERN:
10334 if (parser->pattern_matching_newlines || parser->in_keyword_arg) {
10335 if (!lexed_comment) {
10336 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10337 parser_lex_callback(parser);
10340 lex_state_set(parser, PM_LEX_STATE_BEG);
10341 parser->command_start =
true;
10342 parser->current.type = PM_TOKEN_NEWLINE;
10346 case PM_IGNORED_NEWLINE_ALL:
10347 if (!lexed_comment) parser_lex_ignored_newline(parser);
10348 lexed_comment =
false;
10349 goto lex_next_token;
10356 const uint8_t *next_content = parser->next_start == NULL ? parser->current.end : parser->next_start;
10357 next_content += pm_strspn_inline_whitespace(next_content, parser->end - next_content);
10359 if (next_content < parser->end) {
10365 if (next_content[0] ==
'#') {
10367 const uint8_t *following = next_newline(next_content, parser->end - next_content);
10369 while (following && (following + 1 < parser->end)) {
10371 following += pm_strspn_inline_whitespace(following, parser->end - following);
10375 if (peek_at(parser, following) !=
'#')
break;
10379 following = next_newline(following, parser->end - following);
10384 if (lex_state_ignored_p(parser)) {
10385 if (!lexed_comment) parser_lex_ignored_newline(parser);
10386 lexed_comment =
false;
10387 goto lex_next_token;
10393 (peek_at(parser, following) ==
'.') ||
10394 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
10396 if (!lexed_comment) parser_lex_ignored_newline(parser);
10397 lexed_comment =
false;
10398 goto lex_next_token;
10406 (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) &&
10408 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
10409 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
10411 peek_at(parser, following) ==
'a' &&
10412 peek_at(parser, following + 1) ==
'n' &&
10413 peek_at(parser, following + 2) ==
'd' &&
10414 peek_at(parser, next_content + 3) !=
'!' &&
10415 peek_at(parser, next_content + 3) !=
'?' &&
10416 !char_is_identifier(parser, following + 3, parser->end - (following + 3))
10419 peek_at(parser, following) ==
'o' &&
10420 peek_at(parser, following + 1) ==
'r' &&
10421 peek_at(parser, next_content + 2) !=
'!' &&
10422 peek_at(parser, next_content + 2) !=
'?' &&
10423 !char_is_identifier(parser, following + 2, parser->end - (following + 2))
10427 if (!lexed_comment) parser_lex_ignored_newline(parser);
10428 lexed_comment =
false;
10429 goto lex_next_token;
10435 if (next_content[0] ==
'.') {
10439 if (peek_at(parser, next_content + 1) ==
'.') {
10440 if (!lexed_comment) {
10441 parser->current.type = PM_TOKEN_NEWLINE_TERMINATOR;
10442 parser_lex_callback(parser);
10445 lex_state_set(parser, PM_LEX_STATE_BEG);
10446 parser->command_start =
true;
10447 parser->current.type = PM_TOKEN_NEWLINE;
10451 if (!lexed_comment) parser_lex_ignored_newline(parser);
10452 lex_state_set(parser, PM_LEX_STATE_DOT);
10453 parser->current.start = next_content;
10454 parser->current.end = next_content + 1;
10455 parser->next_start = NULL;
10461 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10462 if (!lexed_comment) parser_lex_ignored_newline(parser);
10463 lex_state_set(parser, PM_LEX_STATE_DOT);
10464 parser->current.start = next_content;
10465 parser->current.end = next_content + 2;
10466 parser->next_start = NULL;
10467 LEX(PM_TOKEN_AMPERSAND_DOT);
10470 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) {
10473 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10474 if (!lexed_comment) parser_lex_ignored_newline(parser);
10475 lex_state_set(parser, PM_LEX_STATE_BEG);
10476 parser->current.start = next_content;
10477 parser->current.end = next_content + 2;
10478 parser->next_start = NULL;
10479 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10484 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10485 if (!lexed_comment) parser_lex_ignored_newline(parser);
10486 lex_state_set(parser, PM_LEX_STATE_BEG);
10487 parser->current.start = next_content;
10488 parser->current.end = next_content + 2;
10489 parser->next_start = NULL;
10490 LEX(PM_TOKEN_PIPE_PIPE);
10496 peek_at(parser, next_content) ==
'a' &&
10497 peek_at(parser, next_content + 1) ==
'n' &&
10498 peek_at(parser, next_content + 2) ==
'd' &&
10499 peek_at(parser, next_content + 3) !=
'!' &&
10500 peek_at(parser, next_content + 3) !=
'?' &&
10501 !char_is_identifier(parser, next_content + 3, parser->end - (next_content + 3))
10503 if (!lexed_comment) parser_lex_ignored_newline(parser);
10504 lex_state_set(parser, PM_LEX_STATE_BEG);
10505 parser->current.start = next_content;
10506 parser->current.end = next_content + 3;
10507 parser->next_start = NULL;
10508 parser->command_start =
true;
10509 LEX(PM_TOKEN_KEYWORD_AND);
10515 peek_at(parser, next_content) ==
'o' &&
10516 peek_at(parser, next_content + 1) ==
'r' &&
10517 peek_at(parser, next_content + 2) !=
'!' &&
10518 peek_at(parser, next_content + 2) !=
'?' &&
10519 !char_is_identifier(parser, next_content + 2, parser->end - (next_content + 2))
10521 if (!lexed_comment) parser_lex_ignored_newline(parser);
10522 lex_state_set(parser, PM_LEX_STATE_BEG);
10523 parser->current.start = next_content;
10524 parser->current.end = next_content + 2;
10525 parser->next_start = NULL;
10526 parser->command_start =
true;
10527 LEX(PM_TOKEN_KEYWORD_OR);
10534 lex_state_set(parser, PM_LEX_STATE_BEG);
10535 parser->command_start =
true;
10536 parser->current.type = PM_TOKEN_NEWLINE;
10537 if (!lexed_comment) parser_lex_callback(parser);
10543 if ((parser->previous.
type == PM_TOKEN_COMMA) && (parser->enclosure_nesting > 0)) {
10544 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
10547 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10548 LEX(PM_TOKEN_COMMA);
10556 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10558 if (lex_state_beg_p(parser)) {
10559 type = PM_TOKEN_PARENTHESIS_LEFT_GROUPING;
10560 }
else if (space_seen && (lex_state_arg_p(parser) || parser->lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10561 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10564 parser->enclosure_nesting++;
10565 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10566 pm_enclosure_frame_push(parser);
10572 parser->enclosure_nesting--;
10573 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10574 pm_enclosure_frame_pop(parser);
10575 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10579 lex_state_set(parser, PM_LEX_STATE_BEG);
10580 parser->command_start =
true;
10581 LEX(PM_TOKEN_SEMICOLON);
10585 parser->enclosure_nesting++;
10586 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10588 if (lex_state_operator_p(parser)) {
10589 if (match(parser,
']')) {
10590 parser->enclosure_nesting--;
10591 lex_state_set(parser, PM_LEX_STATE_ARG);
10592 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10595 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10599 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10600 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10603 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10604 pm_enclosure_frame_push(parser);
10609 parser->enclosure_nesting--;
10610 lex_state_set(parser, PM_LEX_STATE_END);
10611 pm_enclosure_frame_pop(parser);
10612 LEX(PM_TOKEN_BRACKET_RIGHT);
10616 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10618 if (parser->enclosure_nesting == parser->lambda_enclosure_nesting) {
10620 parser->command_start =
true;
10621 lex_state_set(parser, PM_LEX_STATE_BEG);
10622 type = PM_TOKEN_LAMBDA_BEGIN;
10623 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10625 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10626 type = PM_TOKEN_BRACE_LEFT_HASH;
10627 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10629 parser->command_start =
true;
10630 lex_state_set(parser, PM_LEX_STATE_BEG);
10631 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10634 parser->command_start =
true;
10635 lex_state_set(parser, PM_LEX_STATE_BEG);
10636 type = PM_TOKEN_BRACE_LEFT_ARGUMENT;
10639 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10640 type = PM_TOKEN_BRACE_LEFT_HASH;
10643 parser->enclosure_nesting++;
10644 parser->brace_nesting++;
10645 pm_enclosure_frame_push(parser);
10652 parser->enclosure_nesting--;
10653 pm_enclosure_frame_pop(parser);
10655 if ((parser->lex_modes.current->mode == PM_LEX_EMBEXPR) && (parser->brace_nesting == 0)) {
10656 lex_mode_pop(parser);
10657 LEX(PM_TOKEN_EMBEXPR_END);
10660 parser->brace_nesting--;
10661 lex_state_set(parser, PM_LEX_STATE_END);
10662 LEX(PM_TOKEN_BRACE_RIGHT);
10666 if (match(parser,
'*')) {
10667 if (match(parser,
'=')) {
10668 lex_state_set(parser, PM_LEX_STATE_BEG);
10669 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10672 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10674 if (lex_state_spcarg_p(parser, space_seen)) {
10675 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10676 type = PM_TOKEN_USTAR_STAR;
10677 }
else if (lex_state_beg_p(parser)) {
10678 type = PM_TOKEN_USTAR_STAR;
10679 }
else if (ambiguous_operator_p(parser, space_seen)) {
10680 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10683 if (lex_state_operator_p(parser)) {
10684 lex_state_set(parser, PM_LEX_STATE_ARG);
10686 lex_state_set(parser, PM_LEX_STATE_BEG);
10692 if (match(parser,
'=')) {
10693 lex_state_set(parser, PM_LEX_STATE_BEG);
10694 LEX(PM_TOKEN_STAR_EQUAL);
10697 pm_token_type_t
type = PM_TOKEN_STAR;
10699 if (lex_state_spcarg_p(parser, space_seen)) {
10700 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10701 type = PM_TOKEN_USTAR;
10702 }
else if (lex_state_beg_p(parser)) {
10703 type = PM_TOKEN_USTAR;
10704 }
else if (ambiguous_operator_p(parser, space_seen)) {
10705 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10708 if (lex_state_operator_p(parser)) {
10709 lex_state_set(parser, PM_LEX_STATE_ARG);
10711 lex_state_set(parser, PM_LEX_STATE_BEG);
10719 if (lex_state_operator_p(parser)) {
10720 lex_state_set(parser, PM_LEX_STATE_ARG);
10721 if (match(parser,
'@')) {
10722 LEX(PM_TOKEN_BANG);
10725 lex_state_set(parser, PM_LEX_STATE_BEG);
10728 if (match(parser,
'=')) {
10729 LEX(PM_TOKEN_BANG_EQUAL);
10732 if (match(parser,
'~')) {
10733 LEX(PM_TOKEN_BANG_TILDE);
10736 LEX(PM_TOKEN_BANG);
10741 current_token_starts_line(parser) &&
10742 (parser->current.end + 5 <= parser->end) &&
10743 memcmp(parser->current.end,
"begin", 5) == 0 &&
10744 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10746 pm_token_type_t
type = lex_embdoc(parser);
10747 if (
type == PM_TOKEN_EOF) {
10751 goto lex_next_token;
10754 if (lex_state_operator_p(parser)) {
10755 lex_state_set(parser, PM_LEX_STATE_ARG);
10757 lex_state_set(parser, PM_LEX_STATE_BEG);
10760 if (match(parser,
'>')) {
10761 LEX(PM_TOKEN_EQUAL_GREATER);
10764 if (match(parser,
'~')) {
10765 LEX(PM_TOKEN_EQUAL_TILDE);
10768 if (match(parser,
'=')) {
10769 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10772 LEX(PM_TOKEN_EQUAL);
10776 if (match(parser,
'<')) {
10778 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10779 !lex_state_end_p(parser) &&
10780 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10782 const uint8_t *end = parser->current.end;
10784 pm_heredoc_quote_t quote = PM_HEREDOC_QUOTE_NONE;
10785 pm_heredoc_indent_t indent = PM_HEREDOC_INDENT_NONE;
10787 if (match(parser,
'-')) {
10788 indent = PM_HEREDOC_INDENT_DASH;
10790 else if (match(parser,
'~')) {
10791 indent = PM_HEREDOC_INDENT_TILDE;
10794 if (match(parser,
'`')) {
10795 quote = PM_HEREDOC_QUOTE_BACKTICK;
10797 else if (match(parser,
'"')) {
10798 quote = PM_HEREDOC_QUOTE_DOUBLE;
10800 else if (match(parser,
'\'')) {
10801 quote = PM_HEREDOC_QUOTE_SINGLE;
10804 const uint8_t *ident_start = parser->current.end;
10807 if (parser->current.end >= parser->end) {
10808 parser->current.end = end;
10809 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end)) == 0) {
10810 parser->current.end = end;
10812 if (quote == PM_HEREDOC_QUOTE_NONE) {
10813 parser->current.end += width;
10815 while ((width = char_is_identifier(parser, parser->current.end, parser->end - parser->current.end))) {
10816 parser->current.end += width;
10821 while ((parser->current.end < parser->end) && quote != (pm_heredoc_quote_t) (*parser->current.end)) {
10822 if (*parser->current.end ==
'\r' || *parser->current.end ==
'\n')
break;
10823 parser->current.end++;
10827 size_t ident_length = (size_t) (parser->current.end - ident_start);
10828 bool ident_error =
false;
10830 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10831 pm_parser_err(parser, U32(ident_start - parser->start), U32(ident_length), PM_ERR_HEREDOC_IDENTIFIER);
10832 ident_error =
true;
10835 parser->explicit_encoding = NULL;
10837 .mode = PM_LEX_HEREDOC,
10840 .ident_start = ident_start,
10841 .ident_length = ident_length,
10845 .next_start = parser->current.end,
10846 .common_whitespace = NULL,
10847 .line_continuation =
false
10851 if (parser->heredoc_end == NULL) {
10852 const uint8_t *body_start = next_newline(parser->current.end, parser->end - parser->current.end);
10854 if (body_start == NULL) {
10859 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10860 body_start = parser->end;
10864 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(body_start - parser->start + 1));
10868 parser->next_start = body_start;
10870 parser->next_start = parser->heredoc_end;
10873 LEX(PM_TOKEN_HEREDOC_START);
10877 if (match(parser,
'=')) {
10878 lex_state_set(parser, PM_LEX_STATE_BEG);
10879 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10882 if (ambiguous_operator_p(parser, space_seen)) {
10883 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10886 if (lex_state_operator_p(parser)) {
10887 lex_state_set(parser, PM_LEX_STATE_ARG);
10889 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10890 lex_state_set(parser, PM_LEX_STATE_BEG);
10893 LEX(PM_TOKEN_LESS_LESS);
10896 if (lex_state_operator_p(parser)) {
10897 lex_state_set(parser, PM_LEX_STATE_ARG);
10899 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->command_start =
true;
10900 lex_state_set(parser, PM_LEX_STATE_BEG);
10903 if (match(parser,
'=')) {
10904 if (match(parser,
'>')) {
10905 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10908 LEX(PM_TOKEN_LESS_EQUAL);
10911 LEX(PM_TOKEN_LESS);
10915 if (match(parser,
'>')) {
10916 if (lex_state_operator_p(parser)) {
10917 lex_state_set(parser, PM_LEX_STATE_ARG);
10919 lex_state_set(parser, PM_LEX_STATE_BEG);
10921 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10924 if (lex_state_operator_p(parser)) {
10925 lex_state_set(parser, PM_LEX_STATE_ARG);
10927 lex_state_set(parser, PM_LEX_STATE_BEG);
10930 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10934 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10935 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10936 LEX(PM_TOKEN_STRING_BEGIN);
10941 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10942 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10943 LEX(PM_TOKEN_BACKTICK);
10946 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10947 if (previous_command_start) {
10948 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10950 lex_state_set(parser, PM_LEX_STATE_ARG);
10953 LEX(PM_TOKEN_BACKTICK);
10956 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10957 LEX(PM_TOKEN_XSTRING_BEGIN);
10962 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10963 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10964 LEX(PM_TOKEN_STRING_BEGIN);
10969 LEX(lex_question_mark(parser));
10973 if (match(parser,
'&')) {
10974 lex_state_set(parser, PM_LEX_STATE_BEG);
10976 if (match(parser,
'=')) {
10977 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10980 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10983 if (match(parser,
'=')) {
10984 lex_state_set(parser, PM_LEX_STATE_BEG);
10985 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10988 if (match(parser,
'.')) {
10989 lex_state_set(parser, PM_LEX_STATE_DOT);
10990 LEX(PM_TOKEN_AMPERSAND_DOT);
10993 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10994 if (lex_state_spcarg_p(parser, space_seen)) {
10995 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10996 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10998 const uint8_t delim = peek_offset(parser, 1);
11000 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->current.end + 1, parser->end - (parser->current.end + 1))) {
11001 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
11005 type = PM_TOKEN_UAMPERSAND;
11006 }
else if (lex_state_beg_p(parser)) {
11007 type = PM_TOKEN_UAMPERSAND;
11008 }
else if (ambiguous_operator_p(parser, space_seen)) {
11009 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
11012 if (lex_state_operator_p(parser)) {
11013 lex_state_set(parser, PM_LEX_STATE_ARG);
11015 lex_state_set(parser, PM_LEX_STATE_BEG);
11023 if (match(parser,
'|')) {
11024 if (match(parser,
'=')) {
11025 lex_state_set(parser, PM_LEX_STATE_BEG);
11026 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
11029 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
11030 parser->current.end--;
11031 LEX(PM_TOKEN_PIPE);
11034 lex_state_set(parser, PM_LEX_STATE_BEG);
11035 LEX(PM_TOKEN_PIPE_PIPE);
11038 if (match(parser,
'=')) {
11039 lex_state_set(parser, PM_LEX_STATE_BEG);
11040 LEX(PM_TOKEN_PIPE_EQUAL);
11043 if (lex_state_operator_p(parser)) {
11044 lex_state_set(parser, PM_LEX_STATE_ARG);
11046 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
11049 LEX(PM_TOKEN_PIPE);
11053 if (lex_state_operator_p(parser)) {
11054 lex_state_set(parser, PM_LEX_STATE_ARG);
11056 if (match(parser,
'@')) {
11057 LEX(PM_TOKEN_UPLUS);
11060 LEX(PM_TOKEN_PLUS);
11063 if (match(parser,
'=')) {
11064 lex_state_set(parser, PM_LEX_STATE_BEG);
11065 LEX(PM_TOKEN_PLUS_EQUAL);
11069 lex_state_beg_p(parser) ||
11070 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
11072 lex_state_set(parser, PM_LEX_STATE_BEG);
11074 if (pm_char_is_decimal_digit(peek(parser))) {
11075 parser->current.end++;
11076 pm_token_type_t
type = lex_numeric(parser);
11077 lex_state_set(parser, PM_LEX_STATE_END);
11081 LEX(PM_TOKEN_UPLUS);
11084 if (ambiguous_operator_p(parser, space_seen)) {
11085 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
11088 lex_state_set(parser, PM_LEX_STATE_BEG);
11089 LEX(PM_TOKEN_PLUS);
11094 if (lex_state_operator_p(parser)) {
11095 lex_state_set(parser, PM_LEX_STATE_ARG);
11097 if (match(parser,
'@')) {
11098 LEX(PM_TOKEN_UMINUS);
11101 LEX(PM_TOKEN_MINUS);
11104 if (match(parser,
'=')) {
11105 lex_state_set(parser, PM_LEX_STATE_BEG);
11106 LEX(PM_TOKEN_MINUS_EQUAL);
11109 if (match(parser,
'>')) {
11110 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11111 LEX(PM_TOKEN_MINUS_GREATER);
11114 bool spcarg = lex_state_spcarg_p(parser, space_seen);
11115 bool is_beg = lex_state_beg_p(parser);
11116 if (!is_beg && spcarg) {
11117 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
11120 if (is_beg || spcarg) {
11121 lex_state_set(parser, PM_LEX_STATE_BEG);
11122 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
11125 if (ambiguous_operator_p(parser, space_seen)) {
11126 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
11129 lex_state_set(parser, PM_LEX_STATE_BEG);
11130 LEX(PM_TOKEN_MINUS);
11135 bool beg_p = lex_state_beg_p(parser);
11137 if (match(parser,
'.')) {
11138 if (match(parser,
'.')) {
11140 if (!context_p(parser, PM_CONTEXT_DEFAULT_PARAMS) && context_p(parser, PM_CONTEXT_DEF_PARAMS)) {
11141 if (lex_state_p(parser, PM_LEX_STATE_END)) {
11142 lex_state_set(parser, PM_LEX_STATE_BEG);
11144 lex_state_set(parser, PM_LEX_STATE_ENDARG);
11146 LEX(PM_TOKEN_UDOT_DOT_DOT);
11149 if (parser->enclosure_nesting == 0 && parser_end_of_line_p(parser)) {
11150 pm_parser_warn_token(parser, &parser->current, PM_WARN_DOT_DOT_DOT_EOL);
11153 lex_state_set(parser, PM_LEX_STATE_BEG);
11154 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
11157 lex_state_set(parser, PM_LEX_STATE_BEG);
11158 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
11161 lex_state_set(parser, PM_LEX_STATE_DOT);
11176 pm_token_type_t
type = lex_numeric(parser);
11177 lex_state_set(parser, PM_LEX_STATE_END);
11183 if (match(parser,
':')) {
11184 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)) {
11185 lex_state_set(parser, PM_LEX_STATE_BEG);
11186 LEX(PM_TOKEN_UCOLON_COLON);
11189 lex_state_set(parser, PM_LEX_STATE_DOT);
11190 LEX(PM_TOKEN_COLON_COLON);
11193 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
11194 lex_state_set(parser, PM_LEX_STATE_BEG);
11195 LEX(PM_TOKEN_COLON);
11198 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
11199 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->current.end);
11200 parser->current.end++;
11207 parser->explicit_encoding = NULL;
11210 lex_state_set(parser, PM_LEX_STATE_FNAME);
11211 LEX(PM_TOKEN_SYMBOL_BEGIN);
11215 if (lex_state_beg_p(parser)) {
11216 lex_mode_push_regexp(parser,
'\0',
'/');
11217 LEX(PM_TOKEN_REGEXP_BEGIN);
11220 if (match(parser,
'=')) {
11221 lex_state_set(parser, PM_LEX_STATE_BEG);
11222 LEX(PM_TOKEN_SLASH_EQUAL);
11225 if (lex_state_spcarg_p(parser, space_seen)) {
11227 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_4_0) {
11228 pm_parser_warn_token(parser, &parser->current, PM_WARN_AMBIGUOUS_SLASH);
11230 lex_mode_push_regexp(parser,
'\0',
'/');
11231 LEX(PM_TOKEN_REGEXP_BEGIN);
11234 if (ambiguous_operator_p(parser, space_seen)) {
11235 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
11238 if (lex_state_operator_p(parser)) {
11239 lex_state_set(parser, PM_LEX_STATE_ARG);
11241 lex_state_set(parser, PM_LEX_STATE_BEG);
11244 LEX(PM_TOKEN_SLASH);
11248 if (lex_state_operator_p(parser)) {
11249 lex_state_set(parser, PM_LEX_STATE_ARG);
11251 lex_state_set(parser, PM_LEX_STATE_BEG);
11253 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
11257 if (lex_state_operator_p(parser)) {
11258 (void) match(parser,
'@');
11259 lex_state_set(parser, PM_LEX_STATE_ARG);
11261 lex_state_set(parser, PM_LEX_STATE_BEG);
11264 LEX(PM_TOKEN_TILDE);
11272 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->current.end >= parser->end)) {
11273 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
11274 LEX(PM_TOKEN_PERCENT);
11277 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
11278 lex_state_set(parser, PM_LEX_STATE_BEG);
11279 LEX(PM_TOKEN_PERCENT_EQUAL);
11281 lex_state_beg_p(parser) ||
11282 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
11283 lex_state_spcarg_p(parser, space_seen)
11285 if (!parser->encoding->alnum_char(parser->current.end, parser->end - parser->current.end)) {
11286 if (*parser->current.end >= 0x80) {
11287 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11288 goto lex_next_token;
11291 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11292 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11293 LEX(PM_TOKEN_STRING_BEGIN);
11298 uint8_t delimiter = peek_offset(parser, 1);
11299 if (delimiter >= 0x80 || parser->encoding->alnum_char(&delimiter, 1)) {
11300 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11301 goto lex_next_token;
11304 switch (peek(parser)) {
11306 parser->current.end++;
11308 if (parser->current.end < parser->end) {
11309 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11311 lex_mode_push_list_eof(parser);
11314 LEX(PM_TOKEN_PERCENT_LOWER_I);
11317 parser->current.end++;
11319 if (parser->current.end < parser->end) {
11320 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11322 lex_mode_push_list_eof(parser);
11325 LEX(PM_TOKEN_PERCENT_UPPER_I);
11328 parser->current.end++;
11330 if (parser->current.end < parser->end) {
11331 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11332 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11334 lex_mode_push_regexp(parser,
'\0',
'\0');
11337 LEX(PM_TOKEN_REGEXP_BEGIN);
11340 parser->current.end++;
11342 if (parser->current.end < parser->end) {
11343 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11344 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11346 lex_mode_push_string_eof(parser);
11349 LEX(PM_TOKEN_STRING_BEGIN);
11352 parser->current.end++;
11354 if (parser->current.end < parser->end) {
11355 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11356 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11358 lex_mode_push_string_eof(parser);
11361 LEX(PM_TOKEN_STRING_BEGIN);
11364 parser->current.end++;
11366 if (parser->current.end < parser->end) {
11367 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11368 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11369 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
11371 lex_mode_push_string_eof(parser);
11374 LEX(PM_TOKEN_SYMBOL_BEGIN);
11377 parser->current.end++;
11379 if (parser->current.end < parser->end) {
11380 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
11382 lex_mode_push_list_eof(parser);
11385 LEX(PM_TOKEN_PERCENT_LOWER_W);
11388 parser->current.end++;
11390 if (parser->current.end < parser->end) {
11391 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
11393 lex_mode_push_list_eof(parser);
11396 LEX(PM_TOKEN_PERCENT_UPPER_W);
11399 parser->current.end++;
11401 if (parser->current.end < parser->end) {
11402 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
11403 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
11405 lex_mode_push_string_eof(parser);
11408 LEX(PM_TOKEN_PERCENT_LOWER_X);
11415 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
11416 goto lex_next_token;
11420 if (ambiguous_operator_p(parser, space_seen)) {
11421 PM_PARSER_WARN_TOKEN_FORMAT(parser, &parser->current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
11424 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
11425 LEX(PM_TOKEN_PERCENT);
11430 pm_token_type_t
type = lex_global_variable(parser);
11434 if (parser->lex_modes.current->mode == PM_LEX_EMBVAR) {
11435 lex_mode_pop(parser);
11438 lex_state_set(parser, PM_LEX_STATE_END);
11444 lex_state_set(parser, parser->lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
11445 LEX(lex_at_variable(parser));
11448 if (*parser->current.start !=
'_') {
11449 size_t width = char_is_identifier_start(parser, parser->current.start, parser->end - parser->current.start);
11456 if (*parser->current.start >= 0x80) {
11457 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->current.start);
11458 }
else if (*parser->current.start ==
'\\') {
11459 switch (peek_at(parser, parser->current.start + 1)) {
11461 parser->current.end++;
11462 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11465 parser->current.end++;
11466 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11469 parser->current.end++;
11470 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11473 parser->current.end++;
11474 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11477 if (peek_at(parser, parser->current.start + 2) !=
'\n') {
11478 parser->current.end++;
11479 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11484 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11487 }
else if (char_is_ascii_printable(*parser->current.start)) {
11488 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->current.start);
11490 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_INVALID_CHARACTER, *parser->current.start);
11493 goto lex_next_token;
11496 parser->current.end = parser->current.start + width;
11499 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11506 ((parser->current.end - parser->current.start) == 7) &&
11507 current_token_starts_line(parser) &&
11508 (memcmp(parser->current.start,
"__END__", 7) == 0) &&
11509 (parser->current.end == parser->end || match_eol(parser))
11514 const uint8_t *cursor = parser->current.end;
11515 while ((cursor = next_newline(cursor, parser->end - cursor)) != NULL) {
11516 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(++cursor - parser->start));
11519 parser->current.end = parser->end;
11520 parser->current.type = PM_TOKEN___END__;
11521 parser_lex_callback(parser);
11523 parser->data_loc.
start = PM_TOKEN_START(parser, &parser->current);
11524 parser->data_loc.
length = PM_TOKEN_LENGTH(&parser->current);
11529 pm_lex_state_t last_state = parser->lex_state;
11531 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11532 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11533 if (previous_command_start) {
11534 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11536 lex_state_set(parser, PM_LEX_STATE_ARG);
11538 }
else if (parser->lex_state == PM_LEX_STATE_FNAME) {
11539 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11541 lex_state_set(parser, PM_LEX_STATE_END);
11546 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11547 (
type == PM_TOKEN_IDENTIFIER) &&
11548 ((pm_parser_local_depth(parser, &parser->current) != -1) ||
11549 pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)))
11551 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11558 case PM_LEX_LIST: {
11559 if (parser->next_start != NULL) {
11560 parser->current.end = parser->next_start;
11561 parser->next_start = NULL;
11565 parser->current.start = parser->current.end;
11573 if (parser->heredoc_end) {
11574 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11575 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11578 }
else if (lex_mode->as.list.terminator ==
'\n') {
11583 whitespace = pm_strspn_inline_whitespace(parser->current.end, parser->end - parser->current.end);
11585 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));
11588 if (whitespace > 0) {
11589 parser->current.end += whitespace;
11590 if (peek_offset(parser, -1) ==
'\n') {
11592 parser_flush_heredoc_end(parser);
11595 lex_mode->as.list.started =
true;
11596 lex_mode->as.list.separated =
true;
11597 LEX(PM_TOKEN_WORDS_SEP);
11602 if (parser->current.end >= parser->end) {
11611 if (!lex_mode->as.list.started) {
11612 lex_mode->as.list.started =
true;
11613 lex_mode->as.list.separated =
true;
11614 parser->current.type = PM_TOKEN_WORDS_SEP_IMPLICIT;
11615 parser_lex_callback(parser);
11620 const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
11621 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11627 while (breakpoint != NULL) {
11632 if (pm_char_is_whitespace(*breakpoint) && *breakpoint != lex_mode->as.list.terminator) {
11633 parser->current.end = breakpoint;
11634 pm_token_buffer_flush(parser, &token_buffer);
11635 lex_mode->as.list.separated =
false;
11636 LEX(PM_TOKEN_STRING_CONTENT);
11641 if (*breakpoint == lex_mode->as.list.terminator) {
11644 if (lex_mode->as.list.nesting > 0) {
11645 parser->current.end = breakpoint + 1;
11646 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11647 lex_mode->as.list.nesting--;
11653 if (breakpoint > parser->current.start) {
11654 parser->current.end = breakpoint;
11655 pm_token_buffer_flush(parser, &token_buffer);
11656 lex_mode->as.list.separated =
false;
11657 LEX(PM_TOKEN_STRING_CONTENT);
11665 if (!lex_mode->as.list.separated) {
11666 lex_mode->as.list.separated =
true;
11667 parser->current.end = breakpoint;
11668 parser->current.type = PM_TOKEN_WORDS_SEP_IMPLICIT;
11669 parser_lex_callback(parser);
11674 parser->current.end = breakpoint + 1;
11679 if (*breakpoint ==
'\n') {
11680 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11683 lex_mode_pop(parser);
11684 lex_state_set(parser, PM_LEX_STATE_END);
11685 LEX(PM_TOKEN_STRING_END);
11689 if (*breakpoint ==
'\0') {
11690 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->end - (breakpoint + 1),
true);
11697 if (*breakpoint ==
'\\') {
11698 parser->current.end = breakpoint + 1;
11702 if (parser->current.end == parser->end) {
11707 pm_token_buffer_escape(parser, &token_buffer);
11708 uint8_t peeked = peek(parser);
11716 pm_token_buffer_push_byte(&token_buffer, peeked);
11717 parser->current.end++;
11720 parser->current.end++;
11721 if (peek(parser) !=
'\n') {
11722 pm_token_buffer_push_byte(&token_buffer,
'\r');
11727 pm_token_buffer_push_byte(&token_buffer,
'\n');
11729 if (parser->heredoc_end) {
11733 parser_flush_heredoc_end(parser);
11734 pm_token_buffer_copy(parser, &token_buffer);
11735 LEX(PM_TOKEN_STRING_CONTENT);
11738 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11741 parser->current.end++;
11744 if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
11745 pm_token_buffer_push_byte(&token_buffer, peeked);
11746 parser->current.end++;
11747 }
else if (lex_mode->as.list.interpolation) {
11748 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11750 pm_token_buffer_push_byte(&token_buffer,
'\\');
11751 pm_token_buffer_push_escaped(&token_buffer, parser);
11757 token_buffer.
cursor = parser->current.end;
11758 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11763 if (*breakpoint ==
'#') {
11764 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11771 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11775 if (
type == PM_TOKEN_STRING_CONTENT) {
11776 pm_token_buffer_flush(parser, &token_buffer);
11779 lex_mode->as.list.separated =
false;
11785 assert(*breakpoint == lex_mode->as.list.incrementor);
11786 parser->current.end = breakpoint + 1;
11787 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
11788 lex_mode->as.list.nesting++;
11792 if (parser->current.end > parser->current.start) {
11793 pm_token_buffer_flush(parser, &token_buffer);
11794 LEX(PM_TOKEN_STRING_CONTENT);
11799 parser->current.end = parser->end;
11800 pm_token_buffer_flush(parser, &token_buffer);
11801 LEX(PM_TOKEN_STRING_CONTENT);
11803 case PM_LEX_REGEXP: {
11805 if (parser->next_start == NULL) {
11806 parser->current.start = parser->current.end;
11808 parser->current.start = parser->next_start;
11809 parser->current.end = parser->next_start;
11810 parser->next_start = NULL;
11815 if (parser->current.end >= parser->end) {
11825 const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
11826 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11829 while (breakpoint != NULL) {
11830 uint8_t term = lex_mode->as.regexp.terminator;
11831 bool is_terminator = (*breakpoint == term);
11836 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11837 if (term ==
'\n') {
11838 is_terminator =
true;
11844 if (term ==
'\r') {
11845 is_terminator =
false;
11851 if (is_terminator) {
11852 if (lex_mode->as.regexp.nesting > 0) {
11853 parser->current.end = breakpoint + 1;
11854 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11855 lex_mode->as.regexp.nesting--;
11862 if (breakpoint > parser->current.start) {
11863 parser->current.end = breakpoint;
11864 pm_regexp_token_buffer_flush(parser, &token_buffer);
11865 LEX(PM_TOKEN_STRING_CONTENT);
11869 size_t eol_length = match_eol_at(parser, breakpoint);
11871 parser->current.end = breakpoint + eol_length;
11876 if (parser->heredoc_end == NULL) {
11877 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
11880 parser->current.end = breakpoint + 1;
11885 parser->current.end += pm_strspn_regexp_option(parser->current.end, parser->end - parser->current.end);
11887 lex_mode_pop(parser);
11888 lex_state_set(parser, PM_LEX_STATE_END);
11889 LEX(PM_TOKEN_REGEXP_END);
11894 if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
11895 parser->current.end = breakpoint + 1;
11896 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11897 lex_mode->as.regexp.nesting++;
11901 switch (*breakpoint) {
11904 parser->current.end = breakpoint + 1;
11905 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11908 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11909 parser->current.end = breakpoint + 1;
11910 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11915 parser->current.end = breakpoint;
11916 pm_regexp_token_buffer_escape(parser, &token_buffer);
11923 if (parser->heredoc_end == NULL) {
11924 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
11925 parser->current.end = breakpoint + 1;
11926 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
11930 parser->current.end = breakpoint + 1;
11931 parser_flush_heredoc_end(parser);
11932 pm_regexp_token_buffer_flush(parser, &token_buffer);
11933 LEX(PM_TOKEN_STRING_CONTENT);
11938 parser->current.end = breakpoint + 1;
11942 if (parser->current.end == parser->end) {
11947 pm_regexp_token_buffer_escape(parser, &token_buffer);
11948 uint8_t peeked = peek(parser);
11952 parser->current.end++;
11953 if (peek(parser) !=
'\n') {
11954 if (lex_mode->as.regexp.terminator !=
'\r') {
11955 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11957 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11958 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11963 if (parser->heredoc_end) {
11967 parser_flush_heredoc_end(parser);
11968 pm_regexp_token_buffer_copy(parser, &token_buffer);
11969 LEX(PM_TOKEN_STRING_CONTENT);
11972 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
11975 parser->current.end++;
11985 if (lex_mode->as.regexp.terminator == peeked) {
11990 case '$':
case ')':
case '*':
case '+':
11991 case '.':
case '>':
case '?':
case ']':
11992 case '^':
case '|':
case '}':
11993 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11999 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
12000 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
12001 parser->current.end++;
12005 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
12006 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
12010 token_buffer.
base.
cursor = parser->current.end;
12011 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
12017 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12024 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
false);
12028 if (
type == PM_TOKEN_STRING_CONTENT) {
12029 pm_regexp_token_buffer_flush(parser, &token_buffer);
12035 assert(
false &&
"unreachable");
12040 if (parser->current.end > parser->current.start) {
12041 pm_regexp_token_buffer_flush(parser, &token_buffer);
12042 LEX(PM_TOKEN_STRING_CONTENT);
12047 parser->current.end = parser->end;
12048 pm_regexp_token_buffer_flush(parser, &token_buffer);
12049 LEX(PM_TOKEN_STRING_CONTENT);
12051 case PM_LEX_STRING: {
12053 if (parser->next_start == NULL) {
12054 parser->current.start = parser->current.end;
12056 parser->current.start = parser->next_start;
12057 parser->current.end = parser->next_start;
12058 parser->next_start = NULL;
12063 if (parser->current.end >= parser->end) {
12070 const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
12071 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12077 while (breakpoint != NULL) {
12080 if (lex_mode->as.string.incrementor !=
'\0' && *breakpoint == lex_mode->as.string.incrementor) {
12081 lex_mode->as.string.nesting++;
12082 parser->current.end = breakpoint + 1;
12083 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12087 uint8_t term = lex_mode->as.string.terminator;
12088 bool is_terminator = (*breakpoint == term);
12093 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
12094 if (term ==
'\n') {
12095 is_terminator =
true;
12101 if (term ==
'\r') {
12102 is_terminator =
false;
12109 if (is_terminator) {
12112 if (lex_mode->as.string.nesting > 0) {
12113 parser->current.end = breakpoint + 1;
12114 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12115 lex_mode->as.string.nesting--;
12121 if (breakpoint > parser->current.start) {
12122 parser->current.end = breakpoint;
12123 pm_token_buffer_flush(parser, &token_buffer);
12124 LEX(PM_TOKEN_STRING_CONTENT);
12129 size_t eol_length = match_eol_at(parser, breakpoint);
12131 parser->current.end = breakpoint + eol_length;
12136 if (parser->heredoc_end == NULL) {
12137 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current));
12140 parser->current.end = breakpoint + 1;
12143 if (lex_mode->as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
12144 parser->current.end++;
12145 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
12146 lex_mode_pop(parser);
12147 LEX(PM_TOKEN_LABEL_END);
12153 if (term ==
'\n' && parser->heredoc_end) {
12154 parser_flush_heredoc_end(parser);
12157 lex_state_set(parser, PM_LEX_STATE_END);
12158 lex_mode_pop(parser);
12159 LEX(PM_TOKEN_STRING_END);
12162 switch (*breakpoint) {
12165 parser->current.end = breakpoint + 1;
12166 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12169 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12170 parser->current.end = breakpoint + 1;
12171 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12178 parser->current.end = breakpoint;
12179 pm_token_buffer_escape(parser, &token_buffer);
12180 token_buffer.
cursor = breakpoint;
12188 if (parser->heredoc_end == NULL) {
12189 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12190 parser->current.end = breakpoint + 1;
12191 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12195 parser->current.end = breakpoint + 1;
12196 parser_flush_heredoc_end(parser);
12197 pm_token_buffer_flush(parser, &token_buffer);
12198 LEX(PM_TOKEN_STRING_CONTENT);
12201 parser->current.end = breakpoint + 1;
12205 if (parser->current.end == parser->end) {
12210 pm_token_buffer_escape(parser, &token_buffer);
12211 uint8_t peeked = peek(parser);
12215 pm_token_buffer_push_byte(&token_buffer,
'\\');
12216 parser->current.end++;
12219 parser->current.end++;
12220 if (peek(parser) !=
'\n') {
12221 if (!lex_mode->as.string.interpolation) {
12222 pm_token_buffer_push_byte(&token_buffer,
'\\');
12224 pm_token_buffer_push_byte(&token_buffer,
'\r');
12229 if (!lex_mode->as.string.interpolation) {
12230 pm_token_buffer_push_byte(&token_buffer,
'\\');
12231 pm_token_buffer_push_byte(&token_buffer,
'\n');
12234 if (parser->heredoc_end) {
12238 parser_flush_heredoc_end(parser);
12239 pm_token_buffer_copy(parser, &token_buffer);
12240 LEX(PM_TOKEN_STRING_CONTENT);
12243 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, PM_TOKEN_END(parser, &parser->current) + 1);
12246 parser->current.end++;
12249 if (lex_mode->as.string.incrementor !=
'\0' && peeked == lex_mode->as.string.incrementor) {
12250 pm_token_buffer_push_byte(&token_buffer, peeked);
12251 parser->current.end++;
12252 }
else if (lex_mode->as.string.terminator !=
'\0' && peeked == lex_mode->as.string.terminator) {
12253 pm_token_buffer_push_byte(&token_buffer, peeked);
12254 parser->current.end++;
12255 }
else if (lex_mode->as.string.interpolation) {
12256 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12258 pm_token_buffer_push_byte(&token_buffer,
'\\');
12259 pm_token_buffer_push_escaped(&token_buffer, parser);
12265 token_buffer.
cursor = parser->current.end;
12266 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12270 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12277 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12281 if (
type == PM_TOKEN_STRING_CONTENT) {
12282 pm_token_buffer_flush(parser, &token_buffer);
12288 assert(
false &&
"unreachable");
12292 if (parser->current.end > parser->current.start) {
12293 pm_token_buffer_flush(parser, &token_buffer);
12294 LEX(PM_TOKEN_STRING_CONTENT);
12299 parser->current.end = parser->end;
12300 pm_token_buffer_flush(parser, &token_buffer);
12301 LEX(PM_TOKEN_STRING_CONTENT);
12303 case PM_LEX_HEREDOC: {
12305 if (parser->next_start == NULL) {
12306 parser->current.start = parser->current.end;
12308 parser->current.start = parser->next_start;
12309 parser->current.end = parser->next_start;
12310 parser->heredoc_end = NULL;
12311 parser->next_start = NULL;
12319 bool line_continuation = lex_mode->as.heredoc.line_continuation;
12320 lex_mode->as.heredoc.line_continuation =
false;
12326 if (parser->current.end >= parser->end) {
12327 pm_parser_err_heredoc_term(parser, heredoc_lex_mode->ident_start, heredoc_lex_mode->ident_length);
12328 parser->next_start = lex_mode->as.heredoc.next_start;
12329 parser->heredoc_end = parser->current.end;
12330 lex_state_set(parser, PM_LEX_STATE_END);
12331 lex_mode_pop(parser);
12332 LEX(PM_TOKEN_HEREDOC_END);
12335 const uint8_t *ident_start = heredoc_lex_mode->ident_start;
12336 size_t ident_length = heredoc_lex_mode->ident_length;
12340 if (current_token_starts_line(parser)) {
12341 const uint8_t *start = parser->current.start;
12343 if (!line_continuation && (start + ident_length <= parser->end)) {
12344 const uint8_t *newline = next_newline(start, parser->end - start);
12345 const uint8_t *ident_end = newline;
12346 const uint8_t *terminator_end = newline;
12348 if (newline == NULL) {
12349 terminator_end = parser->end;
12350 ident_end = parser->end;
12353 if (newline[-1] ==
'\r') {
12365 if ((
size_t) (ident_end - start) >= ident_length) {
12366 const uint8_t *terminator_start = ident_end - ident_length;
12367 const uint8_t *cursor = start;
12369 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12370 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12376 (cursor == terminator_start) &&
12377 (memcmp(terminator_start, ident_start, ident_length) == 0)
12379 if (newline != NULL) {
12380 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
12383 parser->current.end = terminator_end;
12384 if (*lex_mode->as.heredoc.next_start ==
'\\') {
12385 parser->next_start = NULL;
12387 parser->next_start = lex_mode->as.heredoc.next_start;
12388 parser->heredoc_end = parser->current.end;
12391 lex_state_set(parser, PM_LEX_STATE_END);
12392 lex_mode_pop(parser);
12393 LEX(PM_TOKEN_HEREDOC_END);
12398 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->indent);
12400 heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE &&
12401 lex_mode->as.heredoc.common_whitespace != NULL &&
12402 (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
12403 peek_at(parser, start) !=
'\n'
12405 *lex_mode->as.heredoc.common_whitespace = whitespace;
12412 uint8_t breakpoints[PM_STRPBRK_CACHE_SIZE] =
"\r\n\\#";
12414 pm_heredoc_quote_t quote = heredoc_lex_mode->quote;
12415 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12416 breakpoints[3] =
'\0';
12419 const uint8_t *breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12421 bool was_line_continuation =
false;
12423 while (breakpoint != NULL) {
12424 switch (*breakpoint) {
12427 parser->current.end = breakpoint + 1;
12428 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12431 parser->current.end = breakpoint + 1;
12433 if (peek_at(parser, breakpoint + 1) !=
'\n') {
12434 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12441 pm_token_buffer_escape(parser, &token_buffer);
12442 token_buffer.
cursor = breakpoint;
12446 if (parser->heredoc_end != NULL && (parser->heredoc_end > breakpoint)) {
12447 parser_flush_heredoc_end(parser);
12448 parser->current.end = breakpoint + 1;
12449 pm_token_buffer_flush(parser, &token_buffer);
12450 LEX(PM_TOKEN_STRING_CONTENT);
12453 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(breakpoint - parser->start + 1));
12457 const uint8_t *start = breakpoint + 1;
12459 if (!was_line_continuation && (start + ident_length <= parser->end)) {
12462 const uint8_t *newline = next_newline(start, parser->end - start);
12464 if (newline == NULL) {
12465 newline = parser->end;
12466 }
else if (newline[-1] ==
'\r') {
12478 if ((
size_t) (newline - start) >= ident_length) {
12480 const uint8_t *terminator_start = newline - ident_length;
12484 const uint8_t *cursor = start;
12486 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12487 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
12493 cursor == terminator_start &&
12494 (memcmp(terminator_start, ident_start, ident_length) == 0)
12496 parser->current.end = breakpoint + 1;
12497 pm_token_buffer_flush(parser, &token_buffer);
12498 LEX(PM_TOKEN_STRING_CONTENT);
12503 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
12510 if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
12511 if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
12512 *lex_mode->as.heredoc.common_whitespace = whitespace;
12515 parser->current.end = breakpoint + 1;
12516 pm_token_buffer_flush(parser, &token_buffer);
12517 LEX(PM_TOKEN_STRING_CONTENT);
12522 parser->current.end = breakpoint + 1;
12523 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12533 parser->current.end = breakpoint + 1;
12537 if (parser->current.end == parser->end) {
12542 pm_token_buffer_escape(parser, &token_buffer);
12543 uint8_t peeked = peek(parser);
12545 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12548 parser->current.end++;
12549 if (peek(parser) !=
'\n') {
12550 pm_token_buffer_push_byte(&token_buffer,
'\\');
12551 pm_token_buffer_push_byte(&token_buffer,
'\r');
12556 pm_token_buffer_push_byte(&token_buffer,
'\\');
12557 pm_token_buffer_push_byte(&token_buffer,
'\n');
12558 token_buffer.
cursor = parser->current.end + 1;
12559 breakpoint = parser->current.end;
12562 pm_token_buffer_push_byte(&token_buffer,
'\\');
12563 pm_token_buffer_push_escaped(&token_buffer, parser);
12569 parser->current.end++;
12570 if (peek(parser) !=
'\n') {
12571 pm_token_buffer_push_byte(&token_buffer,
'\r');
12579 if (heredoc_lex_mode->indent == PM_HEREDOC_INDENT_TILDE) {
12580 const uint8_t *end = parser->current.end;
12582 if (parser->heredoc_end == NULL) {
12583 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(end - parser->start + 1));
12588 parser->current.end = breakpoint;
12589 pm_token_buffer_flush(parser, &token_buffer);
12593 parser->current.end = end + 1;
12594 lex_mode->as.heredoc.line_continuation =
true;
12595 LEX(PM_TOKEN_STRING_CONTENT);
12598 was_line_continuation =
true;
12599 token_buffer.
cursor = parser->current.end + 1;
12600 breakpoint = parser->current.end;
12603 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12608 token_buffer.
cursor = parser->current.end;
12609 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12613 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12621 breakpoint = pm_strpbrk(parser, parser->current.end, breakpoints, parser->end - parser->current.end,
true);
12625 if (
type == PM_TOKEN_STRING_CONTENT) {
12626 pm_token_buffer_flush(parser, &token_buffer);
12632 assert(
false &&
"unreachable");
12635 was_line_continuation =
false;
12638 if (parser->current.end > parser->current.start) {
12639 parser->current.end = parser->end;
12640 pm_token_buffer_flush(parser, &token_buffer);
12641 LEX(PM_TOKEN_STRING_CONTENT);
12646 parser->current.end = parser->end;
12647 pm_token_buffer_flush(parser, &token_buffer);
12648 LEX(PM_TOKEN_STRING_CONTENT);
12652 assert(
false &&
"unreachable");
12670 PM_BINDING_POWER_UNSET = 0,
12671 PM_BINDING_POWER_STATEMENT = 2,
12672 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12673 PM_BINDING_POWER_MODIFIER = 6,
12674 PM_BINDING_POWER_COMPOSITION = 8,
12675 PM_BINDING_POWER_NOT = 10,
12676 PM_BINDING_POWER_MATCH = 12,
12677 PM_BINDING_POWER_DEFINED = 14,
12678 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12679 PM_BINDING_POWER_ASSIGNMENT = 18,
12680 PM_BINDING_POWER_TERNARY = 20,
12681 PM_BINDING_POWER_RANGE = 22,
12682 PM_BINDING_POWER_LOGICAL_OR = 24,
12683 PM_BINDING_POWER_LOGICAL_AND = 26,
12684 PM_BINDING_POWER_EQUALITY = 28,
12685 PM_BINDING_POWER_COMPARISON = 30,
12686 PM_BINDING_POWER_BITWISE_OR = 32,
12687 PM_BINDING_POWER_BITWISE_AND = 34,
12688 PM_BINDING_POWER_SHIFT = 36,
12689 PM_BINDING_POWER_TERM = 38,
12690 PM_BINDING_POWER_FACTOR = 40,
12691 PM_BINDING_POWER_UMINUS = 42,
12692 PM_BINDING_POWER_EXPONENT = 44,
12693 PM_BINDING_POWER_UNARY = 46,
12694 PM_BINDING_POWER_INDEX = 48,
12695 PM_BINDING_POWER_CALL = 50,
12696 PM_BINDING_POWER_MAX = 52
12697} pm_binding_power_t;
12720#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12721#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12722#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12723#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12724#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12728 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12731 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12732 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12733 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12734 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12737 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12738 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12741 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12742 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12745 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12746 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12747 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12748 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12749 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12750 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12751 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12752 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12753 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12754 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12755 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12756 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12757 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12758 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12761 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12764 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12765 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12766 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12767 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12770 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12773 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12776 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12777 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12778 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12779 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12780 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12781 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12784 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12785 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12786 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12787 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12790 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12791 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12794 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12797 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12798 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12801 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12802 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12805 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12806 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12807 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12808 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12811 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12812 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12815 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12816 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12819 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12820 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12821 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12824 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12827 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12828 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12829 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12832#undef BINDING_POWER_ASSIGNMENT
12833#undef LEFT_ASSOCIATIVE
12834#undef RIGHT_ASSOCIATIVE
12835#undef RIGHT_ASSOCIATIVE_UNARY
12842 return parser->current.type ==
type;
12849match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12850 return match1(parser, type1) || match1(parser, type2);
12857match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12858 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12865match4(
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) {
12866 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12873match5(
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) {
12874 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5);
12881match6(
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) {
12882 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6);
12889match8(
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) {
12890 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);
12901 if (match1(parser,
type)) {
12902 parser_lex(parser);
12913accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12914 if (match2(parser, type1, type2)) {
12915 parser_lex(parser);
12933expect1(
pm_parser_t *parser, pm_token_type_t
type, pm_diagnostic_id_t diag_id) {
12934 if (accept1(parser,
type))
return;
12936 const uint8_t *location = parser->previous.
end;
12937 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12939 parser->previous.
start = location;
12940 parser->previous.
type = 0;
12948expect2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_diagnostic_id_t diag_id) {
12949 if (accept2(parser, type1, type2))
return;
12951 const uint8_t *location = parser->previous.
end;
12952 pm_parser_err(parser, U32(location - parser->start), 0, diag_id);
12954 parser->previous.
start = location;
12955 parser->previous.
type = 0;
12963expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12964 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12965 parser_lex(parser);
12967 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12968 parser->previous.
start = parser->previous.
end;
12969 parser->previous.
type = 0;
12981 if (accept1(parser,
type))
return;
12983 const uint8_t *start = opening->
start;
12984 pm_parser_err(parser, U32(start - parser->start), U32(opening->
end - start), diag_id);
12986 parser->previous.
start = parser->previous.
end;
12987 parser->previous.
type = 0;
12991#define PM_PARSE_ACCEPTS_COMMAND_CALL ((uint8_t) 0x1)
12992#define PM_PARSE_ACCEPTS_LABEL ((uint8_t) 0x2)
12993#define PM_PARSE_ACCEPTS_DO_BLOCK ((uint8_t) 0x4)
12994#define PM_PARSE_IN_ENDLESS_DEF ((uint8_t) 0x8)
13005#define PM_PARSE_ACCEPTS_STATEMENT ((uint8_t) 0x10)
13018#define PM_PARSE_ACCEPTS_COMMAND_DEF ((uint8_t) 0x20)
13021parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth);
13028parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
13029 pm_node_t *node = parse_expression(parser, binding_power, flags, diag_id, depth);
13030 pm_assert_value_expression(parser, node);
13053token_begins_expression_p(pm_token_type_t
type) {
13055 case PM_TOKEN_EQUAL_GREATER:
13056 case PM_TOKEN_KEYWORD_IN:
13060 case PM_TOKEN_BRACE_RIGHT:
13061 case PM_TOKEN_BRACKET_RIGHT:
13062 case PM_TOKEN_COLON:
13063 case PM_TOKEN_COMMA:
13064 case PM_TOKEN_EMBEXPR_END:
13066 case PM_TOKEN_LAMBDA_BEGIN:
13067 case PM_TOKEN_KEYWORD_DO:
13068 case PM_TOKEN_KEYWORD_DO_BLOCK:
13069 case PM_TOKEN_KEYWORD_DO_LAMBDA:
13070 case PM_TOKEN_KEYWORD_DO_LOOP:
13071 case PM_TOKEN_KEYWORD_END:
13072 case PM_TOKEN_KEYWORD_ELSE:
13073 case PM_TOKEN_KEYWORD_ELSIF:
13074 case PM_TOKEN_KEYWORD_ENSURE:
13075 case PM_TOKEN_KEYWORD_THEN:
13076 case PM_TOKEN_KEYWORD_RESCUE:
13077 case PM_TOKEN_KEYWORD_WHEN:
13078 case PM_TOKEN_NEWLINE:
13079 case PM_TOKEN_PARENTHESIS_RIGHT:
13080 case PM_TOKEN_SEMICOLON:
13086 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
13088 case PM_TOKEN_UAMPERSAND:
13092 case PM_TOKEN_UCOLON_COLON:
13093 case PM_TOKEN_UMINUS:
13094 case PM_TOKEN_UMINUS_NUM:
13095 case PM_TOKEN_UPLUS:
13096 case PM_TOKEN_BANG:
13097 case PM_TOKEN_TILDE:
13098 case PM_TOKEN_UDOT_DOT:
13099 case PM_TOKEN_UDOT_DOT_DOT:
13106 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
13126token_begins_pattern_p(pm_token_type_t
type) {
13128 token_begins_expression_p(
type) ||
13129 type == PM_TOKEN_USTAR ||
13130 type == PM_TOKEN_USTAR_STAR ||
13131 type == PM_TOKEN_CARET
13143token_begins_argument_p(pm_token_type_t
type) {
13145 token_begins_expression_p(
type) ||
13146 type == PM_TOKEN_UAMPERSAND ||
13147 type == PM_TOKEN_USTAR ||
13148 type == PM_TOKEN_USTAR_STAR
13157parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
13158 if (accept1(parser, PM_TOKEN_USTAR)) {
13160 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));
13161 return UP(pm_splat_node_create(parser, &
operator, expression));
13164 return parse_value_expression(parser, binding_power, flags, diag_id, depth);
13168pm_node_unreference_each(
const pm_node_t *node,
void *data) {
13169 switch (PM_NODE_TYPE(node)) {
13174 case PM_BREAK_NODE:
13176 case PM_REDO_NODE: {
13180 while (index < parser->current_block_exits->size) {
13181 pm_node_t *block_exit = parser->current_block_exits->
nodes[index];
13183 if (block_exit == node) {
13184 if (index + 1 < parser->current_block_exits->
size) {
13186 &parser->current_block_exits->
nodes[index],
13187 &parser->current_block_exits->
nodes[index + 1],
13188 (parser->current_block_exits->
size - index - 1) *
sizeof(
pm_node_t *)
13191 parser->current_block_exits->
size--;
13206 case PM_LOCAL_VARIABLE_READ_NODE:
13207 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13209 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
13211 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
13212 if (implicit_parameters->
nodes[index] == node) {
13216 if (index != implicit_parameters->
size - 1) {
13217 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
13220 implicit_parameters->
size--;
13239 pm_visit_node(node, pm_node_unreference_each, parser);
13254 uint8_t *name = (uint8_t *) pm_arena_alloc(parser->arena, length + 1, 1);
13256 memcpy(name,
constant->start, length);
13257 name[length] =
'=';
13259 *name_field = pm_constant_pool_insert_owned(&parser->metadata_arena, &parser->constant_pool, name, length + 1);
13270 switch (PM_NODE_TYPE(target)) {
13271 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13272 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13273 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13274 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13275 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13276 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13277 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13281 pm_constant_id_t name = pm_parser_constant_id_raw(parser, parser->start + PM_NODE_START(target), parser->start + PM_NODE_END(target));
13297 switch (PM_NODE_TYPE(target)) {
13298 case PM_ERROR_RECOVERY_NODE:
13300 case PM_SOURCE_ENCODING_NODE:
13301 case PM_FALSE_NODE:
13302 case PM_SOURCE_FILE_NODE:
13303 case PM_SOURCE_LINE_NODE:
13306 case PM_TRUE_NODE: {
13309 return parse_unwriteable_target(parser, target);
13311 case PM_CLASS_VARIABLE_READ_NODE:
13313 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
13315 case PM_CONSTANT_PATH_NODE:
13316 if (context_def_p(parser)) {
13317 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13321 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
13324 case PM_CONSTANT_READ_NODE:
13325 if (context_def_p(parser)) {
13326 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
13330 target->
type = PM_CONSTANT_TARGET_NODE;
13333 case PM_BACK_REFERENCE_READ_NODE:
13334 case PM_NUMBERED_REFERENCE_READ_NODE:
13335 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13336 return UP(pm_error_recovery_node_create_unexpected(parser, target));
13337 case PM_GLOBAL_VARIABLE_READ_NODE:
13339 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
13341 case PM_LOCAL_VARIABLE_READ_NODE: {
13342 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13343 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(target));
13344 pm_node_unreference(parser, target);
13348 uint32_t name =
cast->name;
13349 uint32_t depth =
cast->depth;
13350 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
13353 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
13357 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13359 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
13361 pm_node_unreference(parser, target);
13365 case PM_INSTANCE_VARIABLE_READ_NODE:
13367 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
13369 case PM_MULTI_TARGET_NODE:
13370 if (splat_parent) {
13373 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13377 case PM_SPLAT_NODE: {
13386 case PM_CALL_NODE: {
13398 (call->
block == NULL)
13411 pm_constant_id_t name = pm_parser_local_add_location(parser, &message_loc, 0);
13413 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
13417 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
13418 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
13421 parse_write_name(parser, &call->
name);
13422 return UP(pm_call_target_node_create(parser, call));
13429 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13430 return UP(pm_index_target_node_create(parser, call));
13438 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
13449 pm_node_t *result = parse_target(parser, target, multiple,
false);
13454 !match1(parser, PM_TOKEN_EQUAL) &&
13455 !(context_p(parser, PM_CONTEXT_FOR_INDEX) && match1(parser, PM_TOKEN_KEYWORD_IN)) &&
13456 !(context_p(parser, PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
13458 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13470 pm_shareable_constant_value_t shareable_constant = pm_parser_scope_shareable_constant_get(parser);
13472 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
13473 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
13484 switch (PM_NODE_TYPE(target)) {
13485 case PM_ERROR_RECOVERY_NODE:
13487 case PM_CLASS_VARIABLE_READ_NODE: {
13491 case PM_CONSTANT_PATH_NODE: {
13494 if (context_def_p(parser)) {
13495 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13498 return parse_shareable_constant_write(parser, node);
13500 case PM_CONSTANT_READ_NODE: {
13503 if (context_def_p(parser)) {
13504 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
13507 return parse_shareable_constant_write(parser, node);
13509 case PM_BACK_REFERENCE_READ_NODE:
13510 case PM_NUMBERED_REFERENCE_READ_NODE:
13511 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
13513 case PM_GLOBAL_VARIABLE_READ_NODE: {
13517 case PM_LOCAL_VARIABLE_READ_NODE: {
13522 uint32_t depth = local_read->
depth;
13523 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
13525 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(target), PM_NODE_LENGTH(target))) {
13526 pm_diagnostic_id_t diag_id = (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
13527 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(target), PM_NODE_LENGTH(target), diag_id, parser->start + PM_NODE_START(target));
13528 pm_node_unreference(parser, target);
13531 pm_locals_unread(&scope->locals, name);
13533 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &location,
operator));
13535 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
13537 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
13539 pm_node_unreference(parser, target);
13543 case PM_INSTANCE_VARIABLE_READ_NODE: {
13547 case PM_MULTI_TARGET_NODE:
13549 case PM_SPLAT_NODE: {
13557 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
13559 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
13561 case PM_CALL_NODE: {
13573 (call->
block == NULL)
13587 pm_refute_numbered_parameter(parser, message_loc.
start, message_loc.
length);
13588 pm_parser_local_add_location(parser, &message_loc, 0);
13590 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));
13591 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message_loc,
operator));
13610 pm_arguments_node_arguments_append(parser->arena, arguments, value);
13611 PM_NODE_LENGTH_SET_NODE(call, arguments);
13612 call->
equal_loc = TOK2LOC(parser,
operator);
13614 parse_write_name(parser, &call->
name);
13615 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13624 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13626 call->
arguments = pm_arguments_node_create(parser);
13629 pm_arguments_node_arguments_append(parser->arena, call->
arguments, value);
13630 PM_NODE_LENGTH_SET_NODE(target, value);
13633 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13634 call->
equal_loc = TOK2LOC(parser,
operator);
13638 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13653 pm_node_unreference(parser, value);
13660 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13673 switch (PM_NODE_TYPE(target)) {
13674 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13675 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13676 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13677 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13678 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13679 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13680 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13701parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13702 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13705 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13707 while (accept1(parser, PM_TOKEN_COMMA)) {
13708 if (accept1(parser, PM_TOKEN_USTAR)) {
13713 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13716 pm_token_t star_operator = parser->previous;
13719 if (token_begins_expression_p(parser->current.type)) {
13720 name = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13721 name = parse_target(parser, name,
true,
true);
13724 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13725 pm_multi_target_node_targets_append(parser, result, splat);
13727 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
13728 context_push(parser, PM_CONTEXT_MULTI_TARGET);
13729 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13730 target = parse_target(parser, target,
true,
false);
13732 pm_multi_target_node_targets_append(parser, result, target);
13733 context_pop(parser);
13734 }
else if (token_begins_expression_p(parser->current.type)) {
13735 pm_node_t *target = parse_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13736 target = parse_target(parser, target,
true,
false);
13738 pm_multi_target_node_targets_append(parser, result, target);
13739 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13742 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->previous));
13743 pm_multi_target_node_targets_append(parser, result, rest);
13756parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13757 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13762 if (context_p(parser, PM_CONTEXT_PARENS) || context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
13763 accept1(parser, PM_TOKEN_NEWLINE);
13767 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13768 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13778parse_statements(
pm_parser_t *parser, pm_context_t context, uint16_t depth) {
13781 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13784 if (context_terminator(context, &parser->current))
return NULL;
13790 context_push(parser, context);
13793 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13794 pm_statements_node_body_append(parser, statements, node,
true);
13798 if (parser->recovering) {
13801 if (context_terminator(context, &parser->current)) parser->recovering =
false;
13807 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13810 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13811 if (context_terminator(context, &parser->current))
break;
13821 if (context_terminator(context, &parser->current))
break;
13833 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE)) {
13834 parser_lex(parser);
13840 if (match1(parser, PM_TOKEN_EOF)) {
13841 parser->recovering =
true;
13845 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13846 if (context_terminator(context, &parser->current))
break;
13847 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13851 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
13852 parser->previous.
start = parser->previous.
end;
13853 parser->previous.
type = 0;
13857 context_pop(parser);
13859 bool last_value =
true;
13861 case PM_CONTEXT_BEGIN_ENSURE:
13862 case PM_CONTEXT_DEF_ENSURE:
13863 last_value =
false;
13868 pm_void_statements_check(parser, statements, last_value);
13879 pm_static_literal_inspect(&buffer, parser, duplicated);
13881 pm_diagnostic_list_append_format(
13882 &parser->metadata_arena,
13883 &parser->warning_list,
13886 PM_WARN_DUPLICATED_HASH_KEY,
13887 (
int) pm_buffer_length(&buffer),
13888 pm_buffer_value(&buffer),
13889 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line
13892 pm_buffer_cleanup(&buffer);
13901 const pm_node_t *duplicated = pm_static_literals_add(parser, literals, node,
true);
13903 if (duplicated != NULL) {
13904 pm_hash_key_duplicated_warn(parser, duplicated, node);
13919 for (
size_t index = 0; index < elements->
size; index++) {
13922 switch (PM_NODE_TYPE(element)) {
13923 case PM_ASSOC_NODE: {
13925 const pm_node_t *duplicated = pm_static_literals_add(parser, literals, key,
true);
13927 if (duplicated != NULL && PM_NODE_START(duplicated) < boundary) {
13928 pm_hash_key_duplicated_warn(parser, duplicated, key);
13933 case PM_ASSOC_SPLAT_NODE: {
13936 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13937 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, boundary);
13956 if ((previous = pm_static_literals_add(parser, literals, node,
false)) != NULL) {
13957 pm_diagnostic_list_append_format(
13958 &parser->metadata_arena,
13959 &parser->warning_list,
13960 PM_NODE_START(node),
13961 PM_NODE_LENGTH(node),
13962 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13963 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(node), parser->start_line).
line,
13964 pm_line_offset_list_line_column(&parser->line_offsets, PM_NODE_START(previous), parser->start_line).
line
13974 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13975 bool contains_keyword_splat =
false;
13980 switch (parser->current.type) {
13981 case PM_TOKEN_USTAR_STAR: {
13982 parser_lex(parser);
13986 if (token_begins_expression_p(parser->current.type)) {
13987 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));
13991 if (value != NULL && PM_NODE_TYPE_P(value, PM_HASH_NODE)) {
13992 pm_hash_key_static_literals_merge(parser, literals, (
const pm_hash_node_t *) value, PM_NODE_START(value));
13995 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13998 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13999 contains_keyword_splat =
true;
14002 case PM_TOKEN_LABEL: {
14004 parser_lex(parser);
14006 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
14007 pm_hash_key_static_literals_add(parser, literals, key);
14011 if (token_begins_expression_p(parser->current.type)) {
14012 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
14014 if (parser->encoding->isupper_char(label.
start, (label.
end - 1) - label.
start)) {
14016 value = UP(pm_constant_read_node_create(parser, &constant));
14021 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
14022 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
14024 depth = pm_parser_local_depth(parser, &identifier);
14028 value = UP(pm_call_node_variable_call_create(parser, &identifier));
14030 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
14035 value = UP(pm_implicit_node_create(parser, value));
14038 element = UP(pm_assoc_node_create(parser, key, NULL, value));
14042 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));
14046 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
14047 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
14050 pm_hash_key_static_literals_add(parser, literals, key);
14053 if (!pm_symbol_node_label_p(parser, key)) {
14054 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
14055 operator = parser->previous;
14058 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));
14059 element = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
14064 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
14065 pm_hash_node_elements_append(parser->arena, (
pm_hash_node_t *) node, element);
14071 if (!accept1(parser, PM_TOKEN_COMMA))
break;
14075 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
14079 if (token_begins_expression_p(parser->current.type))
continue;
14085 return contains_keyword_splat;
14090 if (pm_symbol_node_label_p(parser, argument)) {
14094 switch (PM_NODE_TYPE(argument)) {
14095 case PM_CALL_NODE: {
14097 if (
cast->opening_loc.length == 0 &&
cast->arguments != NULL) {
14098 if (PM_NODE_FLAG_P(
cast->arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
14101 if (
cast->block != NULL) {
14109 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
14118 arguments->
arguments = pm_arguments_node_create(parser);
14121 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, argument);
14132 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
14151 call->
block != NULL && PM_NODE_TYPE_P(call->
block, PM_BLOCK_NODE) &&
14166 switch (PM_NODE_TYPE(node)) {
14167 case PM_CALL_NODE: {
14172 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)) {
14177 if (pm_constant_path_command_call_p(parser, call)) {
14184 return pm_command_call_value_p(parser, call->
receiver);
14189 case PM_SUPER_NODE: {
14194 return cast->lparen_loc.length == 0 &&
14195 (
cast->arguments != NULL ||
cast->block != NULL) &&
14196 !(
cast->block != NULL && PM_NODE_TYPE_P(
cast->block, PM_BLOCK_NODE));
14198 case PM_YIELD_NODE: {
14200 return cast->lparen_loc.length == 0 &&
cast->arguments != NULL;
14202 case PM_RESCUE_MODIFIER_NODE:
14204 case PM_DEF_NODE: {
14206 if (
cast->equal_loc.length > 0 &&
cast->body != NULL) {
14208 if (PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE)) {
14211 return pm_command_call_value_p(parser, body);
14231 switch (PM_NODE_TYPE(node)) {
14233 return pm_constant_path_command_call_p(parser, (
const pm_call_node_t *) node);
14235 return pm_command_call_value_p(parser, node);
14248pm_block_call_p(
const pm_node_t *node) {
14249 while (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
14280 if (PM_NODE_TYPE_P(node, PM_SUPER_NODE)) {
14292parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint8_t flags, uint16_t depth) {
14293 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
14298 match2(parser, terminator, PM_TOKEN_EOF) ||
14299 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
14300 context_terminator(parser->current_context->context, &parser->current)
14305 bool parsed_first_argument =
false;
14306 bool parsed_bare_hash =
false;
14307 bool parsed_block_argument =
false;
14308 bool parsed_forwarding_arguments =
false;
14310 while (!match1(parser, PM_TOKEN_EOF)) {
14311 if (parsed_forwarding_arguments) {
14312 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
14317 switch (parser->current.type) {
14318 case PM_TOKEN_USTAR_STAR:
14319 case PM_TOKEN_LABEL: {
14320 if (parsed_bare_hash) {
14321 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
14325 argument = UP(hash);
14328 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
14330 parse_arguments_append(parser, arguments, argument);
14332 pm_node_flags_t node_flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14333 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14334 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14336 pm_static_literals_free(&hash_keys);
14337 parsed_bare_hash =
true;
14341 case PM_TOKEN_UAMPERSAND: {
14342 parser_lex(parser);
14346 if (token_begins_expression_p(parser->current.type)) {
14347 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14349 pm_parser_scope_forwarding_block_check(parser, &
operator);
14352 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
14353 if (parsed_block_argument) {
14354 parse_arguments_append(parser, arguments, argument);
14356 arguments->
block = argument;
14359 if (match1(parser, PM_TOKEN_COMMA)) {
14360 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
14363 parsed_block_argument =
true;
14366 case PM_TOKEN_USTAR: {
14367 parser_lex(parser);
14370 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
14371 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
14372 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
14373 if (parsed_bare_hash) {
14374 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
14377 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));
14379 if (parsed_bare_hash) {
14380 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);
14383 argument = UP(pm_splat_node_create(parser, &
operator, expression));
14386 parse_arguments_append(parser, arguments, argument);
14389 case PM_TOKEN_UDOT_DOT_DOT: {
14390 if (accepts_forwarding) {
14391 parser_lex(parser);
14393 if (token_begins_expression_p(parser->current.type)) {
14398 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));
14403 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
14405 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.length, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
14408 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
14410 pm_parser_scope_forwarding_all_check(parser, &parser->previous);
14411 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
14412 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
14415 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->previous));
14416 parse_arguments_append(parser, arguments, argument);
14417 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
14419 parsed_forwarding_arguments =
true;
14426 if (argument == NULL) {
14431 uint8_t command_flags = 0;
14432 if (!parsed_first_argument) {
14433 command_flags = PM_PARSE_ACCEPTS_COMMAND_CALL;
14434 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_0) command_flags |= PM_PARSE_ACCEPTS_COMMAND_DEF;
14437 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | command_flags | PM_PARSE_ACCEPTS_LABEL), PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
14440 bool contains_keywords =
false;
14441 bool contains_keyword_splat =
false;
14443 if (argument_allowed_for_bare_hash(parser, argument)) {
14444 if (parsed_bare_hash) {
14445 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
14454 if (pm_command_call_value_p(parser, argument) || pm_block_call_p(argument)) {
14455 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->previous.
type));
14459 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
14460 operator = parser->previous;
14464 contains_keywords =
true;
14468 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
14471 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));
14472 argument = UP(pm_assoc_node_create(parser, argument, NTOK2PTR(
operator), value));
14474 pm_keyword_hash_node_elements_append(parser->arena, bare_hash, argument);
14475 argument = UP(bare_hash);
14478 if (accept1(parser, PM_TOKEN_COMMA) && (
14479 token_begins_expression_p(parser->current.type) ||
14480 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
14482 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
14485 pm_static_literals_free(&hash_keys);
14486 parsed_bare_hash =
true;
14489 parse_arguments_append(parser, arguments, argument);
14491 pm_node_flags_t node_flags = 0;
14492 if (contains_keywords) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
14493 if (contains_keyword_splat) node_flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
14494 pm_node_flag_set(UP(arguments->
arguments), node_flags);
14500 parsed_first_argument =
true;
14503 if (PM_NODE_TYPE_P(argument, PM_ERROR_RECOVERY_NODE) || parser->recovering)
break;
14508 bool accepted_newline =
false;
14509 if (terminator != PM_TOKEN_EOF) {
14510 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14513 if (parser->previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
14517 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
14520 if (accepted_newline) {
14521 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14527 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
14530 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14537 if (pm_command_before_comma_p(parser, argument)) {
14538 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14548 if (match1(parser, terminator)) {
14554 if (parsed_forwarding_arguments) {
14555 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14574parse_required_destructured_parameter(
pm_parser_t *parser) {
14575 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
14578 pm_multi_target_node_opening_set(parser, node, &parser->previous);
14587 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14588 param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14589 pm_multi_target_node_targets_append(parser, node, param);
14590 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14594 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
14595 param = UP(parse_required_destructured_parameter(parser));
14596 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
14600 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14602 value = UP(pm_required_parameter_node_create(parser, &name));
14603 if (pm_parser_parameter_name_check(parser, &name)) {
14604 pm_node_flag_set_repeated_parameter(value);
14606 pm_parser_local_add_token(parser, &name, 1);
14609 param = UP(pm_splat_node_create(parser, &star, value));
14611 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
14614 param = UP(pm_required_parameter_node_create(parser, &name));
14615 if (pm_parser_parameter_name_check(parser, &name)) {
14616 pm_node_flag_set_repeated_parameter(param);
14618 pm_parser_local_add_token(parser, &name, 1);
14621 pm_multi_target_node_targets_append(parser, node, param);
14622 }
while (accept1(parser, PM_TOKEN_COMMA));
14624 accept1(parser, PM_TOKEN_NEWLINE);
14625 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
14626 pm_multi_target_node_closing_set(parser, node, &parser->previous);
14636 PM_PARAMETERS_NO_CHANGE = 0,
14637 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
14638 PM_PARAMETERS_ORDER_KEYWORDS_REST,
14639 PM_PARAMETERS_ORDER_KEYWORDS,
14640 PM_PARAMETERS_ORDER_REST,
14641 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14642 PM_PARAMETERS_ORDER_OPTIONAL,
14643 PM_PARAMETERS_ORDER_NAMED,
14644 PM_PARAMETERS_ORDER_NONE,
14645} pm_parameters_order_t;
14650static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
14651 [0] = PM_PARAMETERS_NO_CHANGE,
14652 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14653 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14654 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
14655 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
14656 [PM_TOKEN_PARENTHESIS_LEFT_GROUPING] = PM_PARAMETERS_ORDER_NAMED,
14657 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
14658 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
14659 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14660 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
14661 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
14662 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
14674 pm_parameters_order_t state = parameters_ordering[token->type];
14675 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
14679 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14680 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
14682 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
14686 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14687 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
14689 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
14690 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
14692 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
14694 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
14698 if (state < *current) *current = state;
14703parse_parameters_handle_trailing_comma(
14706 pm_parameters_order_t order,
14708 bool allows_trailing_comma
14710 if (!allows_trailing_comma) {
14711 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14716 if (order >= PM_PARAMETERS_ORDER_NAMED) {
14718 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->previous));
14720 if (params->
rest == NULL) {
14721 pm_parameters_node_rest_set(params, param);
14723 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14724 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14728 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14733 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1 || order == PM_PARAMETERS_ORDER_NOTHING_AFTER) {
14734 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14745 pm_binding_power_t binding_power,
14746 bool uses_parentheses,
14747 bool allows_trailing_comma,
14748 bool allows_forwarding_parameters,
14749 bool accepts_blocks_in_defaults,
14751 pm_diagnostic_id_t diag_id_forwarding,
14754 pm_do_loop_stack_push(parser,
false);
14757 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
14760 bool parsing =
true;
14762 switch (parser->current.type) {
14763 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
14764 update_parameter_state(parser, &parser->current, &order);
14765 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
14767 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14768 pm_parameters_node_requireds_append(parser->arena, params, param);
14770 pm_parameters_node_posts_append(parser->arena, params, param);
14774 case PM_TOKEN_UAMPERSAND:
14775 case PM_TOKEN_AMPERSAND: {
14776 update_parameter_state(parser, &parser->current, &order);
14777 parser_lex(parser);
14782 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1 && accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14783 param = (
pm_node_t *) pm_no_block_parameter_node_create(parser, &
operator, &parser->previous);
14787 bool repeated =
false;
14788 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14789 name = parser->previous;
14790 repeated = pm_parser_parameter_name_check(parser, &name);
14791 pm_parser_local_add_token(parser, &name, 1);
14793 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_BLOCK;
14796 param = (
pm_node_t *) pm_block_parameter_node_create(parser, NTOK2PTR(name), &
operator);
14798 pm_node_flag_set_repeated_parameter(param);
14802 if (params->
block == NULL) {
14803 pm_parameters_node_block_set(params, param);
14805 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_BLOCK_MULTI);
14806 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
14811 case PM_TOKEN_UDOT_DOT_DOT: {
14812 if (!allows_forwarding_parameters) {
14813 pm_parser_err_current(parser, diag_id_forwarding);
14816 bool succeeded = update_parameter_state(parser, &parser->current, &order);
14817 parser_lex(parser);
14819 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_ALL;
14826 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, keyword_rest)));
14827 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
14831 pm_parameters_node_keyword_rest_set(params, UP(param));
14834 case PM_TOKEN_CLASS_VARIABLE:
14835 case PM_TOKEN_IDENTIFIER:
14836 case PM_TOKEN_CONSTANT:
14837 case PM_TOKEN_INSTANCE_VARIABLE:
14838 case PM_TOKEN_GLOBAL_VARIABLE:
14839 case PM_TOKEN_METHOD_NAME: {
14840 parser_lex(parser);
14841 switch (parser->previous.
type) {
14842 case PM_TOKEN_CONSTANT:
14843 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14845 case PM_TOKEN_INSTANCE_VARIABLE:
14846 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14848 case PM_TOKEN_GLOBAL_VARIABLE:
14849 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14851 case PM_TOKEN_CLASS_VARIABLE:
14852 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14854 case PM_TOKEN_METHOD_NAME:
14855 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
14860 if (parser->current.type == PM_TOKEN_EQUAL) {
14861 update_parameter_state(parser, &parser->current, &order);
14863 update_parameter_state(parser, &parser->previous, &order);
14867 bool repeated = pm_parser_parameter_name_check(parser, &name);
14868 pm_parser_local_add_token(parser, &name, 1);
14870 if (match1(parser, PM_TOKEN_EQUAL)) {
14872 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14873 parser_lex(parser);
14876 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14878 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14879 pm_node_t *value = parse_value_expression(parser, binding_power, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14880 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14885 pm_node_flag_set_repeated_parameter(UP(param));
14887 pm_parameters_node_optionals_append(parser->arena, params, param);
14892 if ((parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3) && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14893 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &name, PM_ERR_PARAMETER_CIRCULAR);
14896 context_pop(parser);
14901 if (parser->recovering) {
14905 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14908 pm_node_flag_set_repeated_parameter(UP(param));
14910 pm_parameters_node_requireds_append(parser->arena, params, UP(param));
14914 pm_node_flag_set_repeated_parameter(UP(param));
14916 pm_parameters_node_posts_append(parser->arena, params, UP(param));
14921 case PM_TOKEN_LABEL: {
14922 if (!uses_parentheses && !in_block) parser->in_keyword_arg =
true;
14923 update_parameter_state(parser, &parser->current, &order);
14925 context_push(parser, PM_CONTEXT_DEFAULT_PARAMS);
14926 parser_lex(parser);
14932 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)) {
14933 pm_parser_err(parser, PM_TOKEN_START(parser, &local), PM_TOKEN_LENGTH(&local), PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14934 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14935 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14938 bool repeated = pm_parser_parameter_name_check(parser, &local);
14939 pm_parser_local_add_token(parser, &local, 1);
14941 switch (parser->current.type) {
14942 case PM_TOKEN_COMMA:
14943 case PM_TOKEN_PARENTHESIS_RIGHT:
14944 case PM_TOKEN_PIPE: {
14945 context_pop(parser);
14947 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14949 pm_node_flag_set_repeated_parameter(param);
14952 pm_parameters_node_keywords_append(parser->arena, params, param);
14955 case PM_TOKEN_SEMICOLON:
14956 case PM_TOKEN_NEWLINE: {
14957 context_pop(parser);
14959 if (uses_parentheses) {
14964 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14966 pm_node_flag_set_repeated_parameter(param);
14969 pm_parameters_node_keywords_append(parser->arena, params, param);
14975 if (token_begins_expression_p(parser->current.type)) {
14977 uint32_t reads = parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 ? pm_locals_reads(&parser->current_scope->locals, name_id) : 0;
14979 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14980 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));
14981 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14983 if (parser->version <= PM_OPTIONS_VERSION_CRUBY_3_3 && (pm_locals_reads(&parser->current_scope->locals, name_id) != reads)) {
14984 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &local, PM_ERR_PARAMETER_CIRCULAR);
14987 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14990 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14994 pm_node_flag_set_repeated_parameter(param);
14997 context_pop(parser);
14998 pm_parameters_node_keywords_append(parser->arena, params, param);
15003 if (parser->recovering) {
15010 parser->in_keyword_arg =
false;
15013 case PM_TOKEN_USTAR:
15014 case PM_TOKEN_STAR: {
15015 update_parameter_state(parser, &parser->current, &order);
15016 parser_lex(parser);
15020 bool repeated =
false;
15022 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
15023 name = parser->previous;
15024 repeated = pm_parser_parameter_name_check(parser, &name);
15025 pm_parser_local_add_token(parser, &name, 1);
15027 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS;
15030 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
15032 pm_node_flag_set_repeated_parameter(param);
15035 if (params->
rest == NULL) {
15036 pm_parameters_node_rest_set(params, param);
15038 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
15039 pm_parameters_node_posts_append(parser->arena, params, param);
15044 case PM_TOKEN_STAR_STAR:
15045 case PM_TOKEN_USTAR_STAR: {
15046 pm_parameters_order_t previous_order = order;
15047 update_parameter_state(parser, &parser->current, &order);
15048 parser_lex(parser);
15053 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
15054 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
15055 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
15058 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
15062 bool repeated =
false;
15063 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
15064 name = parser->previous;
15065 repeated = pm_parser_parameter_name_check(parser, &name);
15066 pm_parser_local_add_token(parser, &name, 1);
15068 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS;
15071 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, NTOK2PTR(name)));
15073 pm_node_flag_set_repeated_parameter(param);
15078 pm_parameters_node_keyword_rest_set(params, param);
15080 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
15081 pm_parameters_node_posts_append(parser->arena, params, UP(pm_error_recovery_node_create_unexpected(parser, param)));
15087 if (parser->previous.
type == PM_TOKEN_COMMA) {
15088 parse_parameters_handle_trailing_comma(parser, params, order, in_block, allows_trailing_comma);
15098 if (!parsing)
break;
15100 bool accepted_newline =
false;
15101 if (uses_parentheses) {
15102 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
15105 if (accept1(parser, PM_TOKEN_COMMA)) {
15108 if (accepted_newline) {
15109 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
15117 pm_do_loop_stack_pop(parser);
15120 if (PM_NODE_START(params) == PM_NODE_END(params)) {
15133 if (parser->heredoc_end == NULL) {
15137 return parser->line_offsets.
size - 1;
15143 return (
size_t) pm_line_offset_list_line(&parser->line_offsets, PM_TOKEN_START(parser, &parser->current), 0);
15152token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
15153 const uint8_t *cursor = parser->start + parser->line_offsets.
offsets[newline_index];
15154 const uint8_t *end = token->start;
15158 newline_index == 0 &&
15159 parser->start[0] == 0xef &&
15160 parser->start[1] == 0xbb &&
15161 parser->start[2] == 0xbf
15164 int64_t column = 0;
15165 for (; cursor < end; cursor++) {
15168 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
15175 if (break_on_non_space)
return -1;
15188parser_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) {
15190 if (!parser->warn_mismatched_indentation)
return;
15193 size_t closing_newline_index = token_newline_index(parser);
15194 if (opening_newline_index == closing_newline_index)
return;
15199 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
15200 if (!if_after_else && (opening_column == -1))
return;
15204 pm_token_t *closing_token = &parser->current;
15207 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
15208 if ((closing_column == -1) || (opening_column == closing_column))
return;
15212 if (allow_indent && (closing_column > opening_column))
return;
15215 PM_PARSER_WARN_FORMAT(
15217 PM_TOKEN_START(parser, closing_token),
15218 PM_TOKEN_LENGTH(closing_token),
15219 PM_WARN_INDENTATION_MISMATCH,
15220 (
int) (closing_token->
end - closing_token->
start),
15221 (
const char *) closing_token->
start,
15222 (
int) (opening_token->
end - opening_token->
start),
15223 (
const char *) opening_token->
start,
15224 ((int32_t) opening_newline_index) + parser->start_line
15229 PM_RESCUES_BEGIN = 1,
15236} pm_rescues_type_t;
15246 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
15247 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15248 parser_lex(parser);
15250 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->previous);
15252 switch (parser->current.type) {
15253 case PM_TOKEN_EQUAL_GREATER: {
15257 parser_lex(parser);
15258 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15260 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15261 reference = parse_target(parser, reference,
false,
false);
15263 pm_rescue_node_reference_set(rescue, reference);
15266 case PM_TOKEN_NEWLINE:
15267 case PM_TOKEN_SEMICOLON:
15268 case PM_TOKEN_KEYWORD_THEN:
15273 if (token_begins_expression_p(parser->current.type) || match1(parser, PM_TOKEN_USTAR)) {
15278 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
15279 pm_rescue_node_exceptions_append(parser->arena, rescue, expression);
15283 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
15287 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
15288 pm_rescue_node_operator_set(parser, rescue, &parser->previous);
15290 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX, PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
15291 reference = parse_target(parser, reference,
false,
false);
15293 pm_rescue_node_reference_set(rescue, reference);
15296 }
while (accept1(parser, PM_TOKEN_COMMA));
15301 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
15302 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15306 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
15310 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
15311 pm_accepts_block_stack_push(parser,
true);
15312 pm_context_t context;
15315 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_RESCUE;
break;
15316 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_RESCUE;
break;
15317 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_RESCUE;
break;
15318 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_RESCUE;
break;
15319 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_RESCUE;
break;
15320 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_RESCUE;
break;
15321 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_RESCUE;
break;
15322 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15326 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
15328 pm_accepts_block_stack_pop(parser);
15329 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15332 if (current == NULL) {
15333 pm_begin_node_rescue_clause_set(parent_node, rescue);
15335 pm_rescue_node_subsequent_set(current, rescue);
15344 if (current != NULL) {
15347 while (clause != NULL) {
15348 PM_NODE_LENGTH_SET_NODE(clause, current);
15354 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15355 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15356 opening_newline_index = token_newline_index(parser);
15358 else_keyword = parser->current;
15359 opening = &else_keyword;
15361 parser_lex(parser);
15362 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15365 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
15366 pm_accepts_block_stack_push(parser,
true);
15367 pm_context_t context;
15370 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ELSE;
break;
15371 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ELSE;
break;
15372 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ELSE;
break;
15373 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ELSE;
break;
15374 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ELSE;
break;
15375 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ELSE;
break;
15376 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ELSE;
break;
15377 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_ELSE;
break;
15380 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15381 pm_accepts_block_stack_pop(parser);
15383 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15386 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->current);
15387 pm_begin_node_else_clause_set(parent_node, else_clause);
15391 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
15394 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
15395 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15396 pm_token_t ensure_keyword = parser->current;
15398 parser_lex(parser);
15399 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15402 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15403 pm_accepts_block_stack_push(parser,
true);
15404 pm_context_t context;
15407 case PM_RESCUES_BEGIN: context = PM_CONTEXT_BEGIN_ENSURE;
break;
15408 case PM_RESCUES_BLOCK: context = PM_CONTEXT_BLOCK_ENSURE;
break;
15409 case PM_RESCUES_CLASS: context = PM_CONTEXT_CLASS_ENSURE;
break;
15410 case PM_RESCUES_DEF: context = PM_CONTEXT_DEF_ENSURE;
break;
15411 case PM_RESCUES_LAMBDA: context = PM_CONTEXT_LAMBDA_ENSURE;
break;
15412 case PM_RESCUES_MODULE: context = PM_CONTEXT_MODULE_ENSURE;
break;
15413 case PM_RESCUES_SCLASS: context = PM_CONTEXT_SCLASS_ENSURE;
break;
15414 default: assert(
false &&
"unreachable"); context = PM_CONTEXT_BEGIN_RESCUE;
break;
15417 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15418 pm_accepts_block_stack_pop(parser);
15420 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15423 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->current);
15424 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
15427 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
15428 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
15429 pm_begin_node_end_keyword_set(parser, parent_node, &parser->current);
15432 pm_begin_node_end_keyword_set(parser, parent_node, &end_keyword);
15442 pm_begin_node_t *node = pm_begin_node_create(parser, NULL, statements);
15443 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
15446 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->current);
15455parse_block_parameters(
15457 bool allows_trailing_comma,
15459 bool is_lambda_literal,
15460 bool accepts_blocks_in_defaults,
15464 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
15465 if (!is_lambda_literal) {
15466 context_push(parser, PM_CONTEXT_BLOCK_PARAMETERS);
15468 parameters = parse_parameters(
15470 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
15472 allows_trailing_comma,
15474 accepts_blocks_in_defaults,
15476 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
15477 (uint16_t) (depth + 1)
15479 if (!is_lambda_literal) {
15480 context_pop(parser);
15485 if (opening != NULL) {
15486 accept1(parser, PM_TOKEN_NEWLINE);
15488 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
15490 switch (parser->current.type) {
15491 case PM_TOKEN_CONSTANT:
15492 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
15493 parser_lex(parser);
15495 case PM_TOKEN_INSTANCE_VARIABLE:
15496 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
15497 parser_lex(parser);
15499 case PM_TOKEN_GLOBAL_VARIABLE:
15500 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
15501 parser_lex(parser);
15503 case PM_TOKEN_CLASS_VARIABLE:
15504 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
15505 parser_lex(parser);
15508 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
15512 bool repeated = pm_parser_parameter_name_check(parser, &parser->previous);
15513 pm_parser_local_add_token(parser, &parser->previous, 1);
15516 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
15518 pm_block_parameters_node_append_local(parser->arena, block_parameters, local);
15519 }
while (accept1(parser, PM_TOKEN_COMMA));
15523 return block_parameters;
15531outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
15532 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15533 if (scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
15544static const char *
const pm_numbered_parameter_names[] = {
15545 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
15555 pm_node_list_t *implicit_parameters = &parser->current_scope->implicit_parameters;
15559 if (parameters != NULL) {
15561 if (implicit_parameters->
size > 0) {
15564 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15565 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
15566 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15567 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
15569 assert(
false &&
"unreachable");
15578 if (implicit_parameters->
size == 0) {
15585 uint8_t numbered_parameter = 0;
15586 bool it_parameter =
false;
15588 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
15591 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
15592 if (it_parameter) {
15593 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
15594 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
15595 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
15596 }
else if (parser->current_scope->parameters & PM_SCOPE_PARAMETERS_NUMBERED_INNER) {
15597 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
15598 }
else if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
15599 numbered_parameter = MAX(numbered_parameter, (uint8_t) (parser->start[node->
location.
start + 1] -
'0'));
15601 assert(
false &&
"unreachable");
15603 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
15604 if (numbered_parameter > 0) {
15605 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
15607 it_parameter =
true;
15612 if (numbered_parameter > 0) {
15615 for (
pm_scope_t *scope = parser->current_scope->previous; scope != NULL && !scope->closed; scope = scope->previous) {
15616 scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
15618 return UP(pm_numbered_parameters_node_create(parser, opening, closing, numbered_parameter));
15621 if (it_parameter) {
15622 return UP(pm_it_parameters_node_create(parser, opening, closing));
15632parse_block(
pm_parser_t *parser, uint16_t depth) {
15634 accept1(parser, PM_TOKEN_NEWLINE);
15640 bool do_block = opening.
type != PM_TOKEN_BRACE_LEFT && opening.
type != PM_TOKEN_BRACE_LEFT_ARGUMENT;
15641 if (do_block) pm_accepts_block_stack_push(parser,
true);
15642 pm_parser_scope_push(parser,
false);
15646 if (accept1(parser, PM_TOKEN_PIPE)) {
15647 pm_token_t block_parameters_opening = parser->previous;
15648 if (match1(parser, PM_TOKEN_PIPE)) {
15649 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
15650 parser->command_start =
true;
15651 parser_lex(parser);
15653 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
15654 accept1(parser, PM_TOKEN_NEWLINE);
15655 parser->command_start =
true;
15656 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
15659 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
15662 accept1(parser, PM_TOKEN_NEWLINE);
15666 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
15667 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_BRACES, (uint16_t) (depth + 1)));
15670 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
15672 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
15673 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
15674 statements = UP(parse_statements(parser, PM_CONTEXT_BLOCK_KEYWORDS, (uint16_t) (depth + 1)));
15677 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
15678 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
15679 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
15685 pm_accepts_block_stack_pop(parser);
15686 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
15690 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
15691 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->previous);
15693 pm_parser_scope_pop(parser);
15694 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->previous);
15709parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool full_arguments, uint8_t flags, uint16_t depth) {
15714 !token_begins_expression_p(parser->current.type) &&
15715 !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)
15720 bool found =
false;
15721 bool parsed_command_args =
false;
15723 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
15725 arguments->
opening_loc = TOK2LOC(parser, &parser->previous);
15727 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15728 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15730 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_PARENTHESIS_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
15738 if (!full_arguments && parser->previous.
type == PM_TOKEN_COMMA) {
15739 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15742 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
15743 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARGUMENT_TERM_PAREN, pm_token_str(parser->current.type));
15744 parser->previous.
start = parser->previous.
end;
15745 parser->previous.
type = 0;
15748 arguments->
closing_loc = TOK2LOC(parser, &parser->previous);
15750 }
else if ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && token_begins_argument_p(parser->current.type) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
15752 parsed_command_args =
true;
15762 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);
15763 if (lookahead_delimiter) pm_accepts_block_stack_pop(parser);
15764 pm_accepts_block_stack_push(parser,
false);
15765 if (lookahead_delimiter) pm_accepts_block_stack_push(parser,
true);
15770 parse_arguments(parser, arguments, full_arguments, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
15775 if (parser->previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
15776 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
15784 bool lookahead_brace = match2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT);
15785 if (lookahead_brace) pm_accepts_block_stack_pop(parser);
15786 pm_accepts_block_stack_pop(parser);
15787 if (lookahead_brace) pm_accepts_block_stack_push(parser,
true);
15793 if (full_arguments) {
15796 if (accept2(parser, PM_TOKEN_BRACE_LEFT, PM_TOKEN_BRACE_LEFT_ARGUMENT)) {
15798 block = parse_block(parser, (uint16_t) (depth + 1));
15799 pm_arguments_validate_block(parser, arguments, block);
15800 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
15802 block = parse_block(parser, (uint16_t) (depth + 1));
15803 }
else if (parsed_command_args && pm_accepts_block_stack_p(parser) && (flags & PM_PARSE_ACCEPTS_DO_BLOCK) && accept1(parser, PM_TOKEN_KEYWORD_DO_BLOCK)) {
15805 block = parse_block(parser, (uint16_t) (depth + 1));
15808 if (block != NULL) {
15810 arguments->
block = UP(block);
15812 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
15814 if (arguments->
block != NULL) {
15816 arguments->
arguments = pm_arguments_node_create(parser);
15818 pm_arguments_node_arguments_append(parser->arena, arguments->
arguments, arguments->
block);
15820 arguments->
block = UP(block);
15834 bool in_sclass =
false;
15835 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15836 switch (context_node->context) {
15837 case PM_CONTEXT_BEGIN_ELSE:
15838 case PM_CONTEXT_BEGIN_ENSURE:
15839 case PM_CONTEXT_BEGIN_RESCUE:
15840 case PM_CONTEXT_BEGIN:
15841 case PM_CONTEXT_CASE_IN:
15842 case PM_CONTEXT_CASE_WHEN:
15843 case PM_CONTEXT_DEFAULT_PARAMS:
15844 case PM_CONTEXT_DEFINED:
15845 case PM_CONTEXT_ELSE:
15846 case PM_CONTEXT_ELSIF:
15847 case PM_CONTEXT_EMBEXPR:
15848 case PM_CONTEXT_FOR_INDEX:
15849 case PM_CONTEXT_FOR:
15850 case PM_CONTEXT_IF:
15851 case PM_CONTEXT_LOOP_PREDICATE:
15852 case PM_CONTEXT_MAIN:
15853 case PM_CONTEXT_MULTI_TARGET:
15854 case PM_CONTEXT_PARENS:
15855 case PM_CONTEXT_POSTEXE:
15856 case PM_CONTEXT_PREDICATE:
15857 case PM_CONTEXT_PREEXE:
15858 case PM_CONTEXT_RESCUE_MODIFIER:
15859 case PM_CONTEXT_TERNARY:
15860 case PM_CONTEXT_UNLESS:
15861 case PM_CONTEXT_UNTIL:
15862 case PM_CONTEXT_WHILE:
15866 case PM_CONTEXT_SCLASS_ELSE:
15867 case PM_CONTEXT_SCLASS_ENSURE:
15868 case PM_CONTEXT_SCLASS_RESCUE:
15869 case PM_CONTEXT_SCLASS:
15872 case PM_CONTEXT_CLASS_ELSE:
15873 case PM_CONTEXT_CLASS_ENSURE:
15874 case PM_CONTEXT_CLASS_RESCUE:
15875 case PM_CONTEXT_CLASS:
15876 case PM_CONTEXT_MODULE_ELSE:
15877 case PM_CONTEXT_MODULE_ENSURE:
15878 case PM_CONTEXT_MODULE_RESCUE:
15879 case PM_CONTEXT_MODULE:
15881 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15883 case PM_CONTEXT_BLOCK_BRACES:
15884 case PM_CONTEXT_BLOCK_ELSE:
15885 case PM_CONTEXT_BLOCK_ENSURE:
15886 case PM_CONTEXT_BLOCK_KEYWORDS:
15887 case PM_CONTEXT_BLOCK_RESCUE:
15888 case PM_CONTEXT_BLOCK_PARAMETERS:
15889 case PM_CONTEXT_DEF_ELSE:
15890 case PM_CONTEXT_DEF_ENSURE:
15891 case PM_CONTEXT_DEF_PARAMS:
15892 case PM_CONTEXT_DEF_RESCUE:
15893 case PM_CONTEXT_DEF:
15894 case PM_CONTEXT_LAMBDA_BRACES:
15895 case PM_CONTEXT_LAMBDA_DO_END:
15896 case PM_CONTEXT_LAMBDA_ELSE:
15897 case PM_CONTEXT_LAMBDA_ENSURE:
15898 case PM_CONTEXT_LAMBDA_RESCUE:
15902 case PM_CONTEXT_NONE:
15903 case PM_CONTEXT_MAXIMUM:
15905 assert(
false &&
"unreachable");
15909 if (in_sclass && parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
15910 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15920 for (
pm_context_node_t *context_node = parser->current_context; context_node != NULL; context_node = context_node->prev) {
15921 switch (context_node->context) {
15922 case PM_CONTEXT_BLOCK_BRACES:
15923 case PM_CONTEXT_BLOCK_KEYWORDS:
15924 case PM_CONTEXT_BLOCK_ELSE:
15925 case PM_CONTEXT_BLOCK_ENSURE:
15926 case PM_CONTEXT_BLOCK_PARAMETERS:
15927 case PM_CONTEXT_BLOCK_RESCUE:
15928 case PM_CONTEXT_DEFINED:
15929 case PM_CONTEXT_FOR:
15930 case PM_CONTEXT_LAMBDA_BRACES:
15931 case PM_CONTEXT_LAMBDA_DO_END:
15932 case PM_CONTEXT_LAMBDA_ELSE:
15933 case PM_CONTEXT_LAMBDA_ENSURE:
15934 case PM_CONTEXT_LAMBDA_RESCUE:
15935 case PM_CONTEXT_LOOP_PREDICATE:
15936 case PM_CONTEXT_UNTIL:
15937 case PM_CONTEXT_WHILE:
15941 case PM_CONTEXT_POSTEXE:
15943 if (context_node->context == PM_CONTEXT_POSTEXE) {
15944 if (parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
15949 case PM_CONTEXT_DEF:
15950 case PM_CONTEXT_DEF_PARAMS:
15951 case PM_CONTEXT_DEF_ELSE:
15952 case PM_CONTEXT_DEF_ENSURE:
15953 case PM_CONTEXT_DEF_RESCUE:
15954 case PM_CONTEXT_MAIN:
15955 case PM_CONTEXT_PREEXE:
15956 case PM_CONTEXT_SCLASS:
15957 case PM_CONTEXT_SCLASS_ELSE:
15958 case PM_CONTEXT_SCLASS_ENSURE:
15959 case PM_CONTEXT_SCLASS_RESCUE:
15969 assert(parser->current_block_exits != NULL);
15970 pm_node_list_append_inline(&parser->scratch_arena, parser->current_block_exits, node);
15972 case PM_CONTEXT_BEGIN_ELSE:
15973 case PM_CONTEXT_BEGIN_ENSURE:
15974 case PM_CONTEXT_BEGIN_RESCUE:
15975 case PM_CONTEXT_BEGIN:
15976 case PM_CONTEXT_CASE_IN:
15977 case PM_CONTEXT_CASE_WHEN:
15978 case PM_CONTEXT_CLASS_ELSE:
15979 case PM_CONTEXT_CLASS_ENSURE:
15980 case PM_CONTEXT_CLASS_RESCUE:
15981 case PM_CONTEXT_CLASS:
15982 case PM_CONTEXT_DEFAULT_PARAMS:
15983 case PM_CONTEXT_ELSE:
15984 case PM_CONTEXT_ELSIF:
15985 case PM_CONTEXT_EMBEXPR:
15986 case PM_CONTEXT_FOR_INDEX:
15987 case PM_CONTEXT_IF:
15988 case PM_CONTEXT_MODULE_ELSE:
15989 case PM_CONTEXT_MODULE_ENSURE:
15990 case PM_CONTEXT_MODULE_RESCUE:
15991 case PM_CONTEXT_MODULE:
15992 case PM_CONTEXT_MULTI_TARGET:
15993 case PM_CONTEXT_PARENS:
15994 case PM_CONTEXT_PREDICATE:
15995 case PM_CONTEXT_RESCUE_MODIFIER:
15996 case PM_CONTEXT_TERNARY:
15997 case PM_CONTEXT_UNLESS:
16001 case PM_CONTEXT_NONE:
16002 case PM_CONTEXT_MAXIMUM:
16004 assert(
false &&
"unreachable");
16016 pm_node_list_t *previous_block_exits = parser->current_block_exits;
16017 parser->current_block_exits = current_block_exits;
16018 return previous_block_exits;
16032 switch (PM_NODE_TYPE(block_exit)) {
16033 case PM_BREAK_NODE:
type =
"break";
break;
16034 case PM_NEXT_NODE:
type =
"next";
break;
16035 case PM_REDO_NODE:
type =
"redo";
break;
16036 default: assert(
false &&
"unreachable");
type =
"";
break;
16039 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
16042 parser->current_block_exits = previous_block_exits;
16051 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
16055 parser->current_block_exits = previous_block_exits;
16056 }
else if (previous_block_exits != NULL) {
16062 pm_node_list_concat(&parser->scratch_arena, previous_block_exits, parser->current_block_exits);
16063 parser->current_block_exits = previous_block_exits;
16068 flush_block_exits(parser, previous_block_exits);
16073parse_predicate(
pm_parser_t *parser, pm_binding_power_t binding_power, pm_context_t context,
pm_token_t *then_keyword, uint16_t depth) {
16074 context_push(parser, PM_CONTEXT_PREDICATE);
16075 pm_diagnostic_id_t error_id = context == PM_CONTEXT_IF ? PM_ERR_CONDITIONAL_IF_PREDICATE : PM_ERR_CONDITIONAL_UNLESS_PREDICATE;
16076 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));
16079 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16081 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
16082 predicate_closed =
true;
16083 *then_keyword = parser->previous;
16086 if (!predicate_closed) {
16087 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
16090 context_pop(parser);
16095parse_conditional(
pm_parser_t *parser, pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
16097 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
16102 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, context, &then_keyword, (uint16_t) (depth + 1));
16105 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
16106 pm_accepts_block_stack_push(parser,
true);
16107 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
16108 pm_accepts_block_stack_pop(parser);
16109 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16115 case PM_CONTEXT_IF:
16116 parent = UP(pm_if_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
16118 case PM_CONTEXT_UNLESS:
16119 parent = UP(pm_unless_node_create(parser, &keyword, predicate, NTOK2PTR(then_keyword), statements));
16122 assert(
false &&
"unreachable");
16130 if (context == PM_CONTEXT_IF) {
16131 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
16132 if (parser_end_of_line_p(parser)) {
16133 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
16136 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16138 parser_lex(parser);
16140 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_COMPOSITION, PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
16141 pm_accepts_block_stack_push(parser,
true);
16143 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
16144 pm_accepts_block_stack_pop(parser);
16145 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16147 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, NTOK2PTR(then_keyword), statements, NULL, NULL));
16153 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
16154 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
16155 opening_newline_index = token_newline_index(parser);
16157 parser_lex(parser);
16160 pm_accepts_block_stack_push(parser,
true);
16161 pm_statements_node_t *else_statements = parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
16162 pm_accepts_block_stack_pop(parser);
16164 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
16165 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
16166 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
16168 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->previous);
16171 case PM_CONTEXT_IF:
16172 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
16174 case PM_CONTEXT_UNLESS:
16178 assert(
false &&
"unreachable");
16182 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
16183 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
16188 case PM_CONTEXT_IF: {
16190 bool recursing =
true;
16192 while (recursing) {
16193 switch (PM_NODE_TYPE(current)) {
16195 pm_if_node_end_keyword_loc_set(parser, (
pm_if_node_t *) current, &parser->previous);
16197 recursing = current != NULL;
16200 pm_else_node_end_keyword_loc_set(parser, (
pm_else_node_t *) current, &parser->previous);
16211 case PM_CONTEXT_UNLESS:
16212 pm_unless_node_end_keyword_loc_set(parser, (
pm_unless_node_t *) parent, &parser->previous);
16215 assert(
false &&
"unreachable");
16219 pop_block_exits(parser, previous_block_exits);
16227#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16228 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
16229 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
16230 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: \
16231 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
16232 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
16233 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
16234 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
16235 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
16236 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
16237 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
16243#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
16244 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
16245 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
16246 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
16247 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
16248 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
16249 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
16250 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
16257#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
16258 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
16259 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
16260 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_XSTRING_BEGIN: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
16261 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
16262 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
16263 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
16264 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
16265 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
16271#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
16272 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
16273 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
16274 case PM_TOKEN_CLASS_VARIABLE
16280#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
16281 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
16282 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
16283 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
16287PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
16295 if (explicit_encoding != NULL) {
16296 if (explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
16299 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
16300 }
else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
16305 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
16316parse_string_part(
pm_parser_t *parser, uint16_t depth) {
16317 switch (parser->current.type) {
16324 case PM_TOKEN_STRING_CONTENT: {
16325 pm_node_t *node = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16326 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
16328 parser_lex(parser);
16337 case PM_TOKEN_EMBEXPR_BEGIN: {
16340 parser->explicit_encoding = NULL;
16342 pm_lex_state_t state = parser->lex_state;
16343 int brace_nesting = parser->brace_nesting;
16345 parser->brace_nesting = 0;
16346 lex_state_set(parser, PM_LEX_STATE_BEG);
16347 parser_lex(parser);
16352 if (!match3(parser, PM_TOKEN_EMBEXPR_END, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
16353 statements = parse_statements(parser, PM_CONTEXT_EMBEXPR, (uint16_t) (depth + 1));
16356 parser->brace_nesting = brace_nesting;
16357 lex_state_set(parser, state);
16358 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
16363 if (statements != NULL && statements->
body.
size == 1) {
16364 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
16367 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &parser->previous));
16376 case PM_TOKEN_EMBVAR: {
16379 parser->explicit_encoding = NULL;
16381 lex_state_set(parser, PM_LEX_STATE_BEG);
16382 parser_lex(parser);
16387 switch (parser->current.type) {
16390 case PM_TOKEN_BACK_REFERENCE:
16391 parser_lex(parser);
16392 variable = UP(pm_back_reference_read_node_create(parser, &parser->previous));
16396 case PM_TOKEN_NUMBERED_REFERENCE:
16397 parser_lex(parser);
16398 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16402 case PM_TOKEN_GLOBAL_VARIABLE:
16403 parser_lex(parser);
16404 variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
16408 case PM_TOKEN_INSTANCE_VARIABLE:
16409 parser_lex(parser);
16410 variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
16414 case PM_TOKEN_CLASS_VARIABLE:
16415 parser_lex(parser);
16416 variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
16422 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
16423 variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16427 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
16430 parser_lex(parser);
16431 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
16441static const uint8_t *
16442parse_operator_symbol_name(
const pm_token_t *name) {
16443 switch (name->
type) {
16444 case PM_TOKEN_TILDE:
16445 case PM_TOKEN_BANG:
16446 if (name->
end[-1] ==
'@')
return name->
end - 1;
16455 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->current, NULL);
16456 const uint8_t *end = parse_operator_symbol_name(&parser->current);
16458 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16459 parser_lex(parser);
16461 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, end);
16462 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
16473parse_symbol(
pm_parser_t *parser, pm_lex_state_t next_state, uint16_t depth) {
16475 parser_lex(parser);
16477 const pm_token_t opening = parser->previous;
16479 if (lex_mode.mode != PM_LEX_STRING) {
16480 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16482 switch (parser->current.type) {
16483 case PM_CASE_OPERATOR:
16484 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
16485 case PM_TOKEN_IDENTIFIER:
16486 case PM_TOKEN_CONSTANT:
16487 case PM_TOKEN_INSTANCE_VARIABLE:
16488 case PM_TOKEN_METHOD_NAME:
16489 case PM_TOKEN_CLASS_VARIABLE:
16490 case PM_TOKEN_GLOBAL_VARIABLE:
16491 case PM_TOKEN_NUMBERED_REFERENCE:
16492 case PM_TOKEN_BACK_REFERENCE:
16493 case PM_CASE_KEYWORD:
16494 parser_lex(parser);
16497 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
16501 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->previous, NULL);
16502 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16503 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16508 if (lex_mode.as.string.interpolation) {
16510 if (match1(parser, PM_TOKEN_STRING_END)) {
16511 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16512 parser_lex(parser);
16514 .
type = PM_TOKEN_STRING_CONTENT,
16515 .start = parser->previous.
start,
16516 .end = parser->previous.
start
16519 return UP(pm_symbol_node_create(parser, &opening, &content, &parser->previous));
16523 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
16527 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16528 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16529 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16531 return UP(pm_string_node_to_symbol_node(parser, (
pm_string_node_t *) part, &opening, &parser->previous));
16535 if (part) pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16537 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16538 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16539 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16543 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
16544 if (match1(parser, PM_TOKEN_EOF)) {
16545 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16547 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
16550 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16557 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16558 content = parser->current;
16559 unescaped = parser->current_string;
16560 parser_lex(parser);
16571 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16573 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16574 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16576 part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->current, NULL, &parser->current_string));
16577 pm_interpolated_symbol_node_append(parser->arena, symbol, part);
16579 if (next_state != PM_LEX_STATE_NONE) {
16580 lex_state_set(parser, next_state);
16583 parser_lex(parser);
16584 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16586 pm_interpolated_symbol_node_closing_loc_set(parser, symbol, &parser->previous);
16590 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->previous.
end, .end = parser->previous.
end };
16591 pm_string_shared_init(&unescaped, content.
start, content.
end);
16594 if (next_state != PM_LEX_STATE_NONE) {
16595 lex_state_set(parser, next_state);
16598 if (match1(parser, PM_TOKEN_EOF)) {
16599 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
16601 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
16604 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
false)));
16612parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
16613 switch (parser->current.type) {
16614 case PM_CASE_OPERATOR:
16615 return parse_operator_symbol(parser, NULL, PM_LEX_STATE_NONE);
16616 case PM_CASE_KEYWORD:
16617 case PM_TOKEN_CONSTANT:
16618 case PM_TOKEN_IDENTIFIER:
16619 case PM_TOKEN_METHOD_NAME: {
16620 parser_lex(parser);
16622 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16623 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16624 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16628 case PM_TOKEN_SYMBOL_BEGIN:
16629 return parse_symbol(parser, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16631 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
16632 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16643parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
16644 switch (parser->current.type) {
16645 case PM_CASE_OPERATOR:
16646 return parse_operator_symbol(parser, NULL, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
16647 case PM_CASE_KEYWORD:
16648 case PM_TOKEN_CONSTANT:
16649 case PM_TOKEN_IDENTIFIER:
16650 case PM_TOKEN_METHOD_NAME: {
16651 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
16652 parser_lex(parser);
16654 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, NULL, &parser->previous, NULL);
16655 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
end);
16656 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, parser->explicit_encoding, &parser->previous, &symbol->
unescaped,
false));
16660 case PM_TOKEN_SYMBOL_BEGIN:
16661 return parse_symbol(parser, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
16662 case PM_TOKEN_BACK_REFERENCE:
16663 parser_lex(parser);
16664 return UP(pm_back_reference_read_node_create(parser, &parser->previous));
16665 case PM_TOKEN_NUMBERED_REFERENCE:
16666 parser_lex(parser);
16667 return UP(pm_numbered_reference_read_node_create(parser, &parser->previous));
16668 case PM_TOKEN_GLOBAL_VARIABLE:
16669 parser_lex(parser);
16670 return UP(pm_global_variable_read_node_create(parser, &parser->previous));
16672 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
16673 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
16683 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, &parser->previous);
16685 bool is_numbered_param = pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
16687 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
16688 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, (uint32_t) depth,
false));
16691 pm_scope_t *current_scope = parser->current_scope;
16692 if (!current_scope->closed && !(current_scope->parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
16693 if (is_numbered_param) {
16698 uint8_t maximum = (uint8_t) (parser->previous.
start[1] -
'0');
16699 for (uint8_t number = 1; number <= maximum; number++) {
16700 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
16703 if (!match1(parser, PM_TOKEN_EQUAL)) {
16704 parser->current_scope->parameters |= PM_SCOPE_PARAMETERS_NUMBERED_FOUND;
16707 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->previous, name_id, 0,
false));
16708 pm_node_list_append_inline(&parser->scratch_arena, ¤t_scope->implicit_parameters, node);
16711 }
else if ((parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) && pm_token_is_it(parser->previous.
start, parser->previous.
end)) {
16712 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->previous));
16713 pm_node_list_append_inline(&parser->scratch_arena, ¤t_scope->implicit_parameters, node);
16727 pm_node_flags_t flags = 0;
16729 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->previous.
end[-1] !=
'!') && (parser->previous.
end[-1] !=
'?')) {
16730 pm_node_t *node = parse_variable(parser);
16731 if (node != NULL)
return node;
16732 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
16735 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->previous);
16736 pm_node_flag_set(UP(node), flags);
16747parse_method_definition_name(
pm_parser_t *parser) {
16748 switch (parser->current.type) {
16749 case PM_CASE_KEYWORD:
16750 case PM_TOKEN_CONSTANT:
16751 case PM_TOKEN_METHOD_NAME:
16752 parser_lex(parser);
16753 return parser->previous;
16754 case PM_TOKEN_IDENTIFIER:
16755 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current));
16756 parser_lex(parser);
16757 return parser->previous;
16758 case PM_CASE_OPERATOR:
16759 lex_state_set(parser, PM_LEX_STATE_ENDFN);
16760 parser_lex(parser);
16761 return parser->previous;
16763 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_NAME, pm_token_str(parser->current.type));
16764 return (
pm_token_t) { .type = 0, .start = parser->current.start, .end = parser->current.end };
16774 size_t length = pm_string_length(
string);
16775 uint8_t *writable = (uint8_t *) pm_arena_memdup(arena, pm_string_source(
string), length,
PRISM_ALIGNOF(uint8_t));
16776 pm_string_init(
string, writable, length);
16781 size_t dest_length = pm_string_length(
string);
16782 const uint8_t *source_cursor = writable;
16783 const uint8_t *source_end = source_cursor + dest_length;
16788 size_t trimmed_whitespace = 0;
16794 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
16795 if (*source_cursor ==
'\t') {
16796 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
16797 if (trimmed_whitespace > common_whitespace)
break;
16799 trimmed_whitespace++;
16806 memmove(writable, source_cursor, (
size_t) (source_end - source_cursor));
16807 string->length = dest_length;
16817 const uint8_t *cursor = parser->start + PM_LOCATION_START(&string_node->
content_loc);
16818 return pm_memchr(cursor,
'\\', string_node->
content_loc.
length, parser->encoding_changed, parser->encoding) == NULL;
16830 bool dedent_next =
true;
16834 size_t write_index = 0;
16841 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
16842 nodes->
nodes[write_index++] = node;
16843 dedent_next =
false;
16849 parse_heredoc_dedent_string(parser->arena, &string_node->
unescaped, common_whitespace);
16852 if (heredoc_dedent_discard_string_node(parser, string_node)) {
16854 nodes->
nodes[write_index++] = node;
16858 dedent_next =
true;
16861 nodes->
size = write_index;
16868parse_strings_empty_content(
const uint8_t *location) {
16869 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
16877 assert(parser->current.type == PM_TOKEN_STRING_BEGIN);
16878 bool concating =
false;
16880 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16886 assert(lex_mode->mode == PM_LEX_STRING);
16887 bool lex_interpolation = lex_mode->as.string.interpolation;
16888 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
16891 parser_lex(parser);
16893 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16894 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16898 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
16899 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->previous);
16903 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16907 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, NULL, &parser->previous);
16908 pm_string_shared_init(&symbol->
unescaped, parser->previous.
start, parser->previous.
start);
16911 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16912 }
else if (!lex_interpolation) {
16918 if (match1(parser, PM_TOKEN_EOF)) {
16919 unescaped = PM_STRING_EMPTY;
16920 content = (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start, .end = parser->start };
16922 unescaped = parser->current_string;
16923 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16924 content = parser->previous;
16938 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16940 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &unescaped));
16941 pm_node_list_append_inline(parser->arena, &parts, part);
16944 part = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
16945 pm_node_list_append_inline(parser->arena, &parts, part);
16946 parser_lex(parser);
16947 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16949 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16950 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
16951 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16952 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, parser->explicit_encoding, &content, &unescaped,
true)));
16953 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16954 }
else if (match1(parser, PM_TOKEN_EOF)) {
16955 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16956 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16957 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16958 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16960 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_STRING_LITERAL_TERM, pm_token_str(parser->previous.
type));
16961 parser->previous.
start = parser->previous.
end;
16962 parser->previous.
type = 0;
16963 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped));
16965 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16972 const pm_encoding_t *explicit_encoding = parser->explicit_encoding;
16973 parser_lex(parser);
16975 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16976 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
16977 pm_node_flag_set(node, parse_unescaped_encoding(parser, explicit_encoding));
16983 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16984 const uint8_t *location = parser->previous.
end;
16985 if (location > parser->start && location[-1] ==
'\n') location--;
16986 pm_parser_err(parser, U32(location - parser->start), 0, PM_ERR_STRING_LITERAL_EOF);
16988 parser->previous.
start = parser->previous.
end;
16989 parser->previous.
type = 0;
16991 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16992 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->previous, &unescaped, parse_symbol_encoding(parser, explicit_encoding, &content, &unescaped,
true)));
16993 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16998 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
16999 pm_node_flag_set(part, parse_unescaped_encoding(parser, explicit_encoding));
17000 pm_node_list_append_inline(parser->arena, &parts, part);
17002 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
17003 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
17004 pm_node_list_append_inline(parser->arena, &parts, part);
17008 if (accept1(parser, PM_TOKEN_LABEL_END)) {
17009 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
17010 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
17011 }
else if (match1(parser, PM_TOKEN_EOF)) {
17012 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
17013 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
17015 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
17016 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
17026 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
17027 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
17028 pm_node_list_append_inline(parser->arena, &parts, part);
17032 if (accept1(parser, PM_TOKEN_LABEL_END)) {
17033 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->previous));
17034 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
17035 }
else if (match1(parser, PM_TOKEN_EOF)) {
17036 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
17037 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->current));
17039 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
17040 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->previous));
17044 if (current == NULL) {
17048 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
17059 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
17060 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
17066 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
17067 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
17072 pm_interpolated_string_node_append(parser, container, current);
17073 current = UP(container);
17083#define PM_PARSE_PATTERN_SINGLE 0
17084#define PM_PARSE_PATTERN_TOP 1
17085#define PM_PARSE_PATTERN_MULTI 2
17098 if (peek_at(parser, parser->start + location->
start) ==
'_')
return;
17100 if (!pm_constant_id_set_insert(&parser->scratch_arena, captures, capture)) {
17101 pm_parser_err(parser, location->
start, location->
length, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
17112 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
17114 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17115 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
17121 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
17129 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
17130 opening = parser->previous;
17131 accept1(parser, PM_TOKEN_NEWLINE);
17133 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17134 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17135 accept1(parser, PM_TOKEN_NEWLINE);
17136 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17139 closing = parser->previous;
17141 parser_lex(parser);
17142 opening = parser->previous;
17143 accept1(parser, PM_TOKEN_NEWLINE);
17145 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17146 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17147 accept1(parser, PM_TOKEN_NEWLINE);
17148 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17151 closing = parser->previous;
17157 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
17164 switch (PM_NODE_TYPE(inner)) {
17165 case PM_ARRAY_PATTERN_NODE: {
17169 PM_NODE_START_SET_NODE(pattern_node, node);
17170 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17173 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17174 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17176 return UP(pattern_node);
17181 case PM_FIND_PATTERN_NODE: {
17185 PM_NODE_START_SET_NODE(pattern_node, node);
17186 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17189 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17190 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17192 return UP(pattern_node);
17197 case PM_HASH_PATTERN_NODE: {
17201 PM_NODE_START_SET_NODE(pattern_node, node);
17202 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17205 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17206 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17208 return UP(pattern_node);
17220 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
17221 pm_array_pattern_node_requireds_append(parser->arena, pattern_node, inner);
17222 return UP(pattern_node);
17230 assert(parser->previous.
type == PM_TOKEN_USTAR);
17237 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17238 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17241 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17242 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17245 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17246 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17247 name = UP(pm_local_variable_target_node_create(
17251 (uint32_t) (depth == -1 ? 0 : depth)
17256 return pm_splat_node_create(parser, &
operator, name);
17264 assert(parser->current.type == PM_TOKEN_USTAR_STAR);
17265 parser_lex(parser);
17270 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
17271 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->previous));
17274 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
17275 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17278 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17279 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17282 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17283 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17284 value = UP(pm_local_variable_target_node_create(
17288 (uint32_t) (depth == -1 ? 0 : depth)
17292 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
17300pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
17301 ptrdiff_t length = end - start;
17302 if (length == 0)
return false;
17305 size_t width = char_is_identifier_start(parser, start, end - start);
17306 if (width == 0)
return false;
17309 if (parser->encoding_changed) {
17310 if (parser->encoding->isupper_char(start, length))
return false;
17312 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
17317 const uint8_t *cursor = start + width;
17318 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
17319 return cursor == end;
17329 const uint8_t *start = parser->start + PM_LOCATION_START(value_loc);
17330 const uint8_t *end = parser->start + PM_LOCATION_END(value_loc);
17332 pm_constant_id_t constant_id = pm_parser_constant_id_raw(parser, start, end);
17335 if (pm_slice_is_valid_local(parser, start, end)) {
17336 depth = pm_parser_local_depth_constant_id(parser, constant_id);
17338 pm_parser_err(parser, PM_NODE_START(key), PM_NODE_LENGTH(key), PM_ERR_PATTERN_HASH_KEY_LOCALS);
17340 if ((end > start) && ((end[-1] ==
'!') || (end[-1] ==
'?'))) {
17341 PM_PARSER_ERR_FORMAT(parser, value_loc->
start, value_loc->
length, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (end - start), (
const char *) start);
17346 pm_parser_local_add(parser, constant_id, start, end, 0);
17349 parse_pattern_capture(parser, captures, constant_id, value_loc);
17354 (uint32_t) (depth == -1 ? 0 : depth)
17357 return UP(pm_implicit_node_create(parser, UP(target)));
17366 if (pm_static_literals_add(parser, keys, node,
true) != NULL) {
17367 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
17380 switch (PM_NODE_TYPE(first_node)) {
17381 case PM_ASSOC_SPLAT_NODE:
17382 case PM_NO_KEYWORDS_PARAMETER_NODE:
17385 case PM_INTERPOLATED_SYMBOL_NODE:
17386 case PM_SYMBOL_NODE: {
17387 if (pm_symbol_node_label_p(parser, first_node)) {
17388 if (PM_NODE_TYPE_P(first_node, PM_INTERPOLATED_SYMBOL_NODE)) {
17389 pm_parser_err_node(parser, first_node, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17391 parse_pattern_hash_key(parser, &keys, first_node);
17401 if (!token_begins_pattern_p(parser->current.type)) {
17402 if (PM_NODE_TYPE_P(first_node, PM_SYMBOL_NODE)) {
17403 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
17405 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(first_node), 0));
17410 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17413 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17414 pm_node_list_append_inline(parser->arena, &assocs, assoc);
17423 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;
17424 pm_parser_err_node(parser, first_node, diag_id);
17426 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_START(first_node), PM_NODE_LENGTH(first_node)));
17427 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, NULL, value));
17429 pm_node_list_append_inline(parser->arena, &assocs, assoc);
17435 while (accept1(parser, PM_TOKEN_COMMA)) {
17441 if (!token_begins_pattern_p(parser->current.type)) {
17443 if (rest != NULL) {
17444 pm_parser_err_token(parser, &parser->current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17450 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
17451 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
17453 if (rest == NULL) {
17456 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17457 pm_node_list_append_inline(parser->arena, &assocs, assoc);
17462 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17463 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
17465 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
17466 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
17467 }
else if (!pm_symbol_node_label_p(parser, key)) {
17468 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17470 }
else if (accept1(parser, PM_TOKEN_LABEL)) {
17471 key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17473 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
17475 pm_token_t label = { .
type = PM_TOKEN_LABEL, .start = parser->previous.
end, .end = parser->previous.
end };
17476 key = UP(pm_symbol_node_create(parser, NULL, &label, NULL));
17479 parse_pattern_hash_key(parser, &keys, key);
17487 if (!token_begins_pattern_p(parser->current.type)) {
17488 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
17489 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
17491 value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(key), 0));
17494 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
17497 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NULL, value));
17499 if (rest != NULL) {
17500 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
17503 pm_node_list_append_inline(parser->arena, &assocs, assoc);
17510 pm_static_literals_free(&keys);
17519 switch (parser->current.type) {
17520 case PM_TOKEN_IDENTIFIER:
17521 case PM_TOKEN_METHOD_NAME: {
17522 parser_lex(parser);
17523 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17526 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17527 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17530 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17531 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17532 return UP(pm_local_variable_target_node_create(
17536 (uint32_t) (depth == -1 ? 0 : depth)
17539 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17541 parser_lex(parser);
17543 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17546 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->previous));
17551 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
17553 accept1(parser, PM_TOKEN_NEWLINE);
17554 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
17557 switch (PM_NODE_TYPE(inner)) {
17558 case PM_ARRAY_PATTERN_NODE: {
17561 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17562 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17564 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17565 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17567 return UP(pattern_node);
17572 case PM_FIND_PATTERN_NODE: {
17575 PM_NODE_START_SET_TOKEN(parser, pattern_node, &opening);
17576 PM_NODE_LENGTH_SET_TOKEN(parser, pattern_node, &closing);
17578 pattern_node->
opening_loc = TOK2LOC(parser, &opening);
17579 pattern_node->
closing_loc = TOK2LOC(parser, &closing);
17581 return UP(pattern_node);
17591 pm_array_pattern_node_requireds_append(parser->arena, node, inner);
17594 case PM_TOKEN_BRACE_LEFT_HASH: {
17595 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17596 parser->pattern_matching_newlines =
false;
17600 parser_lex(parser);
17602 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
17605 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->previous);
17609 switch (parser->current.type) {
17610 case PM_TOKEN_LABEL:
17611 parser_lex(parser);
17612 first_node = UP(pm_symbol_node_label_create(parser, &parser->previous));
17614 case PM_TOKEN_USTAR_STAR:
17615 first_node = parse_pattern_keyword_rest(parser, captures);
17617 case PM_TOKEN_STRING_BEGIN:
17618 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));
17621 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_PATTERN_HASH_KEY, pm_token_str(parser->current.type));
17622 parser_lex(parser);
17624 first_node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
17629 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
17631 accept1(parser, PM_TOKEN_NEWLINE);
17632 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
17635 PM_NODE_START_SET_TOKEN(parser, node, &opening);
17636 PM_NODE_LENGTH_SET_TOKEN(parser, node, &closing);
17642 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17645 case PM_TOKEN_UDOT_DOT:
17646 case PM_TOKEN_UDOT_DOT_DOT: {
17648 parser_lex(parser);
17652 switch (parser->current.type) {
17653 case PM_CASE_PRIMITIVE: {
17654 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));
17655 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17658 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
17659 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17660 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17664 case PM_CASE_PRIMITIVE: {
17665 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));
17668 if (pm_symbol_node_label_p(parser, node))
return node;
17671 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
17672 pm_parser_err_node(parser, node, diag_id);
17673 return UP(pm_error_recovery_node_create_unexpected(parser, node));
17677 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17683 switch (parser->current.type) {
17684 case PM_CASE_PRIMITIVE: {
17685 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));
17686 return UP(pm_range_node_create(parser, node, &
operator, right));
17689 return UP(pm_range_node_create(parser, node, &
operator, NULL));
17695 case PM_TOKEN_CARET: {
17696 parser_lex(parser);
17701 switch (parser->current.type) {
17702 case PM_TOKEN_IDENTIFIER: {
17703 parser_lex(parser);
17704 pm_node_t *variable = UP(parse_variable(parser));
17706 if (variable == NULL) {
17707 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, &parser->previous, PM_ERR_NO_LOCAL_VARIABLE);
17708 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->previous, 0));
17711 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17713 case PM_TOKEN_INSTANCE_VARIABLE: {
17714 parser_lex(parser);
17715 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->previous));
17717 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17719 case PM_TOKEN_CLASS_VARIABLE: {
17720 parser_lex(parser);
17721 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->previous));
17723 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17725 case PM_TOKEN_GLOBAL_VARIABLE: {
17726 parser_lex(parser);
17727 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->previous));
17729 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17731 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING: {
17732 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
17733 parser->pattern_matching_newlines =
false;
17736 parser_lex(parser);
17738 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));
17739 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
17741 accept1(parser, PM_TOKEN_NEWLINE);
17742 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
17743 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->previous));
17748 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
17749 pm_node_t *variable = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &
operator), PM_TOKEN_LENGTH(&
operator)));
17750 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
17754 case PM_TOKEN_UCOLON_COLON: {
17756 parser_lex(parser);
17758 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17761 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
17763 case PM_TOKEN_CONSTANT: {
17765 parser_lex(parser);
17767 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
17768 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
17771 pm_parser_err_current(parser, diag_id);
17772 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17784parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
17787 switch (PM_NODE_TYPE(node)) {
17788 case PM_LOCAL_VARIABLE_TARGET_NODE:
17791 if (peek_at(parser, parser->start + PM_NODE_START(node)) !=
'_') {
17792 pm_parser_err(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PATTERN_CAPTURE_IN_ALTERNATIVE);
17795 case PM_ARRAY_PATTERN_NODE:
17796 case PM_ASSOC_NODE:
17797 case PM_ASSOC_SPLAT_NODE:
17798 case PM_CAPTURE_PATTERN_NODE:
17799 case PM_FIND_PATTERN_NODE:
17800 case PM_HASH_PATTERN_NODE:
17801 case PM_IMPLICIT_NODE:
17802 case PM_PARENTHESES_NODE:
17803 case PM_SPLAT_NODE:
17817 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
17827 bool alternation =
false;
17829 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
17830 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->size) {
17831 parse_pattern_alternation_error(parser, node);
17834 switch (parser->current.type) {
17835 case PM_TOKEN_IDENTIFIER:
17836 case PM_TOKEN_BRACKET_LEFT_ARRAY:
17837 case PM_TOKEN_BRACE_LEFT_HASH:
17838 case PM_TOKEN_CARET:
17839 case PM_TOKEN_CONSTANT:
17840 case PM_TOKEN_UCOLON_COLON:
17841 case PM_TOKEN_UDOT_DOT:
17842 case PM_TOKEN_UDOT_DOT_DOT:
17843 case PM_CASE_PRIMITIVE: {
17844 if (!alternation) {
17845 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17848 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
17850 if (captures->size) parse_pattern_alternation_error(parser, right);
17851 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17856 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
17857 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17860 parser_lex(parser);
17862 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
17863 accept1(parser, PM_TOKEN_NEWLINE);
17864 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
17865 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->previous, 0));
17867 if (!alternation) {
17870 if (captures->size) parse_pattern_alternation_error(parser, right);
17871 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
17877 pm_parser_err_current(parser, diag_id);
17878 pm_node_t *right = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17880 if (!alternation) {
17883 if (captures->size) parse_pattern_alternation_error(parser, right);
17884 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->previous));
17894 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17896 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
17898 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &parser->previous);
17901 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
17902 pm_parser_local_add(parser, constant_id, parser->previous.
start, parser->previous.
end, 0);
17905 pm_location_t previous_loc = TOK2LOC(parser, &parser->previous);
17906 parse_pattern_capture(parser, captures, constant_id, &previous_loc);
17911 (uint32_t) (depth == -1 ? 0 : depth)
17914 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17928 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
17929 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
17934 bool leading_rest =
false;
17935 bool trailing_rest =
false;
17937 switch (parser->current.type) {
17938 case PM_TOKEN_LABEL: {
17939 parser_lex(parser);
17940 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->previous));
17941 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17943 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17944 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17949 case PM_TOKEN_USTAR_STAR: {
17950 node = parse_pattern_keyword_rest(parser, captures);
17951 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17953 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17954 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17959 case PM_TOKEN_STRING_BEGIN: {
17962 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17964 if (pm_symbol_node_label_p(parser, node)) {
17965 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17967 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17968 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17974 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17977 case PM_TOKEN_USTAR: {
17978 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17979 parser_lex(parser);
17980 node = UP(parse_pattern_rest(parser, captures));
17981 leading_rest =
true;
17987 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17993 if (pm_symbol_node_label_p(parser, node)) {
17994 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17997 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
18002 pm_node_list_append_inline(parser->arena, &nodes, node);
18005 while (accept1(parser, PM_TOKEN_COMMA)) {
18011 if (!token_begins_pattern_p(parser->current.type)) {
18016 if (trailing_rest) {
18017 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
18020 node = UP(pm_implicit_rest_node_create(parser, &parser->previous));
18021 pm_node_list_append_inline(parser->arena, &nodes, node);
18022 trailing_rest =
true;
18026 if (accept1(parser, PM_TOKEN_USTAR)) {
18027 node = UP(parse_pattern_rest(parser, captures));
18032 if (trailing_rest) {
18033 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
18036 trailing_rest =
true;
18038 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
18041 pm_node_list_append_inline(parser->arena, &nodes, node);
18048 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
18049 node = UP(pm_find_pattern_node_create(parser, &nodes));
18051 if (nodes.
size == 2) {
18052 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
18055 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
18057 if (leading_rest && trailing_rest) {
18058 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
18063 }
else if (leading_rest) {
18066 node = UP(pm_array_pattern_node_rest_create(parser, node));
18078parse_negative_numeric(
pm_node_t *node) {
18079 switch (PM_NODE_TYPE(node)) {
18080 case PM_INTEGER_NODE: {
18082 cast->base.location.start--;
18083 cast->base.location.length++;
18084 cast->value.negative =
true;
18087 case PM_FLOAT_NODE: {
18089 cast->base.location.start--;
18090 cast->base.location.length++;
18094 case PM_RATIONAL_NODE: {
18096 cast->base.location.start--;
18097 cast->base.location.length++;
18098 cast->numerator.negative =
true;
18101 case PM_IMAGINARY_NODE:
18107 assert(
false &&
"unreachable");
18118pm_parser_err_prefix(
pm_parser_t *parser, pm_diagnostic_id_t diag_id) {
18120 case PM_ERR_HASH_KEY: {
18121 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, pm_token_str(parser->previous.
type));
18124 case PM_ERR_HASH_VALUE:
18125 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
18126 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
18129 case PM_ERR_UNARY_RECEIVER: {
18130 const char *human = (parser->current.type == PM_TOKEN_EOF ?
"end-of-input" : pm_token_str(parser->current.type));
18131 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, diag_id, human, parser->previous.
start[0]);
18134 case PM_ERR_UNARY_DISALLOWED:
18135 case PM_ERR_EXPECT_ARGUMENT: {
18136 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, diag_id, pm_token_str(parser->current.type));
18140 pm_parser_err_previous(parser, diag_id);
18150#define CONTEXT_NONE 0
18151#define CONTEXT_THROUGH_ENSURE 1
18152#define CONTEXT_THROUGH_ELSE 2
18155 int context = CONTEXT_NONE;
18157 while (context_node != NULL) {
18158 switch (context_node->context) {
18159 case PM_CONTEXT_BEGIN_RESCUE:
18160 case PM_CONTEXT_BLOCK_RESCUE:
18161 case PM_CONTEXT_CLASS_RESCUE:
18162 case PM_CONTEXT_DEF_RESCUE:
18163 case PM_CONTEXT_LAMBDA_RESCUE:
18164 case PM_CONTEXT_MODULE_RESCUE:
18165 case PM_CONTEXT_SCLASS_RESCUE:
18166 case PM_CONTEXT_DEFINED:
18167 case PM_CONTEXT_RESCUE_MODIFIER:
18170 case PM_CONTEXT_CLASS:
18171 case PM_CONTEXT_DEF:
18172 case PM_CONTEXT_DEF_PARAMS:
18173 case PM_CONTEXT_MAIN:
18174 case PM_CONTEXT_MODULE:
18175 case PM_CONTEXT_PREEXE:
18176 case PM_CONTEXT_SCLASS:
18179 if (context == CONTEXT_NONE) {
18180 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
18181 }
else if (context == CONTEXT_THROUGH_ENSURE) {
18182 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
18183 }
else if (context == CONTEXT_THROUGH_ELSE) {
18184 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
18187 case PM_CONTEXT_BEGIN_ELSE:
18188 case PM_CONTEXT_BLOCK_ELSE:
18189 case PM_CONTEXT_CLASS_ELSE:
18190 case PM_CONTEXT_DEF_ELSE:
18191 case PM_CONTEXT_LAMBDA_ELSE:
18192 case PM_CONTEXT_MODULE_ELSE:
18193 case PM_CONTEXT_SCLASS_ELSE:
18196 context = CONTEXT_THROUGH_ELSE;
18198 case PM_CONTEXT_BEGIN_ENSURE:
18199 case PM_CONTEXT_BLOCK_ENSURE:
18200 case PM_CONTEXT_CLASS_ENSURE:
18201 case PM_CONTEXT_DEF_ENSURE:
18202 case PM_CONTEXT_LAMBDA_ENSURE:
18203 case PM_CONTEXT_MODULE_ENSURE:
18204 case PM_CONTEXT_SCLASS_ENSURE:
18207 context = CONTEXT_THROUGH_ENSURE;
18209 case PM_CONTEXT_NONE:
18210 case PM_CONTEXT_MAXIMUM:
18212 assert(
false &&
"unreachable");
18214 case PM_CONTEXT_BEGIN:
18215 case PM_CONTEXT_BLOCK_BRACES:
18216 case PM_CONTEXT_BLOCK_KEYWORDS:
18217 case PM_CONTEXT_BLOCK_PARAMETERS:
18218 case PM_CONTEXT_CASE_IN:
18219 case PM_CONTEXT_CASE_WHEN:
18220 case PM_CONTEXT_DEFAULT_PARAMS:
18221 case PM_CONTEXT_ELSE:
18222 case PM_CONTEXT_ELSIF:
18223 case PM_CONTEXT_EMBEXPR:
18224 case PM_CONTEXT_FOR_INDEX:
18225 case PM_CONTEXT_FOR:
18226 case PM_CONTEXT_IF:
18227 case PM_CONTEXT_LAMBDA_BRACES:
18228 case PM_CONTEXT_LAMBDA_DO_END:
18229 case PM_CONTEXT_LOOP_PREDICATE:
18230 case PM_CONTEXT_MULTI_TARGET:
18231 case PM_CONTEXT_PARENS:
18232 case PM_CONTEXT_POSTEXE:
18233 case PM_CONTEXT_PREDICATE:
18234 case PM_CONTEXT_TERNARY:
18235 case PM_CONTEXT_UNLESS:
18236 case PM_CONTEXT_UNTIL:
18237 case PM_CONTEXT_WHILE:
18243 context_node = context_node->prev;
18247#undef CONTEXT_ENSURE
18258 while (context_node != NULL) {
18259 switch (context_node->context) {
18260 case PM_CONTEXT_DEF:
18261 case PM_CONTEXT_DEF_PARAMS:
18262 case PM_CONTEXT_DEFINED:
18263 case PM_CONTEXT_DEF_ENSURE:
18264 case PM_CONTEXT_DEF_RESCUE:
18265 case PM_CONTEXT_DEF_ELSE:
18269 case PM_CONTEXT_CLASS:
18270 case PM_CONTEXT_CLASS_ENSURE:
18271 case PM_CONTEXT_CLASS_RESCUE:
18272 case PM_CONTEXT_CLASS_ELSE:
18273 case PM_CONTEXT_MAIN:
18274 case PM_CONTEXT_MODULE:
18275 case PM_CONTEXT_MODULE_ENSURE:
18276 case PM_CONTEXT_MODULE_RESCUE:
18277 case PM_CONTEXT_MODULE_ELSE:
18278 case PM_CONTEXT_SCLASS:
18279 case PM_CONTEXT_SCLASS_RESCUE:
18280 case PM_CONTEXT_SCLASS_ENSURE:
18281 case PM_CONTEXT_SCLASS_ELSE:
18284 pm_parser_err_node(parser, UP(node), PM_ERR_INVALID_YIELD);
18286 case PM_CONTEXT_NONE:
18287 case PM_CONTEXT_MAXIMUM:
18289 assert(
false &&
"unreachable");
18291 case PM_CONTEXT_BEGIN:
18292 case PM_CONTEXT_BEGIN_ELSE:
18293 case PM_CONTEXT_BEGIN_ENSURE:
18294 case PM_CONTEXT_BEGIN_RESCUE:
18295 case PM_CONTEXT_BLOCK_BRACES:
18296 case PM_CONTEXT_BLOCK_KEYWORDS:
18297 case PM_CONTEXT_BLOCK_ELSE:
18298 case PM_CONTEXT_BLOCK_ENSURE:
18299 case PM_CONTEXT_BLOCK_PARAMETERS:
18300 case PM_CONTEXT_BLOCK_RESCUE:
18301 case PM_CONTEXT_CASE_IN:
18302 case PM_CONTEXT_CASE_WHEN:
18303 case PM_CONTEXT_DEFAULT_PARAMS:
18304 case PM_CONTEXT_ELSE:
18305 case PM_CONTEXT_ELSIF:
18306 case PM_CONTEXT_EMBEXPR:
18307 case PM_CONTEXT_FOR_INDEX:
18308 case PM_CONTEXT_FOR:
18309 case PM_CONTEXT_IF:
18310 case PM_CONTEXT_LAMBDA_BRACES:
18311 case PM_CONTEXT_LAMBDA_DO_END:
18312 case PM_CONTEXT_LAMBDA_ELSE:
18313 case PM_CONTEXT_LAMBDA_ENSURE:
18314 case PM_CONTEXT_LAMBDA_RESCUE:
18315 case PM_CONTEXT_LOOP_PREDICATE:
18316 case PM_CONTEXT_MULTI_TARGET:
18317 case PM_CONTEXT_PARENS:
18318 case PM_CONTEXT_POSTEXE:
18319 case PM_CONTEXT_PREDICATE:
18320 case PM_CONTEXT_PREEXE:
18321 case PM_CONTEXT_RESCUE_MODIFIER:
18322 case PM_CONTEXT_TERNARY:
18323 case PM_CONTEXT_UNLESS:
18324 case PM_CONTEXT_UNTIL:
18325 case PM_CONTEXT_WHILE:
18331 context_node = context_node->prev;
18340parse_case(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18341 size_t opening_newline_index = token_newline_index(parser);
18342 parser_lex(parser);
18348 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18350 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18351 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18353 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18355 }
else if (!token_begins_expression_p(parser->current.type)) {
18358 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));
18359 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18362 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18363 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18364 parser_lex(parser);
18365 pop_block_exits(parser, previous_block_exits);
18366 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18367 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->previous));
18374 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18375 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, NULL);
18381 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18382 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18383 parser_lex(parser);
18386 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18389 if (accept1(parser, PM_TOKEN_USTAR)) {
18391 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));
18393 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18394 pm_when_node_conditions_append(parser->arena, when_node, UP(splat_node));
18396 if (PM_NODE_TYPE_P(expression, PM_ERROR_RECOVERY_NODE))
break;
18398 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));
18399 pm_when_node_conditions_append(parser->arena, when_node, condition);
18403 if (PM_NODE_TYPE_P(condition, PM_ERROR_RECOVERY_NODE))
break;
18407 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18408 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18409 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE) && parser->version < PM_OPTIONS_VERSION_CRUBY_4_1) {
18410 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18413 pm_when_clause_static_literals_add(parser, &literals, condition);
18415 }
while (accept1(parser, PM_TOKEN_COMMA));
18417 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18418 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18419 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18422 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18423 pm_when_node_then_keyword_loc_set(parser, when_node, &parser->previous);
18426 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18427 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18428 if (statements != NULL) {
18429 pm_when_node_statements_set(when_node, statements);
18433 pm_case_node_condition_append(parser->arena, case_node, UP(when_node));
18439 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18442 pm_static_literals_free(&literals);
18443 node = UP(case_node);
18445 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate);
18449 if (predicate == NULL) {
18450 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18455 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18456 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18458 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
18459 parser->pattern_matching_newlines =
true;
18461 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18462 parser->command_start =
false;
18463 parser_lex(parser);
18468 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));
18470 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
18475 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18477 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));
18478 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18479 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18481 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));
18482 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18489 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18490 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18491 then_keyword = parser->previous;
18494 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18495 then_keyword = parser->previous;
18501 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18504 statements = parse_statements(parser, PM_CONTEXT_CASE_IN, (uint16_t) (depth + 1));
18509 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, NTOK2PTR(then_keyword)));
18510 pm_case_match_node_condition_append(parser->arena, case_node, condition);
18516 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18519 node = UP(case_node);
18522 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18523 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18527 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18528 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser, PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->current);
18530 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->current);
18533 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18534 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18540 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18541 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18543 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18544 pm_case_node_end_keyword_loc_set(parser, (
pm_case_node_t *) node, &parser->previous);
18546 pm_case_match_node_end_keyword_loc_set(parser, (
pm_case_match_node_t *) node, &parser->previous);
18549 pop_block_exits(parser, previous_block_exits);
18558parse_class(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18559 size_t opening_newline_index = token_newline_index(parser);
18560 parser_lex(parser);
18562 pm_token_t class_keyword = parser->previous;
18563 pm_do_loop_stack_push(parser,
false);
18566 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18568 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18570 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));
18572 pm_parser_scope_push(parser,
true);
18573 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18574 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_SINGLETON_CLASS_DELIMITER, pm_token_str(parser->current.type));
18578 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18579 pm_accepts_block_stack_push(parser,
true);
18580 statements = UP(parse_statements(parser, PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18581 pm_accepts_block_stack_pop(parser);
18584 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18585 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18586 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)));
18588 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18591 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18594 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18596 pm_parser_scope_pop(parser);
18597 pm_do_loop_stack_pop(parser);
18599 flush_block_exits(parser, previous_block_exits);
18600 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->previous));
18603 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));
18605 if (name.
type != PM_TOKEN_CONSTANT) {
18606 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18612 if (match1(parser, PM_TOKEN_LESS)) {
18613 inheritance_operator = parser->current;
18614 lex_state_set(parser, PM_LEX_STATE_BEG);
18616 parser->command_start =
true;
18617 parser_lex(parser);
18619 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));
18624 pm_parser_scope_push(parser,
true);
18626 if (inheritance_operator.
start != NULL) {
18627 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18629 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18633 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18634 pm_accepts_block_stack_push(parser,
true);
18635 statements = UP(parse_statements(parser, PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18636 pm_accepts_block_stack_pop(parser);
18639 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18640 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18641 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)));
18643 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18646 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18648 if (context_def_p(parser)) {
18649 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18653 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
18655 pm_parser_scope_pop(parser);
18656 pm_do_loop_stack_pop(parser);
18658 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18659 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18660 if (!PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
18661 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
18665 pop_block_exits(parser, previous_block_exits);
18666 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, NTOK2PTR(inheritance_operator), superclass, statements, &parser->previous));
18673parse_def(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
18675 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18678 size_t opening_newline_index = token_newline_index(parser);
18686 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18687 parser_lex(parser);
18691 bool valid_name =
true;
18693 switch (parser->current.type) {
18694 case PM_CASE_OPERATOR:
18695 pm_parser_scope_push(parser,
true);
18696 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18697 parser_lex(parser);
18699 name = parser->previous;
18701 case PM_TOKEN_IDENTIFIER: {
18702 parser_lex(parser);
18704 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18705 receiver = parse_variable_call(parser);
18707 pm_parser_scope_push(parser,
true);
18708 lex_state_set(parser, PM_LEX_STATE_FNAME);
18709 parser_lex(parser);
18711 operator = parser->previous;
18712 name = parse_method_definition_name(parser);
18714 pm_refute_numbered_parameter(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous));
18715 pm_parser_scope_push(parser,
true);
18717 name = parser->previous;
18722 case PM_TOKEN_INSTANCE_VARIABLE:
18723 case PM_TOKEN_CLASS_VARIABLE:
18724 case PM_TOKEN_GLOBAL_VARIABLE:
18725 valid_name =
false;
18727 case PM_TOKEN_CONSTANT:
18728 case PM_TOKEN_KEYWORD_NIL:
18729 case PM_TOKEN_KEYWORD_SELF:
18730 case PM_TOKEN_KEYWORD_TRUE:
18731 case PM_TOKEN_KEYWORD_FALSE:
18732 case PM_TOKEN_KEYWORD___FILE__:
18733 case PM_TOKEN_KEYWORD___LINE__:
18734 case PM_TOKEN_KEYWORD___ENCODING__: {
18735 pm_parser_scope_push(parser,
true);
18736 parser_lex(parser);
18740 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18741 lex_state_set(parser, PM_LEX_STATE_FNAME);
18742 parser_lex(parser);
18743 operator = parser->previous;
18745 switch (identifier.
type) {
18746 case PM_TOKEN_CONSTANT:
18747 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18749 case PM_TOKEN_INSTANCE_VARIABLE:
18750 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18752 case PM_TOKEN_CLASS_VARIABLE:
18753 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18755 case PM_TOKEN_GLOBAL_VARIABLE:
18756 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18758 case PM_TOKEN_KEYWORD_NIL:
18759 receiver = UP(pm_nil_node_create(parser, &identifier));
18761 case PM_TOKEN_KEYWORD_SELF:
18762 receiver = UP(pm_self_node_create(parser, &identifier));
18764 case PM_TOKEN_KEYWORD_TRUE:
18765 receiver = UP(pm_true_node_create(parser, &identifier));
18767 case PM_TOKEN_KEYWORD_FALSE:
18768 receiver = UP(pm_false_node_create(parser, &identifier));
18770 case PM_TOKEN_KEYWORD___FILE__:
18771 receiver = UP(pm_source_file_node_create(parser, &identifier));
18773 case PM_TOKEN_KEYWORD___LINE__:
18774 receiver = UP(pm_source_line_node_create(parser, &identifier));
18776 case PM_TOKEN_KEYWORD___ENCODING__:
18777 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18783 name = parse_method_definition_name(parser);
18786 PM_PARSER_ERR_TOKEN_FORMAT(parser, &identifier, PM_ERR_DEF_NAME, pm_token_str(identifier.
type));
18793 case PM_TOKEN_PARENTHESIS_LEFT: {
18797 context_pop(parser);
18798 parser_lex(parser);
18801 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));
18803 accept1(parser, PM_TOKEN_NEWLINE);
18804 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18807 lex_state_set(parser, PM_LEX_STATE_FNAME);
18808 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18810 operator = parser->previous;
18811 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18815 pm_parser_scope_push(parser,
true);
18816 context_push(parser, PM_CONTEXT_DEF_PARAMS);
18817 name = parse_method_definition_name(parser);
18821 pm_parser_scope_push(parser,
true);
18822 name = parse_method_definition_name(parser);
18830 bool accept_endless_def =
true;
18831 switch (parser->current.type) {
18832 case PM_TOKEN_PARENTHESIS_LEFT: {
18833 parser_lex(parser);
18834 lparen = parser->previous;
18836 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18840 bool allow_trailing_comma = parser->version >= PM_OPTIONS_VERSION_CRUBY_4_1;
18841 params = parse_parameters(
18843 PM_BINDING_POWER_DEFINED,
18845 allow_trailing_comma,
18849 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18850 (uint16_t) (depth + 1)
18854 lex_state_set(parser, PM_LEX_STATE_BEG);
18855 parser->command_start =
true;
18857 context_pop(parser);
18858 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18859 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_DEF_PARAMS_TERM_PAREN, pm_token_str(parser->current.type));
18860 parser->previous.
start = parser->previous.
end;
18861 parser->previous.
type = 0;
18864 rparen = parser->previous;
18867 case PM_CASE_PARAMETER: {
18870 if (parser->current.type == PM_TOKEN_LABEL) {
18871 lex_state_set(parser, parser->lex_state | PM_LEX_STATE_LABEL);
18874 params = parse_parameters(
18876 PM_BINDING_POWER_DEFINED,
18882 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18883 (uint16_t) (depth + 1)
18888 accept_endless_def =
false;
18890 context_pop(parser);
18895 context_pop(parser);
18904 if (accept1(parser, PM_TOKEN_EQUAL)) {
18905 if (token_is_setter_name(&name)) {
18906 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18908 if (!accept_endless_def) {
18909 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18912 parser->current_context->context == PM_CONTEXT_DEFAULT_PARAMS &&
18913 parser->current_context->prev->context == PM_CONTEXT_BLOCK_PARAMETERS
18915 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");
18917 equal = parser->previous;
18919 context_push(parser, PM_CONTEXT_DEF);
18920 pm_do_loop_stack_push(parser,
false);
18921 statements = UP(pm_statements_node_create(parser));
18925 uint8_t allow_flags = (flags & PM_PARSE_ACCEPTS_COMMAND_DEF) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0;
18937 pm_accepts_block_stack_push(parser,
true);
18938 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));
18945 if (accept1(parser, PM_TOKEN_KEYWORD_DO)) {
18946 pm_block_node_t *block = parse_block(parser, (uint16_t) (depth + 1));
18947 pm_parser_err_node(parser, UP(block), PM_ERR_DEF_ENDLESS_DO_BLOCK);
18954 while (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18955 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
18957 pm_token_t rescue_keyword = parser->previous;
18961 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));
18962 context_pop(parser);
18964 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18967 pm_accepts_block_stack_pop(parser);
18972 if (PM_NODE_TYPE_P(statement, PM_DEF_NODE) && pm_command_call_value_p(parser, statement)) {
18973 PM_PARSER_ERR_NODE_FORMAT(parser, statement, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
18976 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18977 pm_do_loop_stack_pop(parser);
18978 context_pop(parser);
18980 if (lparen.
start == NULL) {
18981 lex_state_set(parser, PM_LEX_STATE_BEG);
18982 parser->command_start =
true;
18983 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18985 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18988 pm_accepts_block_stack_push(parser,
true);
18989 pm_do_loop_stack_push(parser,
false);
18991 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18992 pm_accepts_block_stack_push(parser,
true);
18993 statements = UP(parse_statements(parser, PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18994 pm_accepts_block_stack_pop(parser);
18997 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18998 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18999 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)));
19001 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
19004 pm_accepts_block_stack_pop(parser);
19005 pm_do_loop_stack_pop(parser);
19007 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
19008 end_keyword = parser->previous;
19012 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
19013 pm_parser_scope_pop(parser);
19018 pm_constant_id_t name_id = pm_parser_constant_id_raw(parser, name.
start, parse_operator_symbol_name(&name));
19020 flush_block_exits(parser, previous_block_exits);
19022 return UP(pm_def_node_create(
19031 NTOK2PTR(
operator),
19035 NTOK2PTR(end_keyword)
19043parse_module(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19045 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19047 size_t opening_newline_index = token_newline_index(parser);
19048 parser_lex(parser);
19049 pm_token_t module_keyword = parser->previous;
19051 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));
19056 if (PM_NODE_TYPE_P(constant_path, PM_ERROR_RECOVERY_NODE)) {
19057 pop_block_exits(parser, previous_block_exits);
19060 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19063 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19066 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19067 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->previous));
19073 name = parser->previous;
19074 if (name.
type != PM_TOKEN_CONSTANT) {
19075 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19078 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)) {
19079 constant_path = UP(pm_error_recovery_node_create_unexpected(parser, constant_path));
19082 pm_parser_scope_push(parser,
true);
19083 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19086 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19087 pm_accepts_block_stack_push(parser,
true);
19088 statements = UP(parse_statements(parser, PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19089 pm_accepts_block_stack_pop(parser);
19092 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19093 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19094 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)));
19096 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19100 pm_locals_order(parser, &parser->current_scope->locals, &locals,
false);
19102 pm_parser_scope_pop(parser);
19103 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
19105 if (context_def_p(parser)) {
19106 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19109 pop_block_exits(parser, previous_block_exits);
19111 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->previous));
19119parse_parentheses(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19121 pm_node_flags_t paren_flags = 0;
19124 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19126 parser_lex(parser);
19128 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19129 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19130 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19137 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
19141 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT) && opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19142 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19145 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19146 pop_block_exits(parser, previous_block_exits);
19147 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->previous, paren_flags));
19152 context_push(parser, PM_CONTEXT_PARENS);
19153 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
19154 context_pop(parser);
19159 bool terminator_found =
false;
19161 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19162 terminator_found =
true;
19163 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19164 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
19165 terminator_found =
true;
19168 if (terminator_found) {
19170 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
19171 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19172 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
19180 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19181 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
19182 lex_state_set(parser, PM_LEX_STATE_ENDARG);
19185 parser_lex(parser);
19186 pop_block_exits(parser, previous_block_exits);
19188 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19194 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.length == 0) {
19197 multi_target = pm_multi_target_node_create(parser);
19198 pm_multi_target_node_targets_append(parser, multi_target, statement);
19201 multi_target->
lparen_loc = TOK2LOC(parser, &opening);
19202 multi_target->
rparen_loc = TOK2LOC(parser, &parser->previous);
19203 PM_NODE_START_SET_TOKEN(parser, multi_target, &opening);
19204 PM_NODE_LENGTH_SET_TOKEN(parser, multi_target, &parser->previous);
19207 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
19208 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19209 accept1(parser, PM_TOKEN_NEWLINE);
19211 result = UP(multi_target);
19214 if (context_p(parser, PM_CONTEXT_MULTI_TARGET)) {
19216 }
else if (context_p(parser, PM_CONTEXT_FOR_INDEX) && match2(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_COMMA)) {
19220 }
else if (flags & PM_PARSE_ACCEPTS_STATEMENT) {
19224 if (pm_binding_powers[parser->current.type].binary && !match1(parser, PM_TOKEN_EQUAL)) {
19225 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19227 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
19230 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19231 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
19234 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
19244 pm_statements_node_body_append(parser, statements, statement,
true);
19246 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19252 context_push(parser, PM_CONTEXT_PARENS);
19253 paren_flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
19256 pm_statements_node_body_append(parser, statements, statement,
true);
19260 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
19261 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19266 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT, PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF | PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
19267 pm_statements_node_body_append(parser, statements, node,
true);
19271 if (parser->recovering) {
19274 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->recovering =
false;
19280 if (PM_NODE_TYPE_P(node, PM_ERROR_RECOVERY_NODE))
break;
19284 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
19285 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
19286 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
19287 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19289 }
else if (!match1(parser, PM_TOKEN_EOF)) {
19292 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
19296 context_pop(parser);
19297 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19306 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
19308 pm_multi_target_node_targets_append(parser, multi_target, statement);
19310 statement = UP(multi_target);
19314 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
19315 const uint8_t *offset = parser->start + PM_NODE_END(statement);
19316 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
19317 pm_node_t *value = UP(pm_error_recovery_node_create(parser, PM_NODE_END(statement), 0));
19319 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
19322 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
19326 pop_block_exits(parser, previous_block_exits);
19327 pm_void_statements_check(parser, statements,
true);
19328 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->previous, paren_flags));
19337parse_splat(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19341 if (token_begins_expression_p(parser->current.type)) {
19342 name = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19345 return UP(pm_splat_node_create(parser, &
operator, name));
19353 pm_hash_key_static_literals_add(parser, &hash_keys, key);
19356 if (parser->previous.
type == PM_TOKEN_EQUAL_GREATER) {
19357 operator = parser->previous;
19360 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));
19361 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, NTOK2PTR(
operator), value));
19362 pm_keyword_hash_node_elements_append(parser->arena, hash, assoc);
19364 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19365 parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
19368 pm_static_literals_free(&hash_keys);
19373parse_array(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19374 pm_array_node_t *array = pm_array_node_create(parser, &parser->current);
19375 parser_lex(parser);
19377 bool parsed_bare_hash =
false;
19378 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
19379 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
19383 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19389 if (accept1(parser, PM_TOKEN_COMMA)) {
19392 if (accepted_newline) {
19393 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
19398 PM_PARSER_ERR_FORMAT(parser, PM_TOKEN_END(parser, &parser->previous), 0, PM_ERR_ARRAY_SEPARATOR, pm_token_str(parser->current.type));
19399 parser->previous.
start = parser->previous.
end;
19400 parser->previous.
type = 0;
19407 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
19411 if (accept1(parser, PM_TOKEN_USTAR)) {
19415 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
19416 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
19418 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));
19421 element = UP(pm_splat_node_create(parser, &
operator, expression));
19422 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
19423 if (parsed_bare_hash) {
19424 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
19427 element = UP(pm_keyword_hash_node_create(parser));
19430 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)) {
19431 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
19434 pm_static_literals_free(&hash_keys);
19435 parsed_bare_hash =
true;
19437 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));
19439 if (pm_symbol_node_label_p(parser, element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
19440 if (parsed_bare_hash) {
19441 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
19444 element = UP(parse_array_keyword_hash(parser, element, flags, depth));
19445 parsed_bare_hash =
true;
19449 pm_array_node_elements_append(parser->arena, array, element);
19450 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
19453 accept1(parser, PM_TOKEN_NEWLINE);
19455 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
19456 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_ARRAY_TERM, pm_token_str(parser->current.type));
19457 parser->previous.
start = parser->previous.
end;
19458 parser->previous.
type = 0;
19461 pm_array_node_close_set(parser, array, &parser->previous);
19469 parser_lex(parser);
19471 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
19473 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
19474 pm_static_literals_free(&hash_keys);
19476 accept1(parser, PM_TOKEN_NEWLINE);
19479 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
19480 pm_hash_node_closing_loc_set(parser, node, &parser->previous);
19485parse_heredoc(
pm_parser_t *parser, uint16_t depth) {
19486 assert(parser->lex_modes.current->mode == PM_LEX_HEREDOC);
19489 size_t common_whitespace = (size_t) -1;
19490 parser->lex_modes.current->as.heredoc.common_whitespace = &common_whitespace;
19492 parser_lex(parser);
19498 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19501 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19502 pm_token_t content = parse_strings_empty_content(parser->previous.
start);
19504 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19505 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19507 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->previous, &PM_STRING_EMPTY));
19510 PM_NODE_LENGTH_SET_TOKEN(parser, node, &opening);
19511 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
19518 node = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
19519 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19524 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
19527 cast->opening_loc = TOK2LOC(parser, &opening);
19528 cast->closing_loc = TOK2LOC(parser, &parser->current);
19529 cast->base.location =
cast->opening_loc;
19531 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19533 cast->base.type = PM_X_STRING_NODE;
19536 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19537 parse_heredoc_dedent_string(parser->arena, &
cast->unescaped, common_whitespace);
19541 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19547 pm_node_list_append_inline(parser->arena, &parts, part);
19549 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
19550 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19551 pm_node_list_append_inline(parser->arena, &parts, part);
19557 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19559 cast->parts = parts;
19561 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19562 pm_interpolated_xstring_node_closing_set(parser, cast, &parser->previous);
19564 cast->base.location =
cast->opening_loc;
19569 expect1_heredoc_term(parser, lex_mode.ident_start, lex_mode.ident_length);
19570 pm_interpolated_string_node_closing_set(parser, cast, &parser->previous);
19572 cast->base.location =
cast->opening_loc;
19578 if (lex_mode.indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
19580 if (lex_mode.quote == PM_HEREDOC_QUOTE_BACKTICK) {
19586 parse_heredoc_dedent(parser, nodes, common_whitespace);
19594 pm_lex_mode_t *whitespace_mode = parser->lex_modes.current;
19596 if (whitespace_mode->mode == PM_LEX_HEREDOC && whitespace_mode->as.heredoc.common_whitespace == &common_whitespace) {
19597 whitespace_mode->as.heredoc.common_whitespace = NULL;
19599 whitespace_mode = whitespace_mode->prev;
19600 }
while (whitespace_mode != NULL);
19602 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
19603 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
19610parse_begin(
pm_parser_t *parser, uint16_t depth) {
19612 size_t opening_newline_index = token_newline_index(parser);
19613 parser_lex(parser);
19615 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19618 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19621 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19622 pm_accepts_block_stack_push(parser,
true);
19623 begin_statements = parse_statements(parser, PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
19624 pm_accepts_block_stack_pop(parser);
19625 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19628 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
19629 parse_rescues(parser, opening_newline_index, &begin_keyword, node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
19630 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
19632 PM_NODE_LENGTH_SET_TOKEN(parser, node, &parser->previous);
19633 pm_begin_node_end_keyword_set(parser, node, &parser->previous);
19634 pop_block_exits(parser, previous_block_exits);
19639parse_defined(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19641 parser_lex(parser);
19647 context_push(parser, PM_CONTEXT_DEFINED);
19648 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19650 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
19651 lparen = parser->previous;
19653 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19654 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
19657 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));
19659 if (!parser->recovering) {
19660 accept1(parser, PM_TOKEN_NEWLINE);
19661 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19662 rparen = parser->previous;
19666 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19669 context_pop(parser);
19670 return pm_defined_node_create(parser, NTOK2PTR(lparen), expression, NTOK2PTR(rparen), &keyword);
19674parse_for(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19676 size_t opening_newline_index = token_newline_index(parser);
19677 parser_lex(parser);
19680 context_push(parser, PM_CONTEXT_FOR_INDEX);
19683 if (accept1(parser, PM_TOKEN_USTAR)) {
19684 index = parse_splat(parser, flags, depth);
19685 }
else if (token_begins_expression_p(parser->current.type)) {
19686 index = parse_expression(parser, PM_BINDING_POWER_INDEX, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19688 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19689 index = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &for_keyword), PM_TOKEN_LENGTH(&for_keyword)));
19693 if (match1(parser, PM_TOKEN_COMMA)) {
19694 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19696 index = parse_target(parser, index,
false,
false);
19699 context_pop(parser);
19700 pm_do_loop_stack_push(parser,
true);
19702 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19705 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));
19706 pm_do_loop_stack_pop(parser);
19709 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19710 do_keyword = parser->previous;
19712 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19713 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_FOR_DELIMITER, pm_token_str(parser->current.type));
19718 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19719 statements = parse_statements(parser, PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19722 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19723 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19725 return pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, NTOK2PTR(do_keyword), &parser->previous);
19729parse_lambda(
pm_parser_t *parser, uint16_t depth) {
19730 int previous_lambda_enclosure_nesting = parser->lambda_enclosure_nesting;
19731 parser->lambda_enclosure_nesting = parser->enclosure_nesting;
19734 size_t opening_newline_index = token_newline_index(parser);
19735 parser_lex(parser);
19737 pm_parser_scope_push(parser,
false);
19740 switch (parser->current.type) {
19741 case PM_TOKEN_PARENTHESIS_LEFT: {
19743 parser_lex(parser);
19745 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19746 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
19748 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
19751 accept1(parser, PM_TOKEN_NEWLINE);
19752 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19754 pm_block_parameters_node_closing_set(parser, block_parameters, &parser->previous);
19757 case PM_CASE_PARAMETER: {
19758 block_parameters = parse_block_parameters(parser,
false, NULL,
true,
false, (uint16_t) (depth + 1));
19762 block_parameters = NULL;
19770 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
19771 opening = parser->previous;
19773 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
19774 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_BRACES, (uint16_t) (depth + 1)));
19777 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
19783 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
19784 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
19792 pm_enclosure_frame_push(parser);
19793 expect1(parser, PM_TOKEN_KEYWORD_DO_LAMBDA, PM_ERR_LAMBDA_OPEN);
19794 opening = parser->previous;
19800 parser->lambda_enclosure_nesting = -1;
19802 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19803 body = UP(parse_statements(parser, PM_CONTEXT_LAMBDA_DO_END, (uint16_t) (depth + 1)));
19806 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
19807 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
19808 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)));
19810 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
19813 pm_enclosure_frame_pop(parser);
19817 parser->lambda_enclosure_nesting = previous_lambda_enclosure_nesting;
19818 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
19822 pm_locals_order(parser, &parser->current_scope->locals, &locals, pm_parser_scope_toplevel_p(parser));
19823 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->previous);
19825 pm_parser_scope_pop(parser);
19826 return pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->previous, parameters, body);
19830parse_regexp(
pm_parser_t *parser, uint16_t depth) {
19832 parser_lex(parser);
19834 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19839 .
type = PM_TOKEN_STRING_CONTENT,
19840 .start = parser->previous.
end,
19841 .end = parser->previous.
end
19844 parser_lex(parser);
19847 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
19853 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19860 parser_lex(parser);
19865 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19872 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19873 pm_node_flag_set(UP(node), pm_regexp_parse(parser, node, NULL, NULL));
19881 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19883 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
19884 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
19888 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19891 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
19896 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19902 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19903 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19904 pm_interpolated_regular_expression_node_append(parser->arena, interpolated, part);
19909 if (match1(parser, PM_TOKEN_EOF)) {
19910 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19911 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
19913 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19916 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19917 return UP(interpolated);
19921parse_alias(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
19922 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
19923 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
19927 parser_lex(parser);
19929 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
19930 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
19932 switch (PM_NODE_TYPE(new_name)) {
19933 case PM_BACK_REFERENCE_READ_NODE:
19934 case PM_NUMBERED_REFERENCE_READ_NODE:
19935 case PM_GLOBAL_VARIABLE_READ_NODE: {
19936 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)) {
19937 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
19938 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
19940 }
else if (!PM_NODE_TYPE_P(old_name, PM_ERROR_RECOVERY_NODE)) {
19941 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19942 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19945 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
19947 case PM_SYMBOL_NODE:
19948 case PM_INTERPOLATED_SYMBOL_NODE: {
19949 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)) {
19950 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
19951 old_name = UP(pm_error_recovery_node_create_unexpected(parser, old_name));
19956 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
19961parse_until(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19963 size_t opening_newline_index = token_newline_index(parser);
19965 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
19966 pm_do_loop_stack_push(parser,
true);
19968 parser_lex(parser);
19969 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));
19971 pm_do_loop_stack_pop(parser);
19972 context_pop(parser);
19975 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19976 do_keyword = parser->previous;
19978 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19982 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19983 pm_accepts_block_stack_push(parser,
true);
19984 statements = parse_statements(parser, PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19985 pm_accepts_block_stack_pop(parser);
19986 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19989 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19990 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
19992 return pm_until_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0);
19996parse_while(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
19998 size_t opening_newline_index = token_newline_index(parser);
20000 context_push(parser, PM_CONTEXT_LOOP_PREDICATE);
20001 pm_do_loop_stack_push(parser,
true);
20003 parser_lex(parser);
20004 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));
20006 pm_do_loop_stack_pop(parser);
20007 context_pop(parser);
20010 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
20011 do_keyword = parser->previous;
20013 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
20017 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
20018 pm_accepts_block_stack_push(parser,
true);
20019 statements = parse_statements(parser, PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
20020 pm_accepts_block_stack_pop(parser);
20021 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
20024 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
20025 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
20027 return pm_while_node_create(parser, &keyword, NTOK2PTR(do_keyword), &parser->previous, predicate, statements, 0);
20031parse_xstring(
pm_parser_t *parser, uint16_t depth) {
20033 parser_lex(parser);
20039 if (match1(parser, PM_TOKEN_STRING_END)) {
20044 .
type = PM_TOKEN_STRING_CONTENT,
20045 .start = parser->previous.
end,
20046 .end = parser->previous.
end
20049 parser_lex(parser);
20050 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->previous));
20055 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20062 parser_lex(parser);
20064 if (match1(parser, PM_TOKEN_STRING_END)) {
20065 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->current, &unescaped));
20066 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
20067 parser_lex(parser);
20073 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20075 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, NULL, &parser->previous, NULL, &unescaped));
20076 pm_node_flag_set(part, parse_unescaped_encoding(parser, parser->explicit_encoding));
20078 pm_interpolated_xstring_node_append(parser->arena, node, part);
20083 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
20087 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20088 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
20089 pm_interpolated_xstring_node_append(parser->arena, node, part);
20094 if (match1(parser, PM_TOKEN_EOF)) {
20095 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20096 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20098 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20100 pm_interpolated_xstring_node_closing_set(parser, node, &closing);
20106parse_multi_target(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t binding_power, uint16_t depth) {
20107 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
20110 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20116parse_identifier(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20118 parser_lex(parser);
20120 pm_node_t *node = parse_variable_call(parser);
20122 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
20130 if (parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1))) {
20133 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
20142 PM_NODE_LENGTH_SET_LOCATION(call, &call->
message_loc);
20144 PM_NODE_LENGTH_SET_LOCATION(call, end);
20152 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && token_begins_argument_p(parser->current.type)) ||
20153 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
20154 match1(parser, PM_TOKEN_BRACE_LEFT)
20157 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20158 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
20160 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20164 pm_node_unreference(parser, node);
20170 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
20172 if (pm_token_is_numbered_parameter(parser, PM_TOKEN_START(parser, &identifier), PM_TOKEN_LENGTH(&identifier))) {
20173 pm_node_unreference(parser, node);
20176 pm_locals_unread(&pm_parser_scope_find(parser,
cast->depth)->locals,
cast->name);
20184 return parse_multi_target(parser, node, binding_power, depth);
20188parse_uninterpolated_symbol_array(
pm_parser_t *parser) {
20190 parser_lex(parser);
20195 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20196 accept1(parser, PM_TOKEN_WORDS_SEP);
20197 if (match1(parser, PM_TOKEN_STRING_END))
break;
20201 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20203 if (current == NULL) {
20204 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20205 parser_lex(parser);
20206 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20207 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20208 parser_lex(parser);
20210 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20212 pm_token_t content = { .
type = PM_TOKEN_STRING_CONTENT, .start = parser->start +
cast->content_loc.start, .end = parser->start +
cast->content_loc.start +
cast->content_loc.length };
20213 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &
cast->unescaped));
20214 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20215 parser_lex(parser);
20218 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20219 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20222 current = UP(interpolated);
20224 assert(
false &&
"unreachable");
20229 pm_array_node_elements_append(parser->arena, array, current);
20232 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
20237 if (match1(parser, PM_TOKEN_EOF)) {
20238 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
20239 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20241 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
20243 pm_array_node_close_set(parser, array, &closing);
20249parse_interpolated_symbol_array(
pm_parser_t *parser, uint16_t depth) {
20250 parser_lex(parser);
20258 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20259 switch (parser->current.type) {
20260 case PM_TOKEN_WORDS_SEP: {
20263 parser->explicit_encoding = NULL;
20265 if (current == NULL) {
20272 pm_array_node_elements_append(parser->arena, array, current);
20276 parser_lex(parser);
20279 case PM_TOKEN_STRING_CONTENT: {
20280 if (current == NULL) {
20285 current = UP(pm_symbol_node_create_current_string(parser, NULL, &parser->current, NULL));
20286 parser_lex(parser);
20287 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20291 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20292 parser_lex(parser);
20295 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20302 .
type = PM_TOKEN_STRING_CONTENT,
20303 .start = parser->start +
cast->content_loc.start,
20304 .end = parser->start +
cast->content_loc.start +
cast->content_loc.length
20307 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, NULL, &content, NULL, &
cast->unescaped));
20308 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, NULL, &parser->previous, NULL));
20309 parser_lex(parser);
20312 pm_interpolated_symbol_node_append(parser->arena, interpolated, first_string);
20313 pm_interpolated_symbol_node_append(parser->arena, interpolated, second_string);
20315 current = UP(interpolated);
20317 assert(
false &&
"unreachable");
20322 case PM_TOKEN_EMBVAR: {
20323 bool start_location_set =
false;
20324 if (current == NULL) {
20328 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
20329 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20336 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
20337 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
20338 PM_NODE_START_SET_NODE(interpolated, current);
20339 start_location_set =
true;
20340 current = UP(interpolated);
20347 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20349 if (!start_location_set) {
20350 PM_NODE_START_SET_NODE(current, part);
20354 case PM_TOKEN_EMBEXPR_BEGIN: {
20355 bool start_location_set =
false;
20356 if (current == NULL) {
20360 current = UP(pm_interpolated_symbol_node_create(parser, NULL, NULL, NULL));
20361 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
20368 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
20369 pm_interpolated_symbol_node_append(parser->arena, interpolated, current);
20370 PM_NODE_START_SET_NODE(interpolated, current);
20371 start_location_set =
true;
20372 current = UP(interpolated);
20373 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
20377 assert(
false &&
"unreachable");
20380 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20382 if (!start_location_set) {
20383 PM_NODE_START_SET_NODE(current, part);
20388 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
20389 parser_lex(parser);
20396 pm_array_node_elements_append(parser->arena, array, current);
20400 if (match1(parser, PM_TOKEN_EOF)) {
20401 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
20402 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20404 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
20406 pm_array_node_close_set(parser, array, &closing);
20412parse_uninterpolated_string_array(
pm_parser_t *parser) {
20414 parser_lex(parser);
20419 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20420 accept1(parser, PM_TOKEN_WORDS_SEP);
20421 if (match1(parser, PM_TOKEN_STRING_END))
break;
20425 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
20426 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20429 if (current == NULL) {
20431 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20433 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20435 pm_interpolated_string_node_append(parser, interpolated, current);
20436 pm_interpolated_string_node_append(parser, interpolated,
string);
20437 current = UP(interpolated);
20439 assert(
false &&
"unreachable");
20441 parser_lex(parser);
20445 pm_array_node_elements_append(parser->arena, array, current);
20448 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
20453 if (match1(parser, PM_TOKEN_EOF)) {
20454 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
20455 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20457 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
20460 pm_array_node_close_set(parser, array, &closing);
20465parse_interpolated_string_array(
pm_parser_t *parser, uint16_t depth) {
20467 parser_lex(parser);
20472 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
20473 switch (parser->current.type) {
20474 case PM_TOKEN_WORDS_SEP: {
20477 parser->explicit_encoding = NULL;
20479 if (current == NULL) {
20486 pm_array_node_elements_append(parser->arena, array, current);
20490 parser_lex(parser);
20493 case PM_TOKEN_STRING_CONTENT: {
20494 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, NULL, &parser->current, NULL));
20495 pm_node_flag_set(
string, parse_unescaped_encoding(parser, parser->explicit_encoding));
20496 parser_lex(parser);
20498 if (current == NULL) {
20504 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20509 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20515 pm_interpolated_string_node_append(parser, interpolated, current);
20516 pm_interpolated_string_node_append(parser, interpolated,
string);
20517 current = UP(interpolated);
20519 assert(
false &&
"unreachable");
20524 case PM_TOKEN_EMBVAR: {
20525 if (current == NULL) {
20529 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
20530 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20536 pm_interpolated_string_node_append(parser, interpolated, current);
20537 current = UP(interpolated);
20544 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20548 case PM_TOKEN_EMBEXPR_BEGIN: {
20549 if (current == NULL) {
20553 current = UP(pm_interpolated_string_node_create(parser, NULL, NULL, NULL));
20554 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
20560 pm_interpolated_string_node_append(parser, interpolated, current);
20561 current = UP(interpolated);
20562 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
20566 assert(
false &&
"unreachable");
20569 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
20574 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
20575 parser_lex(parser);
20582 pm_array_node_elements_append(parser->arena, array, current);
20586 if (match1(parser, PM_TOKEN_EOF)) {
20587 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
20588 closing = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
20590 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
20593 pm_array_node_close_set(parser, array, &closing);
20598parse_jump(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20599 parser_lex(parser);
20604 if (token_begins_expression_p(parser->current.type) || match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)) {
20605 pm_binding_power_t binding_power = pm_binding_powers[parser->current.type].
left;
20607 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
20614 pm_accepts_block_stack_push(parser,
true);
20615 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, flags, (uint16_t) (depth + 1));
20616 pm_accepts_block_stack_pop(parser);
20619 if (!(flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && arguments.
arguments != NULL) {
20620 PM_PARSER_ERR_TOKEN_FORMAT(parser, &next, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(next.
type));
20629 if (parser->previous.
type == PM_TOKEN_COMMA && match1(parser, PM_TOKEN_EOF)) {
20630 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->previous, PM_ERR_EXPECT_ARGUMENT, pm_token_str(parser->current.type));
20637 if (arguments.
block != NULL) {
20638 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20639 pm_node_unreference(parser, arguments.
block);
20640 arguments.
block = NULL;
20644 switch (keyword.
type) {
20645 case PM_TOKEN_KEYWORD_BREAK: {
20647 if (!parser->partial_script) ensure_valid_jump(parser, node);
20650 case PM_TOKEN_KEYWORD_NEXT: {
20652 if (!parser->partial_script) ensure_valid_jump(parser, node);
20655 case PM_TOKEN_KEYWORD_RETURN: {
20657 ensure_valid_return(parser, node);
20661 assert(
false &&
"unreachable");
20662 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20667parse_not(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20669 parser_lex(parser);
20680 if (binding_power > PM_BINDING_POWER_NOT && !(flags & PM_PARSE_IN_ENDLESS_DEF) && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
20681 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
20682 pm_parser_err(parser, PM_TOKEN_END(parser, &parser->previous), 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
20684 accept1(parser, PM_TOKEN_NEWLINE);
20685 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
20688 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
20691 accept1(parser, PM_TOKEN_NEWLINE);
20693 if (accept2(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_TOKEN_PARENTHESIS_LEFT_GROUPING)) {
20696 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20697 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->previous, 0));
20699 arguments.
opening_loc = TOK2LOC(parser, &lparen);
20700 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));
20702 if (!parser->recovering) {
20703 accept1(parser, PM_TOKEN_NEWLINE);
20704 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20705 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
20715 uint8_t operand_flags = (flags & PM_PARSE_IN_ENDLESS_DEF)
20716 ? (uint8_t) (flags & (PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_IN_ENDLESS_DEF))
20717 : PM_PARSE_ACCEPTS_COMMAND_CALL;
20718 receiver = parse_expression(parser, PM_BINDING_POWER_NOT, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | operand_flags), PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
20721 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
20725parse_preexe(
pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
20727 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
20729 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20730 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
20734 parser_lex(parser);
20736 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
20738 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
20740 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
20741 pm_context_t context = parser->current_context->context;
20742 if ((context != PM_CONTEXT_MAIN) && (context != PM_CONTEXT_PREEXE)) {
20743 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
20746 flush_block_exits(parser, previous_block_exits);
20747 return pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
20751parse_postexe(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20752 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20753 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
20757 parser_lex(parser);
20759 if (context_def_p(parser)) {
20760 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
20763 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
20765 pm_statements_node_t *statements = parse_statements(parser, PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
20767 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
20768 return pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->previous);
20772parse_undef(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20773 if (binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
20774 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
20777 parser_lex(parser);
20778 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->previous);
20779 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20781 if (!PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20782 pm_undef_node_append(parser->arena, undef, name);
20784 while (match1(parser, PM_TOKEN_COMMA)) {
20785 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
20786 parser_lex(parser);
20788 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
20789 if (PM_NODE_TYPE_P(name, PM_ERROR_RECOVERY_NODE)) {
20793 pm_undef_node_append(parser->arena, undef, name);
20801parse_yield(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20803 parser_lex(parser);
20806 parse_arguments_list(parser, &arguments,
false, flags, (uint16_t) (depth + 1));
20811 if (arguments.
block != NULL) {
20812 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
20813 pm_node_unreference(parser, arguments.
block);
20814 arguments.
block = NULL;
20818 if (!parser->parsing_eval && !parser->partial_script) ensure_valid_yield(parser, node);
20825 pm_node_t *node = UP(pm_string_node_create_current_string(
20828 .type = PM_TOKEN_STRING_BEGIN,
20829 .start = parser->current.start,
20830 .end = parser->current.start + 1
20833 .type = PM_TOKEN_STRING_CONTENT,
20834 .start = parser->current.start + 1,
20835 .end = parser->current.end
20840 pm_node_flag_set(node, parse_unescaped_encoding(parser, parser->explicit_encoding));
20844 parser_lex(parser);
20848 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
20849 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
20856parse_constant(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20858 parser_lex(parser);
20863 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
20864 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && token_begins_argument_p(parser->current.type)) ||
20865 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
20866 match1(parser, PM_TOKEN_BRACE_LEFT)
20869 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20870 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
20873 return parse_multi_target(parser, UP(pm_constant_read_node_create(parser, &parser->previous)), binding_power, depth);
20877parse_constant_path_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint16_t depth) {
20879 parser_lex(parser);
20881 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
20882 return parse_multi_target(parser, UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->previous)), binding_power, depth);
20886parse_unary_plus(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20887 if (binding_power > PM_BINDING_POWER_UNARY) {
20888 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20890 parser_lex(parser);
20893 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->previous.
type].right, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20894 return pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20898parse_unary_minus(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20899 if (binding_power > PM_BINDING_POWER_UNARY) {
20900 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20902 parser_lex(parser);
20905 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));
20906 return pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20910parse_unary_minus_number(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20912 parser_lex(parser);
20914 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));
20916 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20917 pm_token_t exponent_operator = parser->previous;
20918 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));
20919 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20920 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20922 switch (PM_NODE_TYPE(node)) {
20923 case PM_INTEGER_NODE:
20924 case PM_FLOAT_NODE:
20925 case PM_RATIONAL_NODE:
20926 case PM_IMAGINARY_NODE:
20927 parse_negative_numeric(node);
20930 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20939parse_unary_star(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
20940 parser_lex(parser);
20945 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20946 pm_parser_err_prefix(parser, diag_id);
20947 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
20950 pm_node_t *splat = parse_splat(parser, flags, depth);
20952 if (match1(parser, PM_TOKEN_COMMA)) {
20953 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20955 return parse_target_validate(parser, splat,
true);
20960parse_super(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20962 parser_lex(parser);
20965 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
20970 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
20972 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
20975 return UP(pm_super_node_create(parser, &keyword, &arguments));
20979parse_range(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
20981 parser_lex(parser);
20983 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));
20988 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
20989 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
20992 return pm_range_node_create(parser, NULL, &
operator, right);
20996parse_bang(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
20997 if (binding_power > PM_BINDING_POWER_UNARY) {
20998 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
21001 parser_lex(parser);
21004 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));
21005 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
21006 return pm_call_node_unary_create(parser, &
operator, receiver,
"!");
21010parse_tilde(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
21011 if (binding_power > PM_BINDING_POWER_UNARY) {
21012 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
21015 parser_lex(parser);
21018 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));
21019 return pm_call_node_unary_create(parser, &
operator, receiver,
"~");
21026parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
21027 switch (parser->current.type) {
21028 case PM_TOKEN_BRACKET_LEFT_ARRAY:
21029 return UP(parse_array(parser, flags, depth));
21030 case PM_TOKEN_PARENTHESIS_LEFT_GROUPING:
21031 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES:
21032 return parse_parentheses(parser, binding_power, flags, depth);
21033 case PM_TOKEN_BRACE_LEFT_HASH:
21034 return UP(parse_hash(parser, depth));
21035 case PM_TOKEN_CHARACTER_LITERAL:
21036 return parse_char(parser, depth);
21037 case PM_TOKEN_CONSTANT:
21038 return parse_constant(parser, binding_power, flags, depth);
21039 case PM_TOKEN_UCOLON_COLON:
21040 return parse_constant_path_prefix(parser, binding_power, depth);
21041 case PM_TOKEN_UDOT_DOT:
21042 case PM_TOKEN_UDOT_DOT_DOT:
21043 return UP(parse_range(parser, flags, depth));
21044 case PM_TOKEN_FLOAT:
21045 parser_lex(parser);
21046 return UP(pm_float_node_create(parser, &parser->previous));
21047 case PM_TOKEN_FLOAT_IMAGINARY:
21048 parser_lex(parser);
21049 return UP(pm_float_node_imaginary_create(parser, &parser->previous));
21050 case PM_TOKEN_FLOAT_RATIONAL:
21051 parser_lex(parser);
21052 return UP(pm_float_node_rational_create(parser, &parser->previous));
21053 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
21054 parser_lex(parser);
21055 return UP(pm_float_node_rational_imaginary_create(parser, &parser->previous));
21056 case PM_TOKEN_IDENTIFIER:
21057 case PM_TOKEN_METHOD_NAME:
21058 return parse_identifier(parser, binding_power, flags, depth);
21059 case PM_TOKEN_HEREDOC_START:
21060 return parse_heredoc(parser, depth);
21061 case PM_TOKEN_CLASS_VARIABLE:
21062 parser_lex(parser);
21063 return parse_multi_target(parser, UP(pm_class_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
21064 case PM_TOKEN_NUMBERED_REFERENCE:
21065 parser_lex(parser);
21066 return parse_multi_target(parser, UP(pm_numbered_reference_read_node_create(parser, &parser->previous)), binding_power, depth);
21067 case PM_TOKEN_GLOBAL_VARIABLE:
21068 parser_lex(parser);
21069 return parse_multi_target(parser, UP(pm_global_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
21070 case PM_TOKEN_BACK_REFERENCE:
21071 parser_lex(parser);
21072 return parse_multi_target(parser, UP(pm_back_reference_read_node_create(parser, &parser->previous)), binding_power, depth);
21073 case PM_TOKEN_INSTANCE_VARIABLE:
21074 parser_lex(parser);
21075 return parse_multi_target(parser, UP(pm_instance_variable_read_node_create(parser, &parser->previous)), binding_power, depth);
21076 case PM_TOKEN_INTEGER: {
21077 pm_node_flags_t base = parser->integer.base;
21078 parser_lex(parser);
21079 return UP(pm_integer_node_create(parser, base, &parser->previous));
21081 case PM_TOKEN_INTEGER_IMAGINARY: {
21082 pm_node_flags_t base = parser->integer.base;
21083 parser_lex(parser);
21084 return UP(pm_integer_node_imaginary_create(parser, base, &parser->previous));
21086 case PM_TOKEN_INTEGER_RATIONAL: {
21087 pm_node_flags_t base = parser->integer.base;
21088 parser_lex(parser);
21089 return UP(pm_integer_node_rational_create(parser, base, &parser->previous));
21091 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
21092 pm_node_flags_t base = parser->integer.base;
21093 parser_lex(parser);
21094 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->previous));
21096 case PM_TOKEN_KEYWORD___ENCODING__:
21097 parser_lex(parser);
21098 return UP(pm_source_encoding_node_create(parser, &parser->previous));
21099 case PM_TOKEN_KEYWORD___FILE__:
21100 parser_lex(parser);
21101 return UP(pm_source_file_node_create(parser, &parser->previous));
21102 case PM_TOKEN_KEYWORD___LINE__:
21103 parser_lex(parser);
21104 return UP(pm_source_line_node_create(parser, &parser->previous));
21105 case PM_TOKEN_KEYWORD_ALIAS:
21106 return parse_alias(parser, binding_power, flags, depth);
21107 case PM_TOKEN_KEYWORD_CASE:
21108 return parse_case(parser, flags, depth);
21109 case PM_TOKEN_KEYWORD_BEGIN:
21110 return UP(parse_begin(parser, depth));
21111 case PM_TOKEN_KEYWORD_BEGIN_UPCASE:
21112 return UP(parse_preexe(parser, binding_power, depth));
21113 case PM_TOKEN_KEYWORD_BREAK:
21114 case PM_TOKEN_KEYWORD_NEXT:
21115 case PM_TOKEN_KEYWORD_RETURN:
21116 return parse_jump(parser, flags, depth);
21117 case PM_TOKEN_KEYWORD_SUPER:
21118 return parse_super(parser, flags, depth);
21119 case PM_TOKEN_KEYWORD_YIELD:
21120 return UP(parse_yield(parser, flags, depth));
21121 case PM_TOKEN_KEYWORD_CLASS:
21122 return parse_class(parser, flags, depth);
21123 case PM_TOKEN_KEYWORD_DEF:
21124 return parse_def(parser, flags, depth);
21125 case PM_TOKEN_KEYWORD_DEFINED:
21126 return UP(parse_defined(parser, flags, depth));
21127 case PM_TOKEN_KEYWORD_END_UPCASE:
21128 return UP(parse_postexe(parser, binding_power, flags, depth));
21129 case PM_TOKEN_KEYWORD_FALSE:
21130 parser_lex(parser);
21131 return UP(pm_false_node_create(parser, &parser->previous));
21132 case PM_TOKEN_KEYWORD_FOR:
21133 return UP(parse_for(parser, flags, depth));
21134 case PM_TOKEN_KEYWORD_IF:
21135 if (parser_end_of_line_p(parser)) {
21136 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_KEYWORD_EOL);
21139 size_t opening_newline_index = token_newline_index(parser);
21140 bool if_after_else = parser->previous.
type == PM_TOKEN_KEYWORD_ELSE;
21141 parser_lex(parser);
21143 return parse_conditional(parser, PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
21144 case PM_TOKEN_KEYWORD_UNDEF:
21145 return UP(parse_undef(parser, binding_power, flags, depth));
21146 case PM_TOKEN_KEYWORD_NOT:
21147 return parse_not(parser, binding_power, flags, depth);
21148 case PM_TOKEN_KEYWORD_UNLESS: {
21149 size_t opening_newline_index = token_newline_index(parser);
21150 parser_lex(parser);
21152 return parse_conditional(parser, PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
21154 case PM_TOKEN_KEYWORD_MODULE:
21155 return parse_module(parser, flags, depth);
21156 case PM_TOKEN_KEYWORD_NIL:
21157 parser_lex(parser);
21158 return UP(pm_nil_node_create(parser, &parser->previous));
21159 case PM_TOKEN_KEYWORD_REDO: {
21160 parser_lex(parser);
21162 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->previous));
21163 if (!parser->partial_script) ensure_valid_jump(parser, node);
21167 case PM_TOKEN_KEYWORD_RETRY: {
21168 parser_lex(parser);
21170 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->previous));
21171 ensure_valid_retry(parser, node);
21175 case PM_TOKEN_KEYWORD_SELF:
21176 parser_lex(parser);
21177 return UP(pm_self_node_create(parser, &parser->previous));
21178 case PM_TOKEN_KEYWORD_TRUE:
21179 parser_lex(parser);
21180 return UP(pm_true_node_create(parser, &parser->previous));
21181 case PM_TOKEN_KEYWORD_UNTIL:
21182 return UP(parse_until(parser, flags, depth));
21183 case PM_TOKEN_KEYWORD_WHILE:
21184 return UP(parse_while(parser, flags, depth));
21185 case PM_TOKEN_PERCENT_LOWER_I:
21186 return UP(parse_uninterpolated_symbol_array(parser));
21187 case PM_TOKEN_PERCENT_UPPER_I:
21188 return UP(parse_interpolated_symbol_array(parser, depth));
21189 case PM_TOKEN_PERCENT_LOWER_W:
21190 return UP(parse_uninterpolated_string_array(parser));
21191 case PM_TOKEN_PERCENT_UPPER_W:
21192 return UP(parse_interpolated_string_array(parser, depth));
21193 case PM_TOKEN_REGEXP_BEGIN:
21194 return parse_regexp(parser, depth);
21195 case PM_TOKEN_XSTRING_BEGIN:
21196 case PM_TOKEN_PERCENT_LOWER_X:
21197 return parse_xstring(parser, depth);
21198 case PM_TOKEN_USTAR:
21199 return parse_unary_star(parser, binding_power, flags, diag_id, depth);
21200 case PM_TOKEN_BANG:
21201 return UP(parse_bang(parser, binding_power, flags, depth));
21202 case PM_TOKEN_TILDE:
21203 return UP(parse_tilde(parser, binding_power, flags, depth));
21204 case PM_TOKEN_UMINUS:
21205 return UP(parse_unary_minus(parser, binding_power, flags, depth));
21206 case PM_TOKEN_UMINUS_NUM:
21207 return UP(parse_unary_minus_number(parser, flags, depth));
21208 case PM_TOKEN_MINUS_GREATER:
21209 return UP(parse_lambda(parser, depth));
21210 case PM_TOKEN_UPLUS:
21211 return UP(parse_unary_plus(parser, binding_power, flags, depth));
21212 case PM_TOKEN_STRING_BEGIN:
21213 return parse_strings(parser, NULL, flags & PM_PARSE_ACCEPTS_LABEL, (uint16_t) (depth + 1));
21214 case PM_TOKEN_SYMBOL_BEGIN:
21215 return parse_symbol(parser, PM_LEX_STATE_END, (uint16_t) (depth + 1));
21217 pm_context_t recoverable = context_recoverable(parser, &parser->current);
21219 if (recoverable != PM_CONTEXT_NONE) {
21220 parser->recovering =
true;
21225 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
21226 pm_parser_err_prefix(parser, diag_id);
21232 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT, pm_token_str(parser->current.type), context_human(recoverable));
21233 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
21237 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_UNEXPECTED_TOKEN_IGNORE, pm_token_str(parser->current.type));
21239 pm_parser_err_prefix(parser, diag_id);
21242 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->previous), PM_TOKEN_LENGTH(&parser->previous)));
21248parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth);
21258parse_rescue_modifier_terminator(
pm_parser_t *parser, uint8_t flags, uint16_t depth) {
21259 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
21260 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21261 parser_lex(parser);
21262 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));
21273 if (match1(parser, PM_TOKEN_COMMA) && pm_command_before_comma_p(parser, value)) {
21274 pm_parser_err_current(parser, PM_ERR_INVALID_COMMA);
21288parse_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) {
21291 uint8_t command_flags = (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT)
21292 ? (uint8_t) (flags & PM_PARSE_ACCEPTS_COMMAND_CALL)
21293 : (previous_binding_power < PM_BINDING_POWER_MATCH ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0);
21294 if (command_flags) command_flags |= PM_PARSE_ACCEPTS_COMMAND_DEF;
21296 pm_node_t *value = parse_value_expression(parser, binding_power, (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | command_flags), diag_id, (uint16_t) (depth + 1));
21301 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
21302 parse_write_value_comma_check(parser, value);
21309 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER && (pm_command_call_value_p(parser, value) || pm_block_call_p(value))) {
21310 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21311 parser_lex(parser);
21312 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));
21317 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21318 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21321 parser_lex(parser);
21326 bool statement_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21327 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21329 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21330 context_pop(parser);
21335 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21336 parse_rescue_modifier_terminator(parser, flags, depth);
21339 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21351 switch (PM_NODE_TYPE(node)) {
21352 case PM_BEGIN_NODE: {
21354 if (
cast->statements != NULL) parse_assignment_value_local(parser, (
const pm_node_t *)
cast->statements);
21357 case PM_LOCAL_VARIABLE_WRITE_NODE: {
21359 pm_locals_read(&pm_parser_scope_find(parser,
cast->depth)->locals,
cast->name);
21362 case PM_PARENTHESES_NODE: {
21364 if (
cast->body != NULL) parse_assignment_value_local(parser,
cast->body);
21367 case PM_STATEMENTS_NODE: {
21372 parse_assignment_value_local(parser, statement);
21394parse_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) {
21395 bool statement_level = (previous_binding_power == PM_BINDING_POWER_STATEMENT) || (flags & PM_PARSE_ACCEPTS_STATEMENT);
21397 bool permitted =
true;
21398 if (!statement_level && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
21403 uint8_t command_call_flag = (previous_binding_power == PM_BINDING_POWER_ASSIGNMENT)
21404 ? (uint8_t) (flags & PM_PARSE_ACCEPTS_COMMAND_CALL)
21405 : ((previous_binding_power < PM_BINDING_POWER_MODIFIER || statement_level) ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0);
21410 if (command_call_flag && binding_power != PM_BINDING_POWER_MULTI_ASSIGNMENT + 1) {
21411 command_call_flag |= PM_PARSE_ACCEPTS_COMMAND_DEF;
21414 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));
21415 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
21417 parse_assignment_value_local(parser, value);
21418 bool single_value =
true;
21420 parse_write_value_comma_check(parser, value);
21425 if (statement_level && !pm_block_call_p(value) && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
21426 single_value =
false;
21429 pm_array_node_elements_append(parser->arena, array, value);
21432 while (accept1(parser, PM_TOKEN_COMMA)) {
21433 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
21435 pm_array_node_elements_append(parser->arena, array, element);
21436 if (PM_NODE_TYPE_P(element, PM_ERROR_RECOVERY_NODE))
break;
21438 parse_assignment_value_local(parser, element);
21446 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))) {
21447 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(parser->current.type));
21448 parser_lex(parser);
21449 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));
21454 bool multiple_assignment = (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1));
21455 if ((single_value || multiple_assignment) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
21456 bool command_value = pm_command_call_value_p(parser, value) || pm_block_call_p(value);
21465 if (multiple_assignment && command_value)
return value;
21467 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
21470 parser_lex(parser);
21476 bool statement_value = multiple_assignment || command_value;
21477 uint8_t rescue_flags = (uint8_t) ((flags & PM_PARSE_ACCEPTS_DO_BLOCK) | (statement_value ? PM_PARSE_ACCEPTS_COMMAND_CALL : 0));
21479 pm_node_t *right = parse_rescue_modifier_value(parser, rescue_flags, statement_value, (uint16_t) (depth + 1));
21480 context_pop(parser);
21485 if (PM_NODE_TYPE_P(right, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(right, PM_MATCH_PREDICATE_NODE)) {
21486 parse_rescue_modifier_terminator(parser, flags, depth);
21489 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
21508parse_rescue_modifier_value(
pm_parser_t *parser, uint8_t flags,
bool statement, uint16_t depth) {
21513 if (match1(parser, PM_TOKEN_USTAR)) {
21515 parser_lex(parser);
21516 value = parse_splat(parser, flags, depth);
21523 value = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, flags | PM_PARSE_ACCEPTS_STATEMENT | PM_PARSE_ACCEPTS_COMMAND_DEF, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21524 multiple = match1(parser, PM_TOKEN_COMMA) || PM_NODE_TYPE_P(value, PM_MULTI_TARGET_NODE);
21528 pm_node_t *target = parse_targets_validate(parser, value, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21535 if (!match1(parser, PM_TOKEN_EQUAL)) {
21536 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
21541 parser_lex(parser);
21543 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));
21544 value = parse_write(parser, target, &
operator, values);
21551 if (!PM_NODE_TYPE_P(value, PM_MATCH_REQUIRED_NODE) && !PM_NODE_TYPE_P(value, PM_MATCH_PREDICATE_NODE)) {
21552 parse_rescue_modifier_terminator(parser, flags, depth);
21560 return parse_expression(parser, PM_BINDING_POWER_DEFINED, flags, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21573 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
21574 pm_node_unreference(parser, UP(call_node->
arguments));
21578 if (call_node->
block != NULL) {
21579 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
21580 pm_node_unreference(parser, UP(call_node->
block));
21581 call_node->
block = NULL;
21586pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21589 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21590 uint8_t value = escape_hexadecimal_digit(*cursor);
21593 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
21594 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
21598 pm_buffer_append_byte(unescaped, value);
21600 pm_buffer_append_string(unescaped,
"\\x", 2);
21607pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
21608 uint8_t value = (uint8_t) (*cursor -
'0');
21611 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21612 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21615 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
21616 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
21621 pm_buffer_append_byte(unescaped, value);
21627 const uint8_t *start = cursor - 1;
21630 if (cursor >= end) {
21631 pm_buffer_append_string(unescaped,
"\\u", 2);
21635 if (*cursor !=
'{') {
21636 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
21637 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21639 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
21640 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
21643 return cursor + length;
21648 while (cursor < end && *cursor ==
' ') cursor++;
21650 if (cursor >= end)
break;
21651 if (*cursor ==
'}') {
21656 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
21660 uint32_t value = escape_unicode(parser, cursor, length, error_location, 0);
21662 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
21670pm_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) {
21671 const uint8_t *end = source + length;
21672 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
21675 if (++cursor >= end) {
21676 pm_buffer_append_byte(unescaped,
'\\');
21682 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
21684 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
21685 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
21688 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
21691 pm_buffer_append_byte(unescaped,
'\\');
21695 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->encoding_changed, parser->encoding);
21696 if (next_cursor == NULL)
break;
21698 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
21699 cursor = next_cursor;
21702 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
21734 const uint8_t *source = pm_string_source(capture);
21735 size_t length = pm_string_length(capture);
21746 const uint8_t *cursor = pm_memchr(source,
'\\', length, parser->encoding_changed, parser->encoding);
21748 pm_named_capture_escape(parser, &unescaped, source, length, cursor, name_data->
shared ? NULL : &call->receiver->location);
21755 if (pm_buffer_length(&unescaped) == 0)
return;
21757 source = (
const uint8_t *) pm_buffer_value(&unescaped);
21758 length = pm_buffer_length(&unescaped);
21761 const uint8_t *start;
21762 const uint8_t *end;
21767 if (!pm_slice_is_valid_local(parser, source, source + length)) {
21768 pm_buffer_cleanup(&unescaped);
21772 if (name_data->
shared) {
21776 end = source + length;
21777 name = pm_parser_constant_id_raw(parser, start, end);
21781 start = parser->start + PM_NODE_START(call->
receiver);
21782 end = parser->start + PM_NODE_END(call->
receiver);
21784 uint8_t *memory = (uint8_t *) pm_arena_alloc(parser->arena, length, 1);
21785 memcpy(memory, source, length);
21786 name = pm_parser_constant_id_owned(parser, memory, length);
21793 if (name != 0 && pm_constant_id_set_insert(&parser->scratch_arena, names, name)) {
21796 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
21799 if (pm_local_is_keyword((
const char *) source, length)) {
21800 pm_buffer_cleanup(&unescaped);
21806 pm_parser_local_add(parser, name, start, end, 0);
21811 if (name_data->
match == NULL) {
21812 name_data->
match = pm_match_write_node_create(parser, call);
21817 pm_token_t token = { .type = 0, .start = start, .end = end };
21819 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &token_loc, name, depth == -1 ? 0 : (uint32_t) depth));
21820 pm_node_list_append_inline(parser->arena, &name_data->
match->
targets, target);
21823 pm_buffer_cleanup(&unescaped);
21840 pm_regexp_parse_named_captures(parser, pm_string_source(content), pm_string_length(content), extended_mode, parse_regular_expression_named_capture, &name_data);
21842 if (name_data.
match != NULL) {
21843 return UP(name_data.
match);
21851 context_push(parser, PM_CONTEXT_TERNARY);
21853 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21856 parser_lex(parser);
21858 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));
21860 if (parser->recovering) {
21868 pm_node_t *false_expression = UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &colon), PM_TOKEN_LENGTH(&colon)));
21870 context_pop(parser);
21871 pop_block_exits(parser, previous_block_exits);
21872 return pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21875 accept1(parser, PM_TOKEN_NEWLINE);
21876 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21879 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));
21881 context_pop(parser);
21882 pop_block_exits(parser, previous_block_exits);
21883 return pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression);
21887parse_constant_path_infix(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
21889 parser_lex(parser);
21891 switch (parser->current.type) {
21892 case PM_TOKEN_CONSTANT: {
21893 parser_lex(parser);
21897 (parser->current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21898 ((flags & PM_PARSE_ACCEPTS_COMMAND_CALL) && token_begins_argument_p(parser->current.type))
21909 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21910 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21914 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21917 return parse_multi_target(parser, path, previous_binding_power, depth);
21919 case PM_CASE_OPERATOR:
21920 case PM_CASE_KEYWORD:
21921 case PM_TOKEN_IDENTIFIER:
21922 case PM_TOKEN_METHOD_NAME: {
21923 parser_lex(parser);
21929 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
21931 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21932 return parse_multi_target(parser, UP(call), previous_binding_power, depth);
21934 case PM_TOKEN_PARENTHESIS_LEFT: {
21938 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21940 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21943 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21944 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->previous));
21949parse_match(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
21958 parser_lex(parser);
21960 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));
21963 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &
operator, argument, 0);
21968 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21975 bool interpolated =
false;
21976 size_t total_length = 0;
21980 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21981 total_length += pm_string_length(&((
pm_string_node_t *) part)->unescaped);
21983 interpolated =
true;
21988 if (!interpolated && total_length > 0) {
21989 uint8_t *memory = (uint8_t *) pm_arena_alloc(&parser->scratch_arena, total_length,
PRISM_ALIGNOF(uint8_t));
21990 uint8_t *cursor = memory;
21993 size_t length = pm_string_length(unescaped);
21995 memcpy(cursor, pm_string_source(unescaped), length);
22000 pm_string_init(&content, memory, total_length);
22001 result = parse_interpolated_regular_expression_named_captures(parser, &content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
22003 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
22014 pm_node_flag_set(UP(regexp), pm_regexp_parse(parser, regexp, parse_regular_expression_named_capture, &name_data));
22016 if (name_data.
match != NULL) {
22017 result = UP(name_data.
match);
22025parse_equal(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
22028 switch (PM_NODE_TYPE(node)) {
22029 case PM_CALL_NODE: {
22035 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22036 pm_parser_local_add_location(parser, &call_node->
message_loc, 0);
22040 case PM_CASE_WRITABLE: {
22044 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
22045 pm_parser_local_add_location(parser, &node->
location, 0);
22048 parser_lex(parser);
22049 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));
22051 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT && !(flags & PM_PARSE_ACCEPTS_STATEMENT)) {
22052 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
22055 return parse_write(parser, node, &
operator, value);
22057 case PM_SPLAT_NODE: {
22059 pm_multi_target_node_targets_append(parser, multi_target, node);
22061 parser_lex(parser);
22062 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));
22063 return parse_write(parser, UP(multi_target), &
operator, value);
22065 case PM_SOURCE_ENCODING_NODE:
22066 case PM_FALSE_NODE:
22067 case PM_SOURCE_FILE_NODE:
22068 case PM_SOURCE_LINE_NODE:
22071 case PM_TRUE_NODE: {
22074 parser_lex(parser);
22075 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
22076 return parse_unwriteable_write(parser, node, &
operator, value);
22082 parser_lex(parser);
22083 pm_parser_err_token(parser, &
operator, PM_ERR_EXPRESSION_NOT_WRITABLE);
22089parse_and_equal(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
22092 switch (PM_NODE_TYPE(node)) {
22093 case PM_BACK_REFERENCE_READ_NODE:
22094 case PM_NUMBERED_REFERENCE_READ_NODE:
22095 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
22097 case PM_GLOBAL_VARIABLE_READ_NODE: {
22098 parser_lex(parser);
22100 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22101 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &
operator, value));
22105 case PM_CLASS_VARIABLE_READ_NODE: {
22106 parser_lex(parser);
22108 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22113 case PM_CONSTANT_PATH_NODE: {
22114 parser_lex(parser);
22116 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22119 return parse_shareable_constant_write(parser, write);
22121 case PM_CONSTANT_READ_NODE: {
22122 parser_lex(parser);
22124 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22127 if (context_def_p(parser)) {
22128 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
22131 return parse_shareable_constant_write(parser, write);
22133 case PM_INSTANCE_VARIABLE_READ_NODE: {
22134 parser_lex(parser);
22136 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22141 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
22143 parser_lex(parser);
22145 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22146 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &
operator, value, name, 0));
22148 pm_node_unreference(parser, node);
22151 case PM_LOCAL_VARIABLE_READ_NODE: {
22152 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
22154 pm_node_unreference(parser, node);
22158 parser_lex(parser);
22160 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22161 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &
operator, value,
cast->name,
cast->depth));
22165 case PM_CALL_NODE: {
22171 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22172 pm_refute_numbered_parameter(parser,
cast->message_loc.start,
cast->message_loc.length);
22174 parser_lex(parser);
22176 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22177 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22184 parser_lex(parser);
22189 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22190 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22191 return UP(pm_index_and_write_node_create(parser, cast, &
operator, value));
22195 if (pm_call_node_writable_p(parser, cast)) {
22196 parse_write_name(parser, &
cast->name);
22198 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22201 parse_call_operator_write(parser, cast, &
operator);
22202 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
22203 return UP(pm_call_and_write_node_create(parser, cast, &
operator, value));
22205 case PM_MULTI_WRITE_NODE: {
22206 parser_lex(parser);
22208 pm_parser_err_token(parser, &
operator, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
22212 parser_lex(parser);
22217 pm_parser_err_token(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
22223parse_or_equal(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
22226 switch (PM_NODE_TYPE(node)) {
22227 case PM_BACK_REFERENCE_READ_NODE:
22228 case PM_NUMBERED_REFERENCE_READ_NODE:
22229 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
22231 case PM_GLOBAL_VARIABLE_READ_NODE: {
22232 parser_lex(parser);
22234 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22235 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &
operator, value));
22239 case PM_CLASS_VARIABLE_READ_NODE: {
22240 parser_lex(parser);
22242 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22247 case PM_CONSTANT_PATH_NODE: {
22248 parser_lex(parser);
22250 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22253 return parse_shareable_constant_write(parser, write);
22255 case PM_CONSTANT_READ_NODE: {
22256 parser_lex(parser);
22258 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22261 if (context_def_p(parser)) {
22262 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
22265 return parse_shareable_constant_write(parser, write);
22267 case PM_INSTANCE_VARIABLE_READ_NODE: {
22268 parser_lex(parser);
22270 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22275 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
22277 parser_lex(parser);
22279 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22280 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &
operator, value, name, 0));
22282 pm_node_unreference(parser, node);
22285 case PM_LOCAL_VARIABLE_READ_NODE: {
22286 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
22287 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
22288 pm_node_unreference(parser, node);
22292 parser_lex(parser);
22294 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22295 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &
operator, value,
cast->name,
cast->depth));
22299 case PM_CALL_NODE: {
22305 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22306 pm_refute_numbered_parameter(parser,
cast->message_loc.start,
cast->message_loc.length);
22308 parser_lex(parser);
22310 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22311 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22318 parser_lex(parser);
22323 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22324 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22325 return UP(pm_index_or_write_node_create(parser, cast, &
operator, value));
22329 if (pm_call_node_writable_p(parser, cast)) {
22330 parse_write_name(parser, &
cast->name);
22332 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22335 parse_call_operator_write(parser, cast, &
operator);
22336 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
22337 return UP(pm_call_or_write_node_create(parser, cast, &
operator, value));
22339 case PM_MULTI_WRITE_NODE: {
22340 parser_lex(parser);
22341 pm_parser_err_token(parser, &
operator, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
22345 parser_lex(parser);
22350 pm_parser_err_token(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
22356parse_operator_equal(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power, uint8_t flags, uint16_t depth) {
22359 switch (PM_NODE_TYPE(node)) {
22360 case PM_BACK_REFERENCE_READ_NODE:
22361 case PM_NUMBERED_REFERENCE_READ_NODE:
22362 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
22364 case PM_GLOBAL_VARIABLE_READ_NODE: {
22365 parser_lex(parser);
22367 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22368 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &
operator, value));
22372 case PM_CLASS_VARIABLE_READ_NODE: {
22373 parser_lex(parser);
22375 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22380 case PM_CONSTANT_PATH_NODE: {
22381 parser_lex(parser);
22383 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22386 return parse_shareable_constant_write(parser, write);
22388 case PM_CONSTANT_READ_NODE: {
22389 parser_lex(parser);
22391 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22394 if (context_def_p(parser)) {
22395 pm_parser_err_node(parser, write, PM_ERR_WRITE_TARGET_IN_METHOD);
22398 return parse_shareable_constant_write(parser, write);
22400 case PM_INSTANCE_VARIABLE_READ_NODE: {
22401 parser_lex(parser);
22403 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22408 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
22410 parser_lex(parser);
22412 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22413 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &
operator, value, name, 0));
22415 pm_node_unreference(parser, node);
22418 case PM_LOCAL_VARIABLE_READ_NODE: {
22419 if (pm_token_is_numbered_parameter(parser, PM_NODE_START(node), PM_NODE_LENGTH(node))) {
22420 PM_PARSER_ERR_FORMAT(parser, PM_NODE_START(node), PM_NODE_LENGTH(node), PM_ERR_PARAMETER_NUMBERED_RESERVED, parser->start + PM_NODE_START(node));
22421 pm_node_unreference(parser, node);
22425 parser_lex(parser);
22427 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22428 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &
operator, value,
cast->name,
cast->depth));
22432 case PM_CALL_NODE: {
22433 parser_lex(parser);
22439 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
22440 pm_refute_numbered_parameter(parser,
cast->message_loc.start,
cast->message_loc.length);
22442 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22443 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &
operator, value, constant_id, 0));
22451 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
22452 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22453 return UP(pm_index_operator_write_node_create(parser, cast, &
operator, value));
22457 if (pm_call_node_writable_p(parser, cast)) {
22458 parse_write_name(parser, &
cast->name);
22460 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
22463 parse_call_operator_write(parser, cast, &
operator);
22464 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, flags, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22465 return UP(pm_call_operator_write_node_create(parser, cast, &
operator, value));
22467 case PM_MULTI_WRITE_NODE: {
22468 parser_lex(parser);
22469 pm_parser_err_token(parser, &
operator, PM_ERR_OPERATOR_MULTI_ASSIGN);
22473 parser_lex(parser);
22478 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, pm_token_str(parser->current.type));
22484parse_call(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
22486 parser_lex(parser);
22491 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
22492 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
22493 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
22496 switch (PM_NODE_TYPE(node)) {
22497 case PM_RESCUE_MODIFIER_NODE: {
22499 if (PM_NODE_TYPE_P(
cast->rescue_expression, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(
cast->rescue_expression, PM_MATCH_REQUIRED_NODE)) {
22500 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22504 case PM_AND_NODE: {
22506 if (PM_NODE_TYPE_P(
cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(
cast->right, PM_MATCH_REQUIRED_NODE)) {
22507 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22513 if (PM_NODE_TYPE_P(
cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(
cast->right, PM_MATCH_REQUIRED_NODE)) {
22514 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22524 switch (parser->current.type) {
22525 case PM_CASE_OPERATOR:
22526 case PM_CASE_KEYWORD:
22527 case PM_TOKEN_CONSTANT:
22528 case PM_TOKEN_IDENTIFIER:
22529 case PM_TOKEN_METHOD_NAME: {
22530 parser_lex(parser);
22531 message = parser->previous;
22535 PM_PARSER_ERR_TOKEN_FORMAT(parser, &parser->current, PM_ERR_EXPECT_MESSAGE, pm_token_str(parser->current.type));
22536 message = (
pm_token_t) { .
type = 0, .start = parser->previous.
end, .end = parser->previous.
end };
22540 parse_arguments_list(parser, &arguments,
true, flags, (uint16_t) (depth + 1));
22541 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
22544 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
22547 match1(parser, PM_TOKEN_COMMA)
22549 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22556parse_aref(
pm_parser_t *parser,
pm_node_t *node, pm_binding_power_t previous_binding_power, uint8_t flags, uint16_t depth) {
22557 parser_lex(parser);
22560 arguments.
opening_loc = TOK2LOC(parser, &parser->previous);
22562 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
22563 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint8_t) (flags & ~PM_PARSE_ACCEPTS_DO_BLOCK), (uint16_t) (depth + 1));
22564 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
22567 arguments.
closing_loc = TOK2LOC(parser, &parser->previous);
22571 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
22572 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
22573 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
22580 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
22581 block = parse_block(parser, (uint16_t) (depth + 1));
22582 pm_arguments_validate_block(parser, &arguments, block);
22583 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
22584 block = parse_block(parser, (uint16_t) (depth + 1));
22587 if (block != NULL) {
22588 if (arguments.
block != NULL) {
22589 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
22591 arguments.
arguments = pm_arguments_node_create(parser);
22593 pm_arguments_node_arguments_append(parser->arena, arguments.
arguments, arguments.
block);
22596 arguments.
block = UP(block);
22599 return UP(pm_call_node_aref_create(parser, node, &arguments));
22603parse_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) {
22606 switch (token.type) {
22607 case PM_TOKEN_EQUAL:
22608 return parse_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22609 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL:
22610 return parse_and_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22611 case PM_TOKEN_PIPE_PIPE_EQUAL:
22612 return parse_or_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22613 case PM_TOKEN_AMPERSAND_EQUAL:
22614 case PM_TOKEN_CARET_EQUAL:
22615 case PM_TOKEN_GREATER_GREATER_EQUAL:
22616 case PM_TOKEN_LESS_LESS_EQUAL:
22617 case PM_TOKEN_MINUS_EQUAL:
22618 case PM_TOKEN_PERCENT_EQUAL:
22619 case PM_TOKEN_PIPE_EQUAL:
22620 case PM_TOKEN_PLUS_EQUAL:
22621 case PM_TOKEN_SLASH_EQUAL:
22622 case PM_TOKEN_STAR_EQUAL:
22623 case PM_TOKEN_STAR_STAR_EQUAL:
22624 return parse_operator_equal(parser, node, previous_binding_power, binding_power, flags, depth);
22625 case PM_TOKEN_AMPERSAND_AMPERSAND:
22626 case PM_TOKEN_KEYWORD_AND: {
22627 parser_lex(parser);
22629 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));
22630 return UP(pm_and_node_create(parser, node, &token, right));
22632 case PM_TOKEN_KEYWORD_OR:
22633 case PM_TOKEN_PIPE_PIPE: {
22634 parser_lex(parser);
22636 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));
22637 return UP(pm_or_node_create(parser, node, &token, right));
22639 case PM_TOKEN_EQUAL_TILDE:
22640 return parse_match(parser, node, binding_power, flags, depth);
22641 case PM_TOKEN_UAMPERSAND:
22642 case PM_TOKEN_USTAR:
22643 case PM_TOKEN_USTAR_STAR:
22646 case PM_TOKEN_BANG_EQUAL:
22647 case PM_TOKEN_BANG_TILDE:
22648 case PM_TOKEN_EQUAL_EQUAL:
22649 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
22650 case PM_TOKEN_LESS_EQUAL_GREATER:
22651 case PM_TOKEN_CARET:
22652 case PM_TOKEN_PIPE:
22653 case PM_TOKEN_AMPERSAND:
22654 case PM_TOKEN_GREATER_GREATER:
22655 case PM_TOKEN_LESS_LESS:
22656 case PM_TOKEN_MINUS:
22657 case PM_TOKEN_PLUS:
22658 case PM_TOKEN_PERCENT:
22659 case PM_TOKEN_SLASH:
22660 case PM_TOKEN_STAR:
22661 case PM_TOKEN_STAR_STAR: {
22662 parser_lex(parser);
22664 switch (PM_NODE_TYPE(node)) {
22665 case PM_RESCUE_MODIFIER_NODE: {
22667 if (PM_NODE_TYPE_P(
cast->rescue_expression, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(
cast->rescue_expression, PM_MATCH_REQUIRED_NODE)) {
22668 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22672 case PM_AND_NODE: {
22674 if (PM_NODE_TYPE_P(
cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(
cast->right, PM_MATCH_REQUIRED_NODE)) {
22675 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22681 if (PM_NODE_TYPE_P(
cast->right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(
cast->right, PM_MATCH_REQUIRED_NODE)) {
22682 PM_PARSER_ERR_TOKEN_FORMAT(parser, &
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT, pm_token_str(
operator.
type));
22690 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));
22691 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
22693 case PM_TOKEN_GREATER:
22694 case PM_TOKEN_GREATER_EQUAL:
22695 case PM_TOKEN_LESS:
22696 case PM_TOKEN_LESS_EQUAL: {
22697 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
22698 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, &parser->current, PM_WARN_COMPARISON_AFTER_COMPARISON);
22701 parser_lex(parser);
22702 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));
22703 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
22705 case PM_TOKEN_AMPERSAND_DOT:
22707 return parse_call(parser, node, previous_binding_power, flags, depth);
22708 case PM_TOKEN_DOT_DOT:
22709 case PM_TOKEN_DOT_DOT_DOT: {
22710 parser_lex(parser);
22713 if (token_begins_expression_p(parser->current.type)) {
22714 right = parse_expression(parser, binding_power, flags & PM_PARSE_ACCEPTS_DO_BLOCK, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
22717 return UP(pm_range_node_create(parser, node, &token, right));
22719 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
22721 parser_lex(parser);
22723 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));
22724 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
22726 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
22728 parser_lex(parser);
22730 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));
22731 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
22733 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
22734 parser_lex(parser);
22736 pm_statements_node_body_append(parser, statements, node,
true);
22738 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));
22739 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));
22741 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
22742 parser_lex(parser);
22744 pm_statements_node_body_append(parser, statements, node,
true);
22746 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));
22747 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));
22749 case PM_TOKEN_QUESTION_MARK:
22750 return UP(parse_ternary(parser, node, flags, depth));
22751 case PM_TOKEN_COLON_COLON:
22752 return parse_constant_path_infix(parser, node, previous_binding_power, flags, depth);
22753 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
22754 context_push(parser, PM_CONTEXT_RESCUE_MODIFIER);
22755 parser_lex(parser);
22756 accept1(parser, PM_TOKEN_NEWLINE);
22758 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));
22759 context_pop(parser);
22761 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
22763 case PM_TOKEN_BRACKET_LEFT:
22764 return parse_aref(parser, node, previous_binding_power, flags, depth);
22765 case PM_TOKEN_KEYWORD_IN: {
22766 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22767 parser->pattern_matching_newlines =
true;
22770 parser->command_start =
false;
22771 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22772 parser_lex(parser);
22775 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));
22777 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22779 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
22781 case PM_TOKEN_EQUAL_GREATER: {
22782 bool previous_pattern_matching_newlines = parser->pattern_matching_newlines;
22783 parser->pattern_matching_newlines =
true;
22786 parser->command_start =
false;
22787 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
22788 parser_lex(parser);
22791 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));
22793 parser->pattern_matching_newlines = previous_pattern_matching_newlines;
22795 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
22798 assert(
false &&
"unreachable");
22803#undef PM_PARSE_PATTERN_SINGLE
22804#undef PM_PARSE_PATTERN_TOP
22805#undef PM_PARSE_PATTERN_MULTI
22821 pm_binding_power_t left = pm_binding_powers[parser->current.type].
left;
22823 switch (PM_NODE_TYPE(node)) {
22824 case PM_MULTI_WRITE_NODE:
22825 case PM_RETURN_NODE:
22826 case PM_BREAK_NODE:
22828 return left > PM_BINDING_POWER_MODIFIER;
22829 case PM_CLASS_VARIABLE_WRITE_NODE:
22830 case PM_CONSTANT_PATH_WRITE_NODE:
22831 case PM_CONSTANT_WRITE_NODE:
22832 case PM_GLOBAL_VARIABLE_WRITE_NODE:
22833 case PM_INSTANCE_VARIABLE_WRITE_NODE:
22834 case PM_LOCAL_VARIABLE_WRITE_NODE:
22835 return PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && left > PM_BINDING_POWER_MODIFIER;
22836 case PM_CALL_NODE: {
22839 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY)) {
22840 return left > PM_BINDING_POWER_MODIFIER;
22846 if (pm_command_call_value_p(parser, node)) {
22847 return left > PM_BINDING_POWER_COMPOSITION;
22853 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22855 case PM_SUPER_NODE:
22856 case PM_YIELD_NODE:
22859 if (pm_command_call_value_p(parser, node)) {
22860 return left > PM_BINDING_POWER_COMPOSITION;
22865 return left > PM_BINDING_POWER_COMPOSITION && left < PM_BINDING_POWER_CALL && pm_block_call_p(node);
22870 return left > PM_BINDING_POWER_MODIFIER && pm_command_call_value_p(parser, node);
22871 case PM_RESCUE_MODIFIER_NODE:
22875 if (left > PM_BINDING_POWER_MODIFIER) {
22878 return PM_NODE_TYPE_P(rescue_expression, PM_MATCH_REQUIRED_NODE) || PM_NODE_TYPE_P(rescue_expression, PM_MATCH_PREDICATE_NODE);
22895parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power, uint8_t flags, pm_diagnostic_id_t diag_id, uint16_t depth) {
22897 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
22898 return UP(pm_error_recovery_node_create(parser, PM_TOKEN_START(parser, &parser->current), PM_TOKEN_LENGTH(&parser->current)));
22901 pm_node_t *node = parse_expression_prefix(parser, binding_power, flags, diag_id, depth);
22906 switch (PM_NODE_TYPE(node)) {
22907 case PM_ERROR_RECOVERY_NODE:
22909 case PM_PRE_EXECUTION_NODE:
22911 case PM_POST_EXECUTION_NODE:
22912 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
22913 case PM_ALIAS_METHOD_NODE:
22914 case PM_UNDEF_NODE:
22915 if (pm_binding_powers[parser->current.type].left > PM_BINDING_POWER_MODIFIER) {
22920 case PM_SUPER_NODE:
22921 case PM_YIELD_NODE:
22923 if (parse_expression_terminator(parser, node)) {
22927 case PM_SYMBOL_NODE:
22928 if (pm_symbol_node_label_p(parser, node)) {
22939 pm_token_type_t current_token_type;
22942 current_token_type = parser->current.type,
22943 current_binding_powers = pm_binding_powers[current_token_type],
22944 binding_power <= current_binding_powers.
left &&
22945 current_binding_powers.
binary
22947 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, flags, (uint16_t) (depth + 1));
22948 if (parse_expression_terminator(parser, node))
return node;
22952 if (current_binding_powers.
nonassoc) {
22960 if (next_binding_powers.
nonassoc && next_binding_powers.
left == current_binding_powers.
left) {
22961 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));
22972 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
22973 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
22974 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));
22978 if (PM_BINDING_POWER_TERM <= next_binding_powers.
left) {
22981 }
else if (current_binding_powers.
left <= next_binding_powers.
left) {
22986 if (flags & PM_PARSE_ACCEPTS_COMMAND_CALL) {
22995 switch (node->
type) {
22996 case PM_CALL_NODE: {
23001 cast->call_operator_loc.length == 0 &&
23002 cast->message_loc.length > 0 &&
23003 parser->start[
cast->message_loc.start] ==
'[' &&
23004 parser->start[
cast->message_loc.start +
cast->message_loc.length - 1] ==
']'
23008 cast->call_operator_loc.length > 0 &&
23009 cast->arguments == NULL &&
23010 cast->block == NULL &&
23011 cast->opening_loc.length == 0
23015 cast->call_operator_loc.length > 0 &&
23016 cast->opening_loc.length > 0
23020 cast->block != NULL && PM_NODE_TYPE_P(
cast->block, PM_BLOCK_NODE)
23023 flags &= (uint8_t) ~(PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF);
23028 case PM_CONSTANT_PATH_NODE:
23031 flags &= (uint8_t) ~(PM_PARSE_ACCEPTS_COMMAND_CALL | PM_PARSE_ACCEPTS_COMMAND_DEF);
23036 if (context_terminator(parser->current_context->context, &parser->current)) {
23039 !next_binding_powers.
binary ||
23040 binding_power > next_binding_powers.
left ||
23041 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((
pm_call_node_t *) node))
23057 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
23058 if (statements == NULL) {
23059 statements = pm_statements_node_create(parser);
23063 pm_arguments_node_arguments_append(
23066 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
23069 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
23072 pm_parser_constant_id_constant(parser,
"print", 5)
23076 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
23077 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
23078 if (statements == NULL) {
23079 statements = pm_statements_node_create(parser);
23083 pm_arguments_node_arguments_append(
23086 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
23089 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
23090 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
23094 pm_parser_constant_id_constant(parser,
"$F", 2),
23098 pm_statements_node_body_prepend(parser->arena, statements, UP(write));
23102 pm_arguments_node_arguments_append(
23105 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
23108 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
23110 pm_keyword_hash_node_elements_append(parser->arena, keywords, UP(pm_assoc_node_create(
23112 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
23114 UP(pm_true_node_synthesized_create(parser))
23117 pm_arguments_node_arguments_append(parser->arena, arguments, UP(keywords));
23118 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
23122 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
23124 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
23128 statements = wrapped_statements;
23142 if (parser->current_scope == NULL) {
23143 pm_parser_scope_push(parser,
true);
23147 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
23149 parser_lex(parser);
23152 if (statements != NULL && !parser->parsing_eval) {
23156 assert(statements->
body.
size > 0);
23157 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
23161 pm_locals_order(parser, &parser->current_scope->locals, &locals,
true);
23162 pm_parser_scope_pop(parser);
23167 statements = wrap_statements(parser, statements);
23169 flush_block_exits(parser, previous_block_exits);
23175 if (statements == NULL) {
23176 statements = pm_statements_node_create(parser);
23180 return UP(pm_program_node_create(parser, &locals, statements));
23197pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
23198 size_t little_length = strlen(little);
23200 for (
const char *max = big + big_length - little_length; big <= max; big++) {
23201 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
23208#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
23216pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
23217 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
23218 pm_parser_warn(parser, U32(start - parser->start), U32(length), PM_WARN_SHEBANG_CARRIAGE_RETURN);
23229 const char *switches = pm_strnstr(engine,
" -", length);
23230 if (switches == NULL)
return;
23233 options->shebang_callback(
23235 (
const uint8_t *) (switches + 1),
23236 length - ((
size_t) (switches - engine)) - 1,
23237 options->shebang_callback_data
23240 size_t encoding_length;
23241 if ((encoding_length = pm_string_length(&next_options.encoding)) > 0) {
23242 const uint8_t *encoding_source = pm_string_source(&next_options.encoding);
23243 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23246 parser->command_line = next_options.command_line;
23247 parser->frozen_string_literal = next_options.frozen_string_literal;
23256#ifndef PM_CONSTANT_POOL_MIN_CAPACITY
23257#define PM_CONSTANT_POOL_MIN_CAPACITY 4
23265 assert(arena != NULL);
23266 assert(source != NULL);
23270 .metadata_arena = { 0 },
23272 .lex_state = PM_LEX_STATE_BEG,
23273 .enclosure_nesting = 0,
23274 .lambda_enclosure_nesting = -1,
23275 .brace_nesting = 0,
23276 .do_loop_stack = 0,
23277 .accepts_block_stack = 0,
23279 .current = &parser->lex_modes.base,
23280 .base = { .mode = PM_LEX_DEFAULT },
23283 .end = source + size,
23284 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
23285 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
23286 .next_start = NULL,
23287 .heredoc_end = NULL,
23289 .comment_list = { 0 },
23290 .magic_comment_list = { 0 },
23291 .warning_list = { 0 },
23292 .error_list = { 0 },
23293 .current_scope = NULL,
23294 .current_context = NULL,
23295 .encoding = PM_ENCODING_UTF_8_ENTRY,
23296 .encoding_changed_callback = NULL,
23297 .encoding_comment_start = source,
23298 .lex_callback = { 0 },
23299 .filepath = PM_STRING_EMPTY,
23300 .constant_pool = { 0 },
23301 .line_offsets = { 0 },
23303 .current_string = PM_STRING_EMPTY,
23305 .explicit_encoding = NULL,
23307 .parsing_eval =
false,
23308 .partial_script =
false,
23309 .attach_comments =
false,
23310 .command_start =
true,
23311 .recovering =
false,
23312 .continuable =
true,
23313 .encoding_locked =
false,
23314 .encoding_changed =
false,
23315 .pattern_matching_newlines =
false,
23316 .in_keyword_arg =
false,
23317 .current_block_exits = NULL,
23318 .semantic_token_seen =
false,
23320 .warn_mismatched_indentation =
true
23328 if (size <= SIZE_MAX / 4) pm_arena_reserve(arena, size * 4);
23329 if (size <= SIZE_MAX / 5 * 4) pm_arena_reserve(&parser->metadata_arena, size + size / 4);
23336 uint32_t constant_size = ((uint32_t) size) / 120;
23337 if (constant_size < PM_CONSTANT_POOL_MIN_CAPACITY) constant_size = PM_CONSTANT_POOL_MIN_CAPACITY;
23338 pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size);
23343 size_t newline_size = size / 22;
23344 pm_line_offset_list_init(&parser->metadata_arena, &parser->line_offsets, newline_size < 4 ? 4 : newline_size);
23347 if (options != NULL) {
23349 if (pm_string_length(&options->filepath) > 0) {
23350 parser->filepath = options->filepath;
23354 parser->start_line = options->line;
23357 size_t encoding_length = pm_string_length(&options->encoding);
23358 if (encoding_length > 0) {
23359 const uint8_t *encoding_source = pm_string_source(&options->encoding);
23360 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
23364 parser->encoding_locked = options->encoding_locked;
23367 parser->frozen_string_literal = options->frozen_string_literal;
23370 parser->command_line = options->command_line;
23373 parser->version = options->version;
23376 parser->partial_script = options->partial_script;
23379 parser->attach_comments = options->attach_comments;
23382 parser->parsing_eval = options->scopes_count > 0;
23383 if (parser->parsing_eval) parser->warn_mismatched_indentation =
false;
23385 for (
size_t scope_index = 0; scope_index < options->scopes_count; scope_index++) {
23387 pm_parser_scope_push(parser, scope_index == 0);
23391 parser->current_scope->parameters = ((pm_scope_parameters_t) scope->forwarding) | PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED;
23393 for (
size_t local_index = 0; local_index < scope->locals_count; local_index++) {
23394 const pm_string_t *local = pm_options_scope_local(scope, local_index);
23396 const uint8_t *source = pm_string_source(local);
23397 size_t length = pm_string_length(local);
23399 uint8_t *allocated = (uint8_t *) pm_arena_alloc(&parser->metadata_arena, length, 1);
23400 memcpy(allocated, source, length);
23401 pm_parser_local_add_owned(parser, allocated, length);
23408 if (parser->version == PM_OPTIONS_VERSION_UNSET) {
23409 parser->version = PM_OPTIONS_VERSION_LATEST;
23412 pm_accepts_block_stack_push(parser,
true);
23415 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
23416 parser->current.end += 3;
23417 parser->encoding_comment_start += 3;
23419 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
23420 parser->encoding = PM_ENCODING_UTF_8_ENTRY;
23421 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
23428 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
23445 const uint8_t *newline = next_newline(parser->current.end, parser->end - parser->current.end);
23446 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - parser->current.end);
23448 if (length > 2 && parser->current.end[0] ==
'#' && parser->current.end[1] ==
'!') {
23449 const char *engine;
23451 if ((engine = pm_strnstr((
const char *) parser->start,
"ruby", length)) != NULL) {
23452 if (newline != NULL) {
23453 parser->encoding_comment_start = newline + 1;
23455 if (options == NULL || options->main_script) {
23456 pm_parser_warn_shebang_carriage_return(parser, parser->start, length + 1);
23460 if (options != NULL && options->main_script && options->shebang_callback != NULL) {
23461 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->start)));
23464 search_shebang =
false;
23465 }
else if (options != NULL && options->main_script && !parser->parsing_eval) {
23466 search_shebang =
true;
23472 if (search_shebang) {
23475 bool found_shebang =
false;
23479 const uint8_t *cursor = parser->start;
23483 const uint8_t *newline = next_newline(cursor, parser->end - cursor);
23485 while (newline != NULL) {
23486 pm_line_offset_list_append(&parser->metadata_arena, &parser->line_offsets, U32(newline - parser->start + 1));
23488 cursor = newline + 1;
23489 newline = next_newline(cursor, parser->end - cursor);
23491 size_t length = (size_t) ((newline != NULL ? newline : parser->end) - cursor);
23492 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
23493 const char *engine;
23494 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
23495 found_shebang =
true;
23497 if (newline != NULL) {
23498 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
23499 parser->encoding_comment_start = newline + 1;
23502 if (options != NULL && options->shebang_callback != NULL) {
23503 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
23511 if (found_shebang) {
23512 parser->previous = (
pm_token_t) { .
type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23513 parser->current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
23515 pm_parser_err(parser, 0, 0, PM_ERR_SCRIPT_NOT_FOUND);
23516 pm_line_offset_list_clear(&parser->line_offsets);
23523 parser->encoding_comment_start += pm_strspn_inline_whitespace(parser->encoding_comment_start, parser->end - parser->encoding_comment_start);
23536 if (parser == NULL) PRISM_OOM();
23538 pm_parser_init(arena, parser, source, size, options);
23547 pm_arena_cleanup(&parser->metadata_arena);
23548 pm_arena_cleanup(&parser->scratch_arena);
23556 pm_parser_cleanup(parser);
23566pm_parse_err_is_fatal(pm_diagnostic_id_t diag_id) {
23568 case PM_ERR_ARRAY_EXPRESSION_AFTER_STAR:
23569 case PM_ERR_BEGIN_UPCASE_BRACE:
23570 case PM_ERR_CLASS_VARIABLE_BARE:
23571 case PM_ERR_END_UPCASE_BRACE:
23572 case PM_ERR_ESCAPE_INVALID_HEXADECIMAL:
23573 case PM_ERR_ESCAPE_INVALID_UNICODE_LIST:
23574 case PM_ERR_ESCAPE_INVALID_UNICODE_SHORT:
23575 case PM_ERR_EXPRESSION_NOT_WRITABLE:
23576 case PM_ERR_EXPRESSION_NOT_WRITABLE_SELF:
23577 case PM_ERR_FLOAT_PARSE:
23578 case PM_ERR_GLOBAL_VARIABLE_BARE:
23579 case PM_ERR_HASH_KEY:
23580 case PM_ERR_HEREDOC_IDENTIFIER:
23581 case PM_ERR_INSTANCE_VARIABLE_BARE:
23582 case PM_ERR_INVALID_BLOCK_EXIT:
23583 case PM_ERR_INVALID_ENCODING_MAGIC_COMMENT:
23584 case PM_ERR_INVALID_FLOAT_EXPONENT:
23585 case PM_ERR_INVALID_NUMBER_BINARY:
23586 case PM_ERR_INVALID_NUMBER_DECIMAL:
23587 case PM_ERR_INVALID_NUMBER_HEXADECIMAL:
23588 case PM_ERR_INVALID_NUMBER_OCTAL:
23589 case PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING:
23590 case PM_ERR_NO_LOCAL_VARIABLE:
23591 case PM_ERR_PARAMETER_ORDER:
23592 case PM_ERR_STATEMENT_UNDEF:
23593 case PM_ERR_VOID_EXPRESSION:
23636 if (parser->error_list.size == 0) {
23637 parser->continuable =
false;
23641 if (!parser->continuable)
return;
23643 size_t source_length = (size_t) (parser->end - parser->start);
23646 bool has_non_stray_error =
false;
23648 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)) {
23649 has_non_stray_error =
true;
23657 size_t non_stray_min_start = SIZE_MAX;
23660 size_t error_start = (size_t) error->location.start;
23661 size_t error_end = error_start + (size_t) error->location.length;
23662 bool at_eof = error_end >= source_length;
23665 if (pm_parse_err_is_fatal(error->diag_id) && !at_eof) {
23666 parser->continuable =
false;
23671 if (error->diag_id != PM_ERR_UNEXPECTED_TOKEN_IGNORE &&
23672 error->diag_id != PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT) {
23673 if (error_start < non_stray_min_start) non_stray_min_start = error_start;
23682 if (non_stray_min_start < error_start)
continue;
23689 if (at_eof && error_start > 0) {
23691 if (error->location.length == 1) {
23692 const uint8_t *
byte = parser->start + error_start;
23693 if (*
byte ==
')' || *
byte ==
']' || *
byte ==
'}') {
23694 parser->continuable =
false;
23704 if (has_non_stray_error)
continue;
23711 if (error->location.length == 1) {
23712 const uint8_t *
byte = parser->start + error_start;
23713 if (*
byte ==
'=' && (error_start == 0 || *(
byte - 1) ==
'\n'))
continue;
23717 parser->continuable =
false;
23727 pm_node_t *node = parse_program(parser);
23728 pm_parse_continuable(parser);
23729 if (parser->attach_comments) pm_comments_attach(parser, node);
23730 pm_arena_cleanup(&parser->scratch_arena);
23742 bool eof = pm_source_stream_read(source);
23747 while (!eof && tmp->error_list.size > 0) {
23748 eof = pm_source_stream_read(source);
23751 pm_arena_cleanup(arena);
23753 tmp =
pm_parser_new(arena, pm_source_source(source), pm_source_length(source), options);
23761#undef PM_CASE_KEYWORD
23762#undef PM_CASE_OPERATOR
23763#undef PM_CASE_WRITABLE
23764#undef PM_STRING_EMPTY
23769#ifndef PRISM_EXCLUDE_SERIALIZATION
23773 pm_buffer_append_string(buffer,
"PRISM", 5);
23777 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
23785 pm_serialize_header(buffer);
23786 pm_serialize_content(parser, node, buffer);
23787 pm_buffer_append_byte(buffer,
'\0');
23795pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23797 pm_options_read(&options, data);
23801 pm_parser_init(&arena, &parser, source, size, &options);
23805 pm_serialize_header(buffer);
23806 pm_serialize_content(&parser, node, buffer);
23807 pm_buffer_append_byte(buffer,
'\0');
23809 pm_parser_cleanup(&parser);
23810 pm_arena_cleanup(&arena);
23811 pm_options_cleanup(&options);
23823 pm_options_read(&options, data);
23825 pm_node_t *node = pm_parse_stream(&parser, &arena, source, &options);
23826 pm_serialize_header(buffer);
23827 pm_serialize_content(parser, node, buffer);
23828 pm_buffer_append_byte(buffer,
'\0');
23831 pm_arena_cleanup(&arena);
23832 pm_options_cleanup(&options);
23846 pm_options_read(&options, data);
23850 pm_parser_init(&arena, &parser, source, size, &options);
23854 int8_t result = -1;
23855 if (parser.error_list.size > 0) {
23856 const char *encoding_name = parser.encoding->name;
23857 pm_buffer_append_string(buffer, encoding_name, strlen(encoding_name));
23858 pm_buffer_append_byte(buffer,
'\0');
23860 result = (int8_t) pm_errors_format(&parser, buffer, format_type);
23863 pm_parser_cleanup(&parser);
23864 pm_arena_cleanup(&arena);
23865 pm_options_cleanup(&options);
23874pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
23876 pm_options_read(&options, data);
23880 pm_parser_init(&arena, &parser, source, size, &options);
23883 pm_serialize_header(buffer);
23884 pm_serialize_encoding(parser.encoding, buffer);
23885 pm_buffer_append_varsint(buffer, parser.start_line);
23886 pm_buffer_append_uint64(buffer, pm_parser_checksum(&parser));
23887 pm_serialize_line_offset_list(&parser.line_offsets, buffer);
23888 pm_serialize_comment_list(&parser.comment_list, buffer);
23890 pm_parser_cleanup(&parser);
23891 pm_arena_cleanup(&arena);
23892 pm_options_cleanup(&options);
#define PRISM_ALIGNOF
Get the alignment requirement of a type.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
A header file that defines macros to exclude certain features of the prism library.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define xmalloc
Old name of ruby_xmalloc.
int len
Length of the buffer.
#define PRISM_INLINE
Old Visual Studio versions do not support the inline keyword, so we need to define it to be __inline.
VALUE type(ANYARGS)
ANYARGS-ed function type.
T * cast(pm_node_t *node) noexcept
Cast the given node, which must not be null and must be of the given struct, to that struct.
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.
std::string_view constant(const pm_parser_t *parser PRISM_LIFETIMEBOUND, pm_constant_id_t constant_id) noexcept
The name of the constant with the given id, which must not be zero.
pm_visit_result_t
The value returned by a visitor callback, which determines where the walk goes next.
@ PM_VISIT_SKIP
Continue the walk without visiting this node's children.
@ PM_VISIT_DESCEND
Continue the walk by visiting this node's children.
#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_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_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.
struct pm_node_list conditions
CaseNode::conditions.
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.
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.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
A Ruby keyword, along with the lex state that it transitions to and the token types that it produces.
int32_t line
The line number.
uint32_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
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 * block
ParametersNode::block.
PM_NODE_ALIGNAS struct pm_node * rest
ParametersNode::rest.
PM_NODE_ALIGNAS struct pm_node * keyword_rest
ParametersNode::keyword_rest.
State for processing named capture groups found during regexp parsing.
bool shared
Whether the content being parsed points into the original source.
pm_constant_id_set_t names
The set of capture names found so far.
pm_call_node_t * call
The call node wrapping the regular expression node (for =~).
pm_match_write_node_t * match
The match write node being built, or NULL if no captures found yet.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_string_t unescaped
RegularExpressionNode::unescaped.
pm_location_t content_loc
RegularExpressionNode::content_loc.
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_string_t unescaped
StringNode::unescaped.
pm_location_t content_loc
StringNode::content_loc.
A view of a sequence of bytes.
size_t length
The length of the string in bytes of memory.
pm_location_t lparen_loc
SuperNode::lparen_loc.
PM_NODE_ALIGNAS struct pm_node * block
SuperNode::block.
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.
#define PRISM_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.