15#define PM_TAB_WHITESPACE_SIZE 8
18#define MIN(a,b) (((a)<(b))?(a):(b))
19#define MAX(a,b) (((a)>(b))?(a):(b))
25#define FL PM_NODE_FLAGS
26#define UP PM_NODE_UPCAST
28#define PM_TOKEN_START(token_) ((token_)->start)
29#define PM_TOKEN_END(token_) ((token_)->end)
31#define PM_NODE_START(node_) (UP(node_)->location.start)
32#define PM_NODE_END(node_) (UP(node_)->location.end)
34#define PM_LOCATION_NULL_VALUE(parser_) ((pm_location_t) { .start = (parser_)->start, .end = (parser_)->start })
35#define PM_LOCATION_TOKEN_VALUE(token_) ((pm_location_t) { .start = PM_TOKEN_START(token_), .end = PM_TOKEN_END(token_) })
36#define PM_LOCATION_NODE_VALUE(node_) ((pm_location_t) { .start = PM_NODE_START(node_), .end = PM_NODE_END(node_) })
37#define PM_OPTIONAL_LOCATION_TOKEN_VALUE(token) ((token)->type == PM_TOKEN_NOT_PROVIDED ? ((pm_location_t) { 0 }) : PM_LOCATION_TOKEN_VALUE(token))
48lex_mode_incrementor(
const uint8_t start) {
65lex_mode_terminator(
const uint8_t start) {
88 parser->lex_modes.index++;
92 if (parser->lex_modes.
current == NULL)
return false;
94 *parser->lex_modes.
current = lex_mode;
96 parser->lex_modes.stack[parser->lex_modes.index] = lex_mode;
97 parser->lex_modes.
current = &parser->lex_modes.stack[parser->lex_modes.index];
107lex_mode_push_list(
pm_parser_t *parser,
bool interpolation, uint8_t delimiter) {
108 uint8_t incrementor = lex_mode_incrementor(delimiter);
109 uint8_t terminator = lex_mode_terminator(delimiter);
115 .interpolation = interpolation,
116 .incrementor = incrementor,
117 .terminator = terminator
123 uint8_t *breakpoints = lex_mode.as.list.breakpoints;
124 memcpy(breakpoints,
"\\ \t\f\r\v\n\0\0\0",
sizeof(lex_mode.as.list.breakpoints));
129 if (terminator !=
'\0') {
130 breakpoints[index++] = terminator;
136 breakpoints[index++] =
'#';
140 if (incrementor !=
'\0') {
141 breakpoints[index++] = incrementor;
145 return lex_mode_push(parser, lex_mode);
155 return lex_mode_push_list(parser,
false,
'\0');
162lex_mode_push_regexp(
pm_parser_t *parser, uint8_t incrementor, uint8_t terminator) {
164 .mode = PM_LEX_REGEXP,
167 .incrementor = incrementor,
168 .terminator = terminator
175 uint8_t *breakpoints = lex_mode.as.regexp.breakpoints;
176 memcpy(breakpoints,
"\r\n\\#\0\0",
sizeof(lex_mode.as.regexp.breakpoints));
180 if (terminator !=
'\0') {
181 breakpoints[index++] = terminator;
185 if (incrementor !=
'\0') {
186 breakpoints[index++] = incrementor;
190 return lex_mode_push(parser, lex_mode);
197lex_mode_push_string(
pm_parser_t *parser,
bool interpolation,
bool label_allowed, uint8_t incrementor, uint8_t terminator) {
199 .mode = PM_LEX_STRING,
202 .interpolation = interpolation,
203 .label_allowed = label_allowed,
204 .incrementor = incrementor,
205 .terminator = terminator
211 uint8_t *breakpoints = lex_mode.as.string.breakpoints;
212 memcpy(breakpoints,
"\r\n\\\0\0\0",
sizeof(lex_mode.as.string.breakpoints));
217 if (terminator !=
'\0') {
218 breakpoints[index++] = terminator;
224 breakpoints[index++] =
'#';
229 if (incrementor !=
'\0') {
230 breakpoints[index++] = incrementor;
234 return lex_mode_push(parser, lex_mode);
244 return lex_mode_push_string(parser,
false,
false,
'\0',
'\0');
254 if (parser->lex_modes.index == 0) {
255 parser->lex_modes.
current->mode = PM_LEX_DEFAULT;
257 parser->lex_modes.index--;
258 parser->lex_modes.
current = &parser->lex_modes.stack[parser->lex_modes.index];
260 parser->lex_modes.index--;
263 parser->lex_modes.
current = prev;
276 PM_IGNORED_NEWLINE_NONE = 0,
277 PM_IGNORED_NEWLINE_ALL,
278 PM_IGNORED_NEWLINE_PATTERN
279} pm_ignored_newline_type_t;
281static inline pm_ignored_newline_type_t
283 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);
286 return PM_IGNORED_NEWLINE_ALL;
287 }
else if ((parser->
lex_state & ~((
unsigned int) PM_LEX_STATE_LABEL)) == (PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED)) {
288 return PM_IGNORED_NEWLINE_PATTERN;
290 return PM_IGNORED_NEWLINE_NONE;
296 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));
301 return lex_state_p(parser, PM_LEX_STATE_ARG_ANY);
305lex_state_spcarg_p(
pm_parser_t *parser,
bool space_seen) {
309 return lex_state_arg_p(parser) && space_seen && !pm_char_is_whitespace(*parser->
current.
end);
314 return lex_state_p(parser, PM_LEX_STATE_END_ANY);
322 return lex_state_p(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_DOT);
334#ifndef PM_DEBUG_LOGGING
339#define PM_DEBUG_LOGGING 0
345 fprintf(stderr,
"STATE: ");
348 if (parser->
lex_state == PM_LEX_STATE_NONE) {
349 fprintf(stderr,
"NONE\n");
353#define CHECK_STATE(state) \
354 if (parser->lex_state & state) { \
355 if (!first) fprintf(stderr, "|"); \
356 fprintf(stderr, "%s", #state); \
360 CHECK_STATE(PM_LEX_STATE_BEG)
361 CHECK_STATE(PM_LEX_STATE_END)
362 CHECK_STATE(PM_LEX_STATE_ENDARG)
363 CHECK_STATE(PM_LEX_STATE_ENDFN)
364 CHECK_STATE(PM_LEX_STATE_ARG)
365 CHECK_STATE(PM_LEX_STATE_CMDARG)
366 CHECK_STATE(PM_LEX_STATE_MID)
367 CHECK_STATE(PM_LEX_STATE_FNAME)
368 CHECK_STATE(PM_LEX_STATE_DOT)
369 CHECK_STATE(PM_LEX_STATE_CLASS)
370 CHECK_STATE(PM_LEX_STATE_LABEL)
371 CHECK_STATE(PM_LEX_STATE_LABELED)
372 CHECK_STATE(PM_LEX_STATE_FITEM)
376 fprintf(stderr,
"\n");
381 fprintf(stderr,
"Caller: %s:%d\nPrevious: ", caller_name, line_number);
383 lex_state_set(parser, state);
384 fprintf(stderr,
"Now: ");
386 fprintf(stderr,
"\n");
389#define lex_state_set(parser, state) debug_lex_state_set(parser, state, __func__, __LINE__)
397#define PM_PARSER_COMMAND_LINE_OPTION(parser, option) ((parser)->command_line & (option))
400#define PM_PARSER_COMMAND_LINE_OPTION_A(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_A)
403#define PM_PARSER_COMMAND_LINE_OPTION_E(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_E)
406#define PM_PARSER_COMMAND_LINE_OPTION_L(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_L)
409#define PM_PARSER_COMMAND_LINE_OPTION_N(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_N)
412#define PM_PARSER_COMMAND_LINE_OPTION_P(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_P)
415#define PM_PARSER_COMMAND_LINE_OPTION_X(parser) PM_PARSER_COMMAND_LINE_OPTION(parser, PM_OPTIONS_COMMAND_LINE_X)
426 pm_diagnostic_list_append(&parser->
error_list, start, end, diag_id);
432#define PM_PARSER_ERR_FORMAT(parser, start, end, diag_id, ...) \
433 pm_diagnostic_list_append_format(&parser->error_list, start, end, diag_id, __VA_ARGS__)
448#define PM_PARSER_ERR_LOCATION_FORMAT(parser, location, diag_id, ...) \
449 PM_PARSER_ERR_FORMAT(parser, (location)->start, (location)->end, diag_id, __VA_ARGS__)
464#define PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, ...) \
465 PM_PARSER_ERR_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
471#define PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, diag_id) \
472 PM_PARSER_ERR_NODE_FORMAT(parser, node, diag_id, (int) ((node)->location.end - (node)->location.start), (const char *) (node)->location.start)
489 pm_parser_err(parser, token->
start, token->
end, diag_id);
496#define PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, ...) \
497 PM_PARSER_ERR_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
503#define PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
504 PM_PARSER_ERR_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
511 pm_diagnostic_list_append(&parser->
warning_list, start, end, diag_id);
520 pm_parser_warn(parser, token->
start, token->
end, diag_id);
535#define PM_PARSER_WARN_FORMAT(parser, start, end, diag_id, ...) \
536 pm_diagnostic_list_append_format(&parser->warning_list, start, end, diag_id, __VA_ARGS__)
542#define PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, ...) \
543 PM_PARSER_WARN_FORMAT(parser, (token).start, (token).end, diag_id, __VA_ARGS__)
549#define PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, token, diag_id) \
550 PM_PARSER_WARN_TOKEN_FORMAT(parser, token, diag_id, (int) ((token).end - (token).start), (const char *) (token).start)
556#define PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, ...) \
557 PM_PARSER_WARN_FORMAT(parser, (node)->location.start, (node)->location.end, diag_id, __VA_ARGS__)
565pm_parser_err_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
566 PM_PARSER_ERR_FORMAT(
569 ident_start + ident_length,
572 (
const char *) ident_start
584pm_parser_scope_push(
pm_parser_t *parser,
bool closed) {
586 if (scope == NULL)
return false;
591 .parameters = PM_SCOPE_PARAMETERS_NONE,
592 .implicit_parameters = { 0 },
610 if (scope->
previous == NULL)
return true;
611 if (scope->
closed)
return false;
612 }
while ((scope = scope->
previous) != NULL);
614 assert(
false &&
"unreachable");
622pm_parser_scope_find(
pm_parser_t *parser, uint32_t depth) {
625 while (depth-- > 0) {
626 assert(scope != NULL);
634 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS,
635 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT,
636 PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL
637} pm_scope_forwarding_param_check_result_t;
639static pm_scope_forwarding_param_check_result_t
640pm_parser_scope_forwarding_param_check(
pm_parser_t *parser,
const uint8_t mask) {
642 bool conflict =
false;
644 while (scope != NULL) {
648 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT;
650 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS;
661 return PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL;
666 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_BLOCK)) {
667 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
670 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
671 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_AMPERSAND);
673 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
674 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_AMPERSAND);
681 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_POSITIONALS)) {
682 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
685 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
686 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR);
688 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
689 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR);
696 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_ALL)) {
697 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
700 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
705 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
706 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
713 switch (pm_parser_scope_forwarding_param_check(parser, PM_SCOPE_PARAMETERS_FORWARDING_KEYWORDS)) {
714 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_PASS:
717 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_CONFLICT:
718 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_CONFLICT_STAR_STAR);
720 case PM_SCOPE_FORWARDING_PARAM_CHECK_RESULT_FAIL:
721 pm_parser_err_token(parser, token, PM_ERR_ARGUMENT_NO_FORWARDING_STAR_STAR);
730pm_parser_scope_shareable_constant_get(
pm_parser_t *parser) {
754#define PM_LOCALS_HASH_THRESHOLD 9
769 name = ((name >> 16) ^ name) * 0x45d9f3b;
770 name = ((name >> 16) ^ name) * 0x45d9f3b;
771 name = (name >> 16) ^ name;
781 uint32_t next_capacity = locals->
capacity == 0 ? 4 : (locals->
capacity * 2);
782 assert(next_capacity > locals->
capacity);
785 if (next_locals == NULL) abort();
787 if (next_capacity < PM_LOCALS_HASH_THRESHOLD) {
788 if (locals->
size > 0) {
794 bool hash_needed = (locals->
capacity <= PM_LOCALS_HASH_THRESHOLD);
795 uint32_t mask = next_capacity - 1;
797 for (uint32_t index = 0; index < locals->
capacity; index++) {
801 if (hash_needed) local->
hash = pm_locals_hash(local->
name);
803 uint32_t hash = local->
hash;
805 next_locals[hash & mask] = *local;
810 pm_locals_free(locals);
811 locals->
locals = next_locals;
833 pm_locals_resize(locals);
836 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
837 for (uint32_t index = 0; index < locals->
capacity; index++) {
843 .location = { .start = start, .end = end },
844 .index = locals->
size++,
849 }
else if (local->
name == name) {
854 uint32_t mask = locals->
capacity - 1;
855 uint32_t hash = pm_locals_hash(name);
856 uint32_t initial_hash = hash;
864 .location = { .start = start, .end = end },
865 .index = locals->
size++,
870 }
else if (local->
name == name) {
875 }
while ((hash & mask) != initial_hash);
878 assert(
false &&
"unreachable");
888 if (locals->
capacity < PM_LOCALS_HASH_THRESHOLD) {
889 for (uint32_t index = 0; index < locals->
size; index++) {
891 if (local->
name == name)
return index;
894 uint32_t mask = locals->
capacity - 1;
895 uint32_t hash = pm_locals_hash(name);
896 uint32_t initial_hash = hash & mask;
903 }
else if (local->
name == name) {
908 }
while ((hash & mask) != initial_hash);
920 uint32_t index = pm_locals_find(locals, name);
921 assert(index != UINT32_MAX);
924 assert(local->
reads < UINT32_MAX);
935 uint32_t index = pm_locals_find(locals, name);
936 assert(index != UINT32_MAX);
939 assert(local->
reads > 0);
949 uint32_t index = pm_locals_find(locals, name);
950 assert(index != UINT32_MAX);
965 pm_constant_id_list_init_capacity(list, locals->
size);
970 uint32_t capacity = locals->
capacity < PM_LOCALS_HASH_THRESHOLD ? locals->
size : locals->
capacity;
974 bool warn_unused = !toplevel || (!parser->parsing_eval && !PM_PARSER_COMMAND_LINE_OPTION_E(parser));
976 for (uint32_t index = 0; index < capacity; index++) {
980 pm_constant_id_list_insert(list, (
size_t) local->
index, local->
name);
982 if (warn_unused && local->
reads == 0 && ((parser->start_line >= 0) || (pm_newline_list_line(&parser->newline_list, local->
location.
start, parser->start_line) >= 0))) {
983 pm_constant_t *constant = pm_constant_pool_id_to_constant(&parser->constant_pool, local->
name);
985 if (constant->
length >= 1 && *constant->
start !=
'_') {
986 PM_PARSER_WARN_FORMAT(
990 PM_WARN_UNUSED_LOCAL_VARIABLE,
992 (
const char *) constant->
start
1008pm_parser_constant_id_location(
pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
1009 return pm_constant_pool_insert_shared(&parser->
constant_pool, start, (
size_t) (end - start));
1016pm_parser_constant_id_owned(
pm_parser_t *parser, uint8_t *start,
size_t length) {
1017 return pm_constant_pool_insert_owned(&parser->
constant_pool, start, length);
1024pm_parser_constant_id_constant(
pm_parser_t *parser,
const char *start,
size_t length) {
1025 return pm_constant_pool_insert_constant(&parser->
constant_pool, (
const uint8_t *) start, length);
1033 return pm_parser_constant_id_location(parser, token->
start, token->
end);
1042 return token->
type == PM_TOKEN_NOT_PROVIDED ? 0 : pm_parser_constant_id_token(parser, token);
1051pm_check_value_expression(
pm_parser_t *parser, pm_node_t *node) {
1052 pm_node_t *void_node = NULL;
1054 while (node != NULL) {
1055 switch (PM_NODE_TYPE(node)) {
1056 case PM_RETURN_NODE:
1061 case PM_MATCH_REQUIRED_NODE:
1062 return void_node != NULL ? void_node : node;
1063 case PM_MATCH_PREDICATE_NODE:
1065 case PM_BEGIN_NODE: {
1066 pm_begin_node_t *cast = (pm_begin_node_t *) node;
1070 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
rescue_clause));
1071 if (vn != NULL)
return vn;
1075 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
statements));
1076 if (vn != NULL)
return vn;
1083 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
statements));
1084 if (vn == NULL)
return NULL;
1085 if (void_node == NULL) void_node = vn;
1087 for (pm_rescue_node_t *rescue_clause = cast->
rescue_clause; rescue_clause != NULL; rescue_clause = rescue_clause->
subsequent) {
1088 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1093 if (void_node == NULL) {
1109 case PM_ENSURE_NODE: {
1110 pm_ensure_node_t *cast = (pm_ensure_node_t *) node;
1114 case PM_PARENTHESES_NODE: {
1115 pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
1116 node = UP(cast->
body);
1119 case PM_STATEMENTS_NODE: {
1120 pm_statements_node_t *cast = (pm_statements_node_t *) node;
1125 pm_if_node_t *cast = (pm_if_node_t *) node;
1129 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
statements));
1133 if (void_node == NULL) {
1139 case PM_UNLESS_NODE: {
1140 pm_unless_node_t *cast = (pm_unless_node_t *) node;
1144 pm_node_t *vn = pm_check_value_expression(parser, UP(cast->
statements));
1148 if (void_node == NULL) {
1154 case PM_ELSE_NODE: {
1155 pm_else_node_t *cast = (pm_else_node_t *) node;
1160 pm_and_node_t *cast = (pm_and_node_t *) node;
1165 pm_or_node_t *cast = (pm_or_node_t *) node;
1169 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1170 pm_local_variable_write_node_t *cast = (pm_local_variable_write_node_t *) node;
1173 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
1187pm_assert_value_expression(
pm_parser_t *parser, pm_node_t *node) {
1188 pm_node_t *void_node = pm_check_value_expression(parser, node);
1189 if (void_node != NULL) {
1190 pm_parser_err_node(parser, void_node, PM_ERR_VOID_EXPRESSION);
1198pm_void_statement_check(
pm_parser_t *parser,
const pm_node_t *node) {
1199 const char *
type = NULL;
1202 switch (PM_NODE_TYPE(node)) {
1203 case PM_BACK_REFERENCE_READ_NODE:
1204 case PM_CLASS_VARIABLE_READ_NODE:
1205 case PM_GLOBAL_VARIABLE_READ_NODE:
1206 case PM_INSTANCE_VARIABLE_READ_NODE:
1207 case PM_LOCAL_VARIABLE_READ_NODE:
1208 case PM_NUMBERED_REFERENCE_READ_NODE:
1209 type =
"a variable";
1212 case PM_CALL_NODE: {
1213 const pm_call_node_t *cast = (
const pm_call_node_t *) node;
1217 switch (message->
length) {
1219 switch (message->
start[0]) {
1236 switch (message->
start[1]) {
1238 if (message->
start[0] ==
'<' || message->
start[0] ==
'>' || message->
start[0] ==
'!' || message->
start[0] ==
'=') {
1244 if (message->
start[0] ==
'+' || message->
start[0] ==
'-') {
1250 if (message->
start[0] ==
'*') {
1258 if (memcmp(message->
start,
"<=>", 3) == 0) {
1267 case PM_CONSTANT_PATH_NODE:
1271 case PM_CONSTANT_READ_NODE:
1272 type =
"a constant";
1275 case PM_DEFINED_NODE:
1284 case PM_IMAGINARY_NODE:
1285 case PM_INTEGER_NODE:
1286 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1287 case PM_INTERPOLATED_STRING_NODE:
1288 case PM_RATIONAL_NODE:
1289 case PM_REGULAR_EXPRESSION_NODE:
1290 case PM_SOURCE_ENCODING_NODE:
1291 case PM_SOURCE_FILE_NODE:
1292 case PM_SOURCE_LINE_NODE:
1293 case PM_STRING_NODE:
1294 case PM_SYMBOL_NODE:
1302 case PM_RANGE_NODE: {
1303 const pm_range_node_t *cast = (
const pm_range_node_t *) node;
1305 if (PM_NODE_FLAG_P(cast, PM_RANGE_FLAGS_EXCLUDE_END)) {
1328 PM_PARSER_WARN_NODE_FORMAT(parser, node, PM_WARN_VOID_STATEMENT, length,
type);
1337pm_void_statements_check(
pm_parser_t *parser,
const pm_statements_node_t *node,
bool last_value) {
1339 const size_t size = node->
body.
size - (last_value ? 1 : 0);
1340 for (
size_t index = 0; index < size; index++) {
1341 pm_void_statement_check(parser, node->
body.
nodes[index]);
1351 PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL,
1352 PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP,
1353 PM_CONDITIONAL_PREDICATE_TYPE_NOT
1354} pm_conditional_predicate_type_t;
1360pm_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) {
1362 case PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL:
1363 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"condition");
1365 case PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP:
1366 PM_PARSER_WARN_NODE_FORMAT(parser, node, diag_id, prefix,
"flip-flop");
1368 case PM_CONDITIONAL_PREDICATE_TYPE_NOT:
1378pm_conditional_predicate_warn_write_literal_p(
const pm_node_t *node) {
1379 switch (PM_NODE_TYPE(node)) {
1380 case PM_ARRAY_NODE: {
1381 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1383 const pm_array_node_t *cast = (
const pm_array_node_t *) node;
1384 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1385 if (!pm_conditional_predicate_warn_write_literal_p(cast->
elements.
nodes[index]))
return false;
1390 case PM_HASH_NODE: {
1391 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL))
return true;
1393 const pm_hash_node_t *cast = (
const pm_hash_node_t *) node;
1394 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1396 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
1398 const pm_assoc_node_t *assoc = (
const pm_assoc_node_t *) element;
1399 if (!pm_conditional_predicate_warn_write_literal_p(assoc->
key) || !pm_conditional_predicate_warn_write_literal_p(assoc->
value))
return false;
1406 case PM_IMAGINARY_NODE:
1407 case PM_INTEGER_NODE:
1409 case PM_RATIONAL_NODE:
1410 case PM_REGULAR_EXPRESSION_NODE:
1411 case PM_SOURCE_ENCODING_NODE:
1412 case PM_SOURCE_FILE_NODE:
1413 case PM_SOURCE_LINE_NODE:
1414 case PM_STRING_NODE:
1415 case PM_SYMBOL_NODE:
1428pm_conditional_predicate_warn_write_literal(
pm_parser_t *parser,
const pm_node_t *node) {
1429 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1447pm_conditional_predicate(
pm_parser_t *parser, pm_node_t *node, pm_conditional_predicate_type_t
type) {
1448 switch (PM_NODE_TYPE(node)) {
1450 pm_and_node_t *cast = (pm_and_node_t *) node;
1451 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1452 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1456 pm_or_node_t *cast = (pm_or_node_t *) node;
1457 pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1458 pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
1461 case PM_PARENTHESES_NODE: {
1462 pm_parentheses_node_t *cast = (pm_parentheses_node_t *) node;
1464 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1465 pm_statements_node_t *statements = (pm_statements_node_t *) cast->
body;
1466 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1471 case PM_BEGIN_NODE: {
1472 pm_begin_node_t *cast = (pm_begin_node_t *) node;
1474 pm_statements_node_t *statements = cast->
statements;
1479 case PM_RANGE_NODE: {
1480 pm_range_node_t *cast = (pm_range_node_t *) node;
1482 if (cast->
left != NULL) pm_conditional_predicate(parser, cast->
left, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1483 if (cast->
right != NULL) pm_conditional_predicate(parser, cast->
right, PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP);
1490 assert(
sizeof(pm_range_node_t) ==
sizeof(pm_flip_flop_node_t));
1491 node->
type = PM_FLIP_FLOP_NODE;
1495 case PM_REGULAR_EXPRESSION_NODE:
1499 assert(
sizeof(pm_regular_expression_node_t) ==
sizeof(pm_match_last_line_node_t));
1500 node->
type = PM_MATCH_LAST_LINE_NODE;
1502 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1503 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"regex ");
1507 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
1511 assert(
sizeof(pm_interpolated_regular_expression_node_t) ==
sizeof(pm_interpolated_match_last_line_node_t));
1512 node->
type = PM_INTERPOLATED_MATCH_LAST_LINE_NODE;
1514 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1515 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"regex ");
1519 case PM_INTEGER_NODE:
1520 if (
type == PM_CONDITIONAL_PREDICATE_TYPE_FLIP_FLOP) {
1521 if (!PM_PARSER_COMMAND_LINE_OPTION_E(parser)) {
1522 pm_parser_warn_node(parser, node, PM_WARN_INTEGER_IN_FLIP_FLOP);
1525 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1528 case PM_STRING_NODE:
1529 case PM_SOURCE_FILE_NODE:
1530 case PM_INTERPOLATED_STRING_NODE:
1531 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_DEFAULT,
"string ");
1533 case PM_SYMBOL_NODE:
1534 case PM_INTERPOLATED_SYMBOL_NODE:
1535 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"symbol ");
1537 case PM_SOURCE_LINE_NODE:
1538 case PM_SOURCE_ENCODING_NODE:
1540 case PM_RATIONAL_NODE:
1541 case PM_IMAGINARY_NODE:
1542 pm_parser_warn_conditional_predicate_literal(parser, node,
type, PM_WARN_LITERAL_IN_CONDITION_VERBOSE,
"");
1544 case PM_CLASS_VARIABLE_WRITE_NODE:
1545 pm_conditional_predicate_warn_write_literal(parser, ((pm_class_variable_write_node_t *) node)->value);
1547 case PM_CONSTANT_WRITE_NODE:
1548 pm_conditional_predicate_warn_write_literal(parser, ((pm_constant_write_node_t *) node)->value);
1550 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1551 pm_conditional_predicate_warn_write_literal(parser, ((pm_global_variable_write_node_t *) node)->value);
1553 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1554 pm_conditional_predicate_warn_write_literal(parser, ((pm_instance_variable_write_node_t *) node)->value);
1556 case PM_LOCAL_VARIABLE_WRITE_NODE:
1557 pm_conditional_predicate_warn_write_literal(parser, ((pm_local_variable_write_node_t *) node)->value);
1559 case PM_MULTI_WRITE_NODE:
1560 pm_conditional_predicate_warn_write_literal(parser, ((pm_multi_write_node_t *) node)->value);
1577 return (
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start };
1606static inline const uint8_t *
1608 if (arguments->
block != NULL) {
1649 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_UNEXPECTED_BLOCK);
1663char_is_identifier_start(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1664 if (n <= 0)
return 0;
1671 }
else if (*b ==
'_') {
1673 }
else if (*b >= 0x80) {
1678 }
else if (*b < 0x80) {
1681 return pm_encoding_utf_8_char_width(b, n);
1690char_is_identifier_utf8(
const uint8_t *b, ptrdiff_t n) {
1693 }
else if (*b < 0x80) {
1696 return pm_encoding_utf_8_char_width(b, n);
1706char_is_identifier(
const pm_parser_t *parser,
const uint8_t *b, ptrdiff_t n) {
1714 }
else if (*b ==
'_') {
1716 }
else if (*b >= 0x80) {
1722 return char_is_identifier_utf8(b, n);
1729#define BIT(c, idx) (((c) / 32 - 1 == idx) ? (1U << ((c) % 32)) : 0)
1730#define PUNCT(idx) ( \
1731 BIT('~', idx) | BIT('*', idx) | BIT('$', idx) | BIT('?', idx) | \
1732 BIT('!', idx) | BIT('@', idx) | BIT('/', idx) | BIT('\\', idx) | \
1733 BIT(';', idx) | BIT(',', idx) | BIT('.', idx) | BIT('=', idx) | \
1734 BIT(':', idx) | BIT('<', idx) | BIT('>', idx) | BIT('\"', idx) | \
1735 BIT('&', idx) | BIT('`', idx) | BIT('\'', idx) | BIT('+', idx) | \
1738const unsigned int pm_global_name_punctuation_hash[(0x7e - 0x20 + 31) / 32] = { PUNCT(0), PUNCT(1), PUNCT(2) };
1744char_is_global_name_punctuation(const uint8_t b) {
1745 const unsigned int i = (const unsigned int) b;
1746 if (i <= 0x20 || 0x7e < i) return false;
1748 return (pm_global_name_punctuation_hash[(i - 0x20) / 32] >> (i % 32)) & 1;
1752token_is_setter_name(pm_token_t *token) {
1754 (token->type == PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL) ||
1755 ((token->type == PM_TOKEN_IDENTIFIER) &&
1756 (token->end - token->start >= 2) &&
1757 (token->end[-1] == '='))
1765pm_local_is_keyword(const char *source, size_t length) {
1766#define KEYWORD(name) if (memcmp(source, name, length) == 0) return true
1770 switch (source[0]) {
1771 case 'd': KEYWORD("do"); return false;
1772 case 'i': KEYWORD("if"); KEYWORD("in"); return false;
1773 case 'o': KEYWORD("or"); return false;
1774 default: return false;
1777 switch (source[0]) {
1778 case 'a': KEYWORD("and"); return false;
1779 case 'd': KEYWORD("def"); return false;
1780 case 'e': KEYWORD("end"); return false;
1781 case 'f': KEYWORD("for"); return false;
1782 case 'n': KEYWORD("nil"); KEYWORD("not"); return false;
1783 default: return false;
1786 switch (source[0]) {
1787 case 'c': KEYWORD("case"); return false;
1788 case 'e': KEYWORD("else"); return false;
1789 case 'n': KEYWORD("next"); return false;
1790 case 'r': KEYWORD("redo"); return false;
1791 case 's': KEYWORD("self"); return false;
1792 case 't': KEYWORD("then"); KEYWORD("true"); return false;
1793 case 'w': KEYWORD("when"); return false;
1794 default: return false;
1797 switch (source[0]) {
1798 case 'a': KEYWORD("alias"); return false;
1799 case 'b': KEYWORD("begin"); KEYWORD("break"); return false;
1800 case 'c': KEYWORD("class"); return false;
1801 case 'e': KEYWORD("elsif"); return false;
1802 case 'f': KEYWORD("false"); return false;
1803 case 'r': KEYWORD("retry"); return false;
1804 case 's': KEYWORD("super"); return false;
1805 case 'u': KEYWORD("undef"); KEYWORD("until"); return false;
1806 case 'w': KEYWORD("while"); return false;
1807 case 'y': KEYWORD("yield"); return false;
1808 default: return false;
1811 switch (source[0]) {
1812 case 'e': KEYWORD("ensure"); return false;
1813 case 'm': KEYWORD("module"); return false;
1814 case 'r': KEYWORD("rescue"); KEYWORD("return"); return false;
1815 case 'u': KEYWORD("unless"); return false;
1816 default: return false;
1819 KEYWORD("__LINE__");
1820 KEYWORD("__FILE__");
1823 KEYWORD("__ENCODING__");
1832/******************************************************************************/
1833/* Node flag handling functions */
1834/******************************************************************************/
1840pm_node_flag_set(pm_node_t *node, pm_node_flags_t flag) {
1841 node->flags |= flag;
1848pm_node_flag_unset(pm_node_t *node, pm_node_flags_t flag) {
1849 node->flags &= (pm_node_flags_t) ~flag;
1856pm_node_flag_set_repeated_parameter(pm_node_t *node) {
1857 assert(PM_NODE_TYPE(node) == PM_BLOCK_LOCAL_VARIABLE_NODE ||
1858 PM_NODE_TYPE(node) == PM_BLOCK_PARAMETER_NODE ||
1859 PM_NODE_TYPE(node) == PM_KEYWORD_REST_PARAMETER_NODE ||
1860 PM_NODE_TYPE(node) == PM_OPTIONAL_KEYWORD_PARAMETER_NODE ||
1861 PM_NODE_TYPE(node) == PM_OPTIONAL_PARAMETER_NODE ||
1862 PM_NODE_TYPE(node) == PM_REQUIRED_KEYWORD_PARAMETER_NODE ||
1863 PM_NODE_TYPE(node) == PM_REQUIRED_PARAMETER_NODE ||
1864 PM_NODE_TYPE(node) == PM_REST_PARAMETER_NODE);
1866 pm_node_flag_set(node, PM_PARAMETER_FLAGS_REPEATED_PARAMETER);
1869/******************************************************************************/
1870/* Node creation functions */
1871/******************************************************************************/
1878#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)
1883static inline pm_node_flags_t
1884pm_regular_expression_flags_create(pm_parser_t *parser, const pm_token_t *closing) {
1885 pm_node_flags_t flags = 0;
1887 if (closing->type == PM_TOKEN_REGEXP_END) {
1888 pm_buffer_t unknown_flags = { 0 };
1890 for (const uint8_t *flag = closing->start + 1; flag < closing->end; flag++) {
1892 case 'i': flags |= PM_REGULAR_EXPRESSION_FLAGS_IGNORE_CASE; break;
1893 case 'm': flags |= PM_REGULAR_EXPRESSION_FLAGS_MULTI_LINE; break;
1894 case 'x': flags |= PM_REGULAR_EXPRESSION_FLAGS_EXTENDED; break;
1895 case 'o': flags |= PM_REGULAR_EXPRESSION_FLAGS_ONCE; break;
1897 case 'e': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_EUC_JP); break;
1898 case 'n': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT); break;
1899 case 's': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J); break;
1900 case 'u': flags = (pm_node_flags_t) (((pm_node_flags_t) (flags & PM_REGULAR_EXPRESSION_ENCODING_MASK)) | PM_REGULAR_EXPRESSION_FLAGS_UTF_8); break;
1902 default: pm_buffer_append_byte(&unknown_flags, *flag);
1906 size_t unknown_flags_length = pm_buffer_length(&unknown_flags);
1907 if (unknown_flags_length != 0) {
1908 const char *word = unknown_flags_length >= 2 ? "options" : "option";
1909 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->previous, PM_ERR_REGEXP_UNKNOWN_OPTIONS, word, unknown_flags_length, pm_buffer_value(&unknown_flags));
1911 pm_buffer_free(&unknown_flags);
1917#undef PM_REGULAR_EXPRESSION_ENCODING_MASK
1919static pm_statements_node_t *
1920pm_statements_node_create(pm_parser_t *parser);
1923pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline);
1926pm_statements_node_body_length(pm_statements_node_t *node);
1933pm_node_alloc(PRISM_ATTRIBUTE_UNUSED pm_parser_t *parser, size_t size) {
1934 void *memory = xcalloc(1, size);
1935 if (memory == NULL) {
1936 fprintf(stderr, "Failed to allocate %d bytes\n", (int) size);
1942#define PM_NODE_ALLOC(parser_, type_) (type_ *) pm_node_alloc(parser_, sizeof(type_))
1943#define PM_NODE_INIT(parser_, type_, flags_, start_, end_) (pm_node_t) { \
1945 .flags = (flags_), \
1946 .node_id = ++(parser_)->node_id, \
1947 .location = { .start = (start_), .end = (end_) } \
1950#define PM_NODE_INIT_UNSET(parser_, type_, flags_) PM_NODE_INIT(parser_, type_, flags_, NULL, NULL)
1951#define PM_NODE_INIT_BASE(parser_, type_, flags_) PM_NODE_INIT(parser_, type_, flags_, (parser_)->start, (parser_)->start)
1952#define PM_NODE_INIT_TOKEN(parser_, type_, flags_, token_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(token_), PM_TOKEN_END(token_))
1953#define PM_NODE_INIT_NODE(parser_, type_, flags_, node_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(node_), PM_NODE_END(node_))
1955#define PM_NODE_INIT_TOKENS(parser_, type_, flags_, left_, right_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(left_), PM_TOKEN_END(right_))
1956#define PM_NODE_INIT_NODES(parser_, type_, flags_, left_, right_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(left_), PM_NODE_END(right_))
1957#define PM_NODE_INIT_TOKEN_NODE(parser_, type_, flags_, token_, node_) PM_NODE_INIT(parser_, type_, flags_, PM_TOKEN_START(token_), PM_NODE_END(node_))
1958#define PM_NODE_INIT_NODE_TOKEN(parser_, type_, flags_, node_, token_) PM_NODE_INIT(parser_, type_, flags_, PM_NODE_START(node_), PM_TOKEN_END(token_))
1963static pm_missing_node_t *
1964pm_missing_node_create(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
1965 pm_missing_node_t *node = PM_NODE_ALLOC(parser, pm_missing_node_t);
1967 *node = (pm_missing_node_t) {
1968 .base = PM_NODE_INIT(parser, PM_MISSING_NODE, 0, start, end)
1977static pm_alias_global_variable_node_t *
1978pm_alias_global_variable_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1979 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1980 pm_alias_global_variable_node_t *node = PM_NODE_ALLOC(parser, pm_alias_global_variable_node_t);
1982 *node = (pm_alias_global_variable_node_t) {
1983 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_ALIAS_GLOBAL_VARIABLE_NODE, 0, keyword, old_name),
1984 .new_name = new_name,
1985 .old_name = old_name,
1986 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
1995static pm_alias_method_node_t *
1996pm_alias_method_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_node_t *new_name, pm_node_t *old_name) {
1997 assert(keyword->type == PM_TOKEN_KEYWORD_ALIAS);
1998 pm_alias_method_node_t *node = PM_NODE_ALLOC(parser, pm_alias_method_node_t);
2000 *node = (pm_alias_method_node_t) {
2001 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_ALIAS_METHOD_NODE, 0, keyword, old_name),
2002 .new_name = new_name,
2003 .old_name = old_name,
2004 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2013static pm_alternation_pattern_node_t *
2014pm_alternation_pattern_node_create(pm_parser_t *parser, pm_node_t *left, pm_node_t *right, const pm_token_t *operator) {
2015 pm_alternation_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_alternation_pattern_node_t);
2017 *node = (pm_alternation_pattern_node_t) {
2018 .base = PM_NODE_INIT_NODES(parser, PM_ALTERNATION_PATTERN_NODE, 0, left, right),
2021 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2030static pm_and_node_t *
2031pm_and_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
2032 pm_assert_value_expression(parser, left);
2034 pm_and_node_t *node = PM_NODE_ALLOC(parser, pm_and_node_t);
2036 *node = (pm_and_node_t) {
2037 .base = PM_NODE_INIT_NODES(parser, PM_AND_NODE, 0, left, right),
2039 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2049static pm_arguments_node_t *
2050pm_arguments_node_create(pm_parser_t *parser) {
2051 pm_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_arguments_node_t);
2053 *node = (pm_arguments_node_t) {
2054 .base = PM_NODE_INIT_BASE(parser, PM_ARGUMENTS_NODE, 0),
2065pm_arguments_node_size(pm_arguments_node_t *node) {
2066 return node->arguments.size;
2073pm_arguments_node_arguments_append(pm_arguments_node_t *node, pm_node_t *argument) {
2074 if (pm_arguments_node_size(node) == 0) {
2075 node->base.location.start = argument->location.start;
2078 if (node->base.location.end < argument->location.end) {
2079 node->base.location.end = argument->location.end;
2082 pm_node_list_append(&node->arguments, argument);
2084 if (PM_NODE_TYPE_P(argument, PM_SPLAT_NODE)) {
2085 if (PM_NODE_FLAG_P(node, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
2086 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_MULTIPLE_SPLATS);
2088 pm_node_flag_set(UP(node), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT);
2096static pm_array_node_t *
2097pm_array_node_create(pm_parser_t *parser, const pm_token_t *opening) {
2098 pm_array_node_t *node = PM_NODE_ALLOC(parser, pm_array_node_t);
2100 *node = (pm_array_node_t) {
2101 .base = PM_NODE_INIT_TOKEN(parser, PM_ARRAY_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
2102 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2103 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2114pm_array_node_elements_append(pm_array_node_t *node, pm_node_t *element) {
2115 if (!node->elements.size && !node->opening_loc.start) {
2116 node->base.location.start = element->location.start;
2119 pm_node_list_append(&node->elements, element);
2120 node->base.location.end = element->location.end;
2122 // If the element is not a static literal, then the array is not a static
2123 // literal. Turn that flag off.
2124 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)) {
2125 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
2128 if (PM_NODE_TYPE_P(element, PM_SPLAT_NODE)) {
2129 pm_node_flag_set(UP(node), PM_ARRAY_NODE_FLAGS_CONTAINS_SPLAT);
2137pm_array_node_close_set(pm_array_node_t *node, const pm_token_t *closing) {
2138 assert(closing->type == PM_TOKEN_BRACKET_RIGHT || closing->type == PM_TOKEN_STRING_END || closing->type == PM_TOKEN_MISSING || closing->type == PM_TOKEN_NOT_PROVIDED);
2139 node->base.location.end = closing->end;
2140 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2147static pm_array_pattern_node_t *
2148pm_array_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *nodes) {
2149 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2151 *node = (pm_array_pattern_node_t) {
2152 .base = PM_NODE_INIT_NODES(parser, PM_ARRAY_PATTERN_NODE, 0, nodes->nodes[0], nodes->nodes[nodes->size - 1]),
2157 .opening_loc = { 0 },
2158 .closing_loc = { 0 }
2161 // For now we're going to just copy over each pointer manually. This could be
2162 // much more efficient, as we could instead resize the node list.
2163 bool found_rest = false;
2166 PM_NODE_LIST_FOREACH(nodes, index, child) {
2167 if (!found_rest && (PM_NODE_TYPE_P(child, PM_SPLAT_NODE) || PM_NODE_TYPE_P(child, PM_IMPLICIT_REST_NODE))) {
2170 } else if (found_rest) {
2171 pm_node_list_append(&node->posts, child);
2173 pm_node_list_append(&node->requireds, child);
2183static pm_array_pattern_node_t *
2184pm_array_pattern_node_rest_create(pm_parser_t *parser, pm_node_t *rest) {
2185 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2187 *node = (pm_array_pattern_node_t) {
2188 .base = PM_NODE_INIT_NODE(parser, PM_ARRAY_PATTERN_NODE, 0, rest),
2193 .opening_loc = { 0 },
2194 .closing_loc = { 0 }
2204static pm_array_pattern_node_t *
2205pm_array_pattern_node_constant_create(pm_parser_t *parser, pm_node_t *constant, const pm_token_t *opening, const pm_token_t *closing) {
2206 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2208 *node = (pm_array_pattern_node_t) {
2209 .base = PM_NODE_INIT_NODE_TOKEN(parser, PM_ARRAY_PATTERN_NODE, 0, constant, closing),
2210 .constant = constant,
2212 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2213 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2225static pm_array_pattern_node_t *
2226pm_array_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
2227 pm_array_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_array_pattern_node_t);
2229 *node = (pm_array_pattern_node_t) {
2230 .base = PM_NODE_INIT_TOKENS(parser, PM_ARRAY_PATTERN_NODE, 0, opening, closing),
2233 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2234 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
2243pm_array_pattern_node_requireds_append(pm_array_pattern_node_t *node, pm_node_t *inner) {
2244 pm_node_list_append(&node->requireds, inner);
2250static pm_assoc_node_t *
2251pm_assoc_node_create(pm_parser_t *parser, pm_node_t *key, const pm_token_t *operator, pm_node_t *value) {
2252 pm_assoc_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_node_t);
2255 if (value != NULL && value->location.end > key->location.end) {
2256 end = value->location.end;
2257 } else if (operator->type != PM_TOKEN_NOT_PROVIDED) {
2258 end = operator->end;
2260 end = key->location.end;
2263 // Hash string keys will be frozen, so we can mark them as frozen here so
2264 // that the compiler picks them up and also when we check for static literal
2265 // on the keys it gets factored in.
2266 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
2267 key->flags |= PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL;
2270 // If the key and value of this assoc node are both static literals, then
2271 // we can mark this node as a static literal.
2272 pm_node_flags_t flags = 0;
2274 !PM_NODE_TYPE_P(key, PM_ARRAY_NODE) && !PM_NODE_TYPE_P(key, PM_HASH_NODE) && !PM_NODE_TYPE_P(key, PM_RANGE_NODE) &&
2275 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)
2277 flags = key->flags & value->flags & PM_NODE_FLAG_STATIC_LITERAL;
2280 *node = (pm_assoc_node_t) {
2281 .base = PM_NODE_INIT(parser, PM_ASSOC_NODE, flags, key->location.start, end),
2283 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
2293static pm_assoc_splat_node_t *
2294pm_assoc_splat_node_create(pm_parser_t *parser, pm_node_t *value, const pm_token_t *operator) {
2295 assert(operator->type == PM_TOKEN_USTAR_STAR);
2296 pm_assoc_splat_node_t *node = PM_NODE_ALLOC(parser, pm_assoc_splat_node_t);
2298 *node = (pm_assoc_splat_node_t) {
2301 ? PM_NODE_INIT_TOKEN(parser, PM_ASSOC_SPLAT_NODE, 0, operator)
2302 : PM_NODE_INIT_TOKEN_NODE(parser, PM_ASSOC_SPLAT_NODE, 0, operator, value)
2305 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2314static pm_back_reference_read_node_t *
2315pm_back_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
2316 assert(name->type == PM_TOKEN_BACK_REFERENCE);
2317 pm_back_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_back_reference_read_node_t);
2319 *node = (pm_back_reference_read_node_t) {
2320 .base = PM_NODE_INIT_TOKEN(parser, PM_BACK_REFERENCE_READ_NODE, 0, name),
2321 .name = pm_parser_constant_id_token(parser, name)
2330static pm_begin_node_t *
2331pm_begin_node_create(pm_parser_t *parser, const pm_token_t *begin_keyword, pm_statements_node_t *statements) {
2332 pm_begin_node_t *node = PM_NODE_ALLOC(parser, pm_begin_node_t);
2334 *node = (pm_begin_node_t) {
2336 (statements == NULL)
2337 ? PM_NODE_INIT_TOKEN(parser, PM_BEGIN_NODE, 0, begin_keyword)
2338 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BEGIN_NODE, 0, begin_keyword, statements)
2340 .begin_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(begin_keyword),
2341 .statements = statements,
2342 .end_keyword_loc = { 0 }
2352pm_begin_node_rescue_clause_set(pm_begin_node_t *node, pm_rescue_node_t *rescue_clause) {
2353 // If the begin keyword doesn't exist, we set the start on the begin_node
2354 if (!node->begin_keyword_loc.start) {
2355 node->base.location.start = rescue_clause->base.location.start;
2357 node->base.location.end = rescue_clause->base.location.end;
2358 node->rescue_clause = rescue_clause;
2365pm_begin_node_else_clause_set(pm_begin_node_t *node, pm_else_node_t *else_clause) {
2366 node->base.location.end = else_clause->base.location.end;
2367 node->else_clause = else_clause;
2374pm_begin_node_ensure_clause_set(pm_begin_node_t *node, pm_ensure_node_t *ensure_clause) {
2375 node->base.location.end = ensure_clause->base.location.end;
2376 node->ensure_clause = ensure_clause;
2383pm_begin_node_end_keyword_set(pm_begin_node_t *node, const pm_token_t *end_keyword) {
2384 assert(end_keyword->type == PM_TOKEN_KEYWORD_END || end_keyword->type == PM_TOKEN_MISSING);
2386 node->base.location.end = end_keyword->end;
2387 node->end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword);
2393static pm_block_argument_node_t *
2394pm_block_argument_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
2395 pm_block_argument_node_t *node = PM_NODE_ALLOC(parser, pm_block_argument_node_t);
2397 *node = (pm_block_argument_node_t) {
2399 (expression == NULL)
2400 ? PM_NODE_INIT_TOKEN(parser, PM_BLOCK_ARGUMENT_NODE, 0, operator)
2401 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BLOCK_ARGUMENT_NODE, 0, operator, expression)
2403 .expression = expression,
2404 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2413static pm_block_node_t *
2414pm_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) {
2415 pm_block_node_t *node = PM_NODE_ALLOC(parser, pm_block_node_t);
2417 *node = (pm_block_node_t) {
2418 .base = PM_NODE_INIT_TOKENS(parser, PM_BLOCK_NODE, 0, opening, closing),
2420 .parameters = parameters,
2422 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
2423 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
2432static pm_block_parameter_node_t *
2433pm_block_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator) {
2434 assert(operator->type == PM_TOKEN_NOT_PROVIDED || operator->type == PM_TOKEN_UAMPERSAND || operator->type == PM_TOKEN_AMPERSAND);
2435 pm_block_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameter_node_t);
2437 *node = (pm_block_parameter_node_t) {
2439 (name->type == PM_TOKEN_NOT_PROVIDED)
2440 ? PM_NODE_INIT_TOKEN(parser, PM_BLOCK_PARAMETER_NODE, 0, operator)
2441 : PM_NODE_INIT_TOKENS(parser, PM_BLOCK_PARAMETER_NODE, 0, operator, name)
2443 .name = pm_parser_optional_constant_id_token(parser, name),
2444 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
2445 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
2454static pm_block_parameters_node_t *
2455pm_block_parameters_node_create(pm_parser_t *parser, pm_parameters_node_t *parameters, const pm_token_t *opening) {
2456 pm_block_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_block_parameters_node_t);
2458 const uint8_t *start;
2459 if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2460 start = opening->start;
2461 } else if (parameters != NULL) {
2462 start = parameters->base.location.start;
2468 if (parameters != NULL) {
2469 end = parameters->base.location.end;
2470 } else if (opening->type != PM_TOKEN_NOT_PROVIDED) {
2476 *node = (pm_block_parameters_node_t) {
2477 .base = PM_NODE_INIT(parser, PM_BLOCK_PARAMETERS_NODE, 0, start, end),
2478 .parameters = parameters,
2479 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
2480 .closing_loc = { 0 },
2491pm_block_parameters_node_closing_set(pm_block_parameters_node_t *node, const pm_token_t *closing) {
2492 assert(closing->type == PM_TOKEN_PIPE || closing->type == PM_TOKEN_PARENTHESIS_RIGHT || closing->type == PM_TOKEN_MISSING);
2494 node->base.location.end = closing->end;
2495 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
2501static pm_block_local_variable_node_t *
2502pm_block_local_variable_node_create(pm_parser_t *parser, const pm_token_t *name) {
2503 pm_block_local_variable_node_t *node = PM_NODE_ALLOC(parser, pm_block_local_variable_node_t);
2505 *node = (pm_block_local_variable_node_t) {
2506 .base = PM_NODE_INIT_TOKEN(parser, PM_BLOCK_LOCAL_VARIABLE_NODE, 0, name),
2507 .name = pm_parser_constant_id_token(parser, name)
2517pm_block_parameters_node_append_local(pm_block_parameters_node_t *node, const pm_block_local_variable_node_t *local) {
2518 pm_node_list_append(&node->locals, UP(local));
2520 if (node->base.location.start == NULL) node->base.location.start = local->base.location.start;
2521 node->base.location.end = local->base.location.end;
2527static pm_break_node_t *
2528pm_break_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
2529 assert(keyword->type == PM_TOKEN_KEYWORD_BREAK);
2530 pm_break_node_t *node = PM_NODE_ALLOC(parser, pm_break_node_t);
2532 *node = (pm_break_node_t) {
2535 ? PM_NODE_INIT_TOKEN(parser, PM_BREAK_NODE, 0, keyword)
2536 : PM_NODE_INIT_TOKEN_NODE(parser, PM_BREAK_NODE, 0, keyword, arguments)
2538 .arguments = arguments,
2539 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
2545// There are certain flags that we want to use internally but don't want to
2546// expose because they are not relevant beyond parsing. Therefore we'll define
2547// them here and not define them in config.yml/a header file.
2548static const pm_node_flags_t PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY = (1 << 2);
2550static const pm_node_flags_t PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY = ((PM_CALL_NODE_FLAGS_LAST - 1) << 1);
2551static const pm_node_flags_t PM_CALL_NODE_FLAGS_COMPARISON = ((PM_CALL_NODE_FLAGS_LAST - 1) << 2);
2552static const pm_node_flags_t PM_CALL_NODE_FLAGS_INDEX = ((PM_CALL_NODE_FLAGS_LAST - 1) << 3);
2559static pm_call_node_t *
2560pm_call_node_create(pm_parser_t *parser, pm_node_flags_t flags) {
2561 pm_call_node_t *node = PM_NODE_ALLOC(parser, pm_call_node_t);
2563 *node = (pm_call_node_t) {
2564 .base = PM_NODE_INIT_BASE(parser, PM_CALL_NODE, flags),
2566 .call_operator_loc = { 0 },
2567 .message_loc = { 0 },
2568 .opening_loc = { 0 },
2570 .closing_loc = { 0 },
2583static inline pm_node_flags_t
2584pm_call_node_ignore_visibility_flag(const pm_node_t *receiver) {
2585 return PM_NODE_TYPE_P(receiver, PM_SELF_NODE) ? PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY : 0;
2592static pm_call_node_t *
2593pm_call_node_aref_create(pm_parser_t *parser, pm_node_t *receiver, pm_arguments_t *arguments) {
2594 pm_assert_value_expression(parser, receiver);
2596 pm_node_flags_t flags = pm_call_node_ignore_visibility_flag(receiver);
2597 if (arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_ARGUMENT_NODE)) {
2598 flags |= PM_CALL_NODE_FLAGS_INDEX;
2601 pm_call_node_t *node = pm_call_node_create(parser, flags);
2603 node->base.location.start = receiver->location.start;
2604 node->base.location.end = pm_arguments_end(arguments);
2606 node->receiver = receiver;
2607 node->message_loc.start = arguments->opening_loc.start;
2608 node->message_loc.end = arguments->closing_loc.end;
2610 node->opening_loc = arguments->opening_loc;
2611 node->arguments = arguments->arguments;
2612 node->closing_loc = arguments->closing_loc;
2613 node->block = arguments->block;
2615 node->name = pm_parser_constant_id_constant(parser, "[]", 2);
2622static pm_call_node_t *
2623pm_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) {
2624 pm_assert_value_expression(parser, receiver);
2625 pm_assert_value_expression(parser, argument);
2627 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver) | flags);
2629 node->base.location.start = MIN(receiver->location.start, argument->location.start);
2630 node->base.location.end = MAX(receiver->location.end, argument->location.end);
2632 node->receiver = receiver;
2633 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2635 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
2636 pm_arguments_node_arguments_append(arguments, argument);
2637 node->arguments = arguments;
2639 node->name = pm_parser_constant_id_token(parser, operator);
2643static const uint8_t * parse_operator_symbol_name(const pm_token_t *);
2648static pm_call_node_t *
2649pm_call_node_call_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_token_t *message, pm_arguments_t *arguments) {
2650 pm_assert_value_expression(parser, receiver);
2652 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2654 node->base.location.start = receiver->location.start;
2655 const uint8_t *end = pm_arguments_end(arguments);
2659 node->base.location.end = end;
2661 node->receiver = receiver;
2662 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2663 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2664 node->opening_loc = arguments->opening_loc;
2665 node->arguments = arguments->arguments;
2666 node->closing_loc = arguments->closing_loc;
2667 node->block = arguments->block;
2669 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2670 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2677 node->name = pm_parser_constant_id_location(parser, message->start, parse_operator_symbol_name(message));
2684static pm_call_node_t *
2685pm_call_node_call_synthesized_create(pm_parser_t *parser, pm_node_t *receiver, const char *message, pm_arguments_node_t *arguments) {
2686 pm_call_node_t *node = pm_call_node_create(parser, 0);
2687 node->base.location.start = parser->start;
2688 node->base.location.end = parser->end;
2690 node->receiver = receiver;
2691 node->call_operator_loc = (pm_location_t) { .start = NULL, .end = NULL };
2692 node->message_loc = (pm_location_t) { .start = NULL, .end = NULL };
2693 node->arguments = arguments;
2695 node->name = pm_parser_constant_id_constant(parser, message, strlen(message));
2703static pm_call_node_t *
2704pm_call_node_fcall_create(pm_parser_t *parser, pm_token_t *message, pm_arguments_t *arguments) {
2705 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2707 node->base.location.start = message->start;
2708 node->base.location.end = pm_arguments_end(arguments);
2710 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2711 node->opening_loc = arguments->opening_loc;
2712 node->arguments = arguments->arguments;
2713 node->closing_loc = arguments->closing_loc;
2714 node->block = arguments->block;
2716 node->name = pm_parser_constant_id_token(parser, message);
2724static pm_call_node_t *
2725pm_call_node_fcall_synthesized_create(pm_parser_t *parser, pm_arguments_node_t *arguments, pm_constant_id_t name) {
2726 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2728 node->base.location = PM_LOCATION_NULL_VALUE(parser);
2729 node->arguments = arguments;
2738static pm_call_node_t *
2739pm_call_node_not_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *message, pm_arguments_t *arguments) {
2740 pm_assert_value_expression(parser, receiver);
2741 if (receiver != NULL) pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
2743 pm_call_node_t *node = pm_call_node_create(parser, receiver == NULL ? 0 : pm_call_node_ignore_visibility_flag(receiver));
2745 node->base.location.start = message->start;
2746 if (arguments->closing_loc.start != NULL) {
2747 node->base.location.end = arguments->closing_loc.end;
2749 assert(receiver != NULL);
2750 node->base.location.end = receiver->location.end;
2753 node->receiver = receiver;
2754 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2755 node->opening_loc = arguments->opening_loc;
2756 node->arguments = arguments->arguments;
2757 node->closing_loc = arguments->closing_loc;
2759 node->name = pm_parser_constant_id_constant(parser, "!", 1);
2766static pm_call_node_t *
2767pm_call_node_shorthand_create(pm_parser_t *parser, pm_node_t *receiver, pm_token_t *operator, pm_arguments_t *arguments) {
2768 pm_assert_value_expression(parser, receiver);
2770 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2772 node->base.location.start = receiver->location.start;
2773 node->base.location.end = pm_arguments_end(arguments);
2775 node->receiver = receiver;
2776 node->call_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2777 node->opening_loc = arguments->opening_loc;
2778 node->arguments = arguments->arguments;
2779 node->closing_loc = arguments->closing_loc;
2780 node->block = arguments->block;
2782 if (operator->type == PM_TOKEN_AMPERSAND_DOT) {
2783 pm_node_flag_set(UP(node), PM_CALL_NODE_FLAGS_SAFE_NAVIGATION);
2786 node->name = pm_parser_constant_id_constant(parser, "call", 4);
2793static pm_call_node_t *
2794pm_call_node_unary_create(pm_parser_t *parser, pm_token_t *operator, pm_node_t *receiver, const char *name) {
2795 pm_assert_value_expression(parser, receiver);
2797 pm_call_node_t *node = pm_call_node_create(parser, pm_call_node_ignore_visibility_flag(receiver));
2799 node->base.location.start = operator->start;
2800 node->base.location.end = receiver->location.end;
2802 node->receiver = receiver;
2803 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
2805 node->name = pm_parser_constant_id_constant(parser, name, strlen(name));
2813static pm_call_node_t *
2814pm_call_node_variable_call_create(pm_parser_t *parser, pm_token_t *message) {
2815 pm_call_node_t *node = pm_call_node_create(parser, PM_CALL_NODE_FLAGS_IGNORE_VISIBILITY);
2817 node->base.location = PM_LOCATION_TOKEN_VALUE(message);
2818 node->message_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(message);
2820 node->name = pm_parser_constant_id_token(parser, message);
2829pm_call_node_writable_p(const pm_parser_t *parser, const pm_call_node_t *node) {
2831 (node->message_loc.start != NULL) &&
2832 (node->message_loc.end[-1] != '!') &&
2833 (node->message_loc.end[-1] != '?') &&
2834 char_is_identifier_start(parser, node->message_loc.start, parser->end - node->message_loc.start) &&
2835 (node->opening_loc.start == NULL) &&
2836 (node->arguments == NULL) &&
2837 (node->block == NULL)
2845pm_call_write_read_name_init(pm_parser_t *parser, pm_constant_id_t *read_name, pm_constant_id_t *write_name) {
2846 pm_constant_t *write_constant = pm_constant_pool_id_to_constant(&parser->constant_pool, *write_name);
2848 if (write_constant->length > 0) {
2849 size_t length = write_constant->length - 1;
2851 void *memory = xmalloc(length);
2852 memcpy(memory, write_constant->start, length);
2854 *read_name = pm_constant_pool_insert_owned(&parser->constant_pool, (uint8_t *) memory, length);
2856 // We can get here if the message was missing because of a syntax error.
2857 *read_name = pm_parser_constant_id_constant(parser, "", 0);
2864static pm_call_and_write_node_t *
2865pm_call_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2866 assert(target->block == NULL);
2867 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2868 pm_call_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_and_write_node_t);
2870 *node = (pm_call_and_write_node_t) {
2871 .base = PM_NODE_INIT_NODES(parser, PM_CALL_AND_WRITE_NODE, FL(target), target, value),
2872 .receiver = target->receiver,
2873 .call_operator_loc = target->call_operator_loc,
2874 .message_loc = target->message_loc,
2876 .write_name = target->name,
2877 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2881 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2883 // Here we're going to free the target, since it is no longer necessary.
2884 // However, we don't want to call `pm_node_destroy` because we want to keep
2885 // around all of its children since we just reused them.
2896pm_index_arguments_check(pm_parser_t *parser, const pm_arguments_node_t *arguments, const pm_node_t *block) {
2897 if (parser->version >= PM_OPTIONS_VERSION_CRUBY_3_4) {
2898 if (arguments != NULL && PM_NODE_FLAG_P(arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS)) {
2900 PM_NODE_LIST_FOREACH(&arguments->arguments, index, node) {
2901 if (PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE)) {
2902 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_INDEX_KEYWORDS);
2908 if (block != NULL) {
2909 pm_parser_err_node(parser, block, PM_ERR_UNEXPECTED_INDEX_BLOCK);
2917static pm_index_and_write_node_t *
2918pm_index_and_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2919 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
2920 pm_index_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_and_write_node_t);
2922 pm_index_arguments_check(parser, target->arguments, target->block);
2924 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2925 *node = (pm_index_and_write_node_t) {
2926 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_AND_WRITE_NODE, FL(target), target, value),
2927 .receiver = target->receiver,
2928 .call_operator_loc = target->call_operator_loc,
2929 .opening_loc = target->opening_loc,
2930 .arguments = target->arguments,
2931 .closing_loc = target->closing_loc,
2932 .block = (pm_block_argument_node_t *) target->block,
2933 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2937 // Here we're going to free the target, since it is no longer necessary.
2938 // However, we don't want to call `pm_node_destroy` because we want to keep
2939 // around all of its children since we just reused them.
2948static pm_call_operator_write_node_t *
2949pm_call_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2950 assert(target->block == NULL);
2951 pm_call_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_operator_write_node_t);
2953 *node = (pm_call_operator_write_node_t) {
2954 .base = PM_NODE_INIT_NODES(parser, PM_CALL_OPERATOR_WRITE_NODE, FL(target), target, value),
2955 .receiver = target->receiver,
2956 .call_operator_loc = target->call_operator_loc,
2957 .message_loc = target->message_loc,
2959 .write_name = target->name,
2960 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
2961 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2965 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
2967 // Here we're going to free the target, since it is no longer necessary.
2968 // However, we don't want to call `pm_node_destroy` because we want to keep
2969 // around all of its children since we just reused them.
2978static pm_index_operator_write_node_t *
2979pm_index_operator_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
2980 pm_index_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_operator_write_node_t);
2982 pm_index_arguments_check(parser, target->arguments, target->block);
2984 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
2985 *node = (pm_index_operator_write_node_t) {
2986 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_OPERATOR_WRITE_NODE, FL(target), target, value),
2987 .receiver = target->receiver,
2988 .call_operator_loc = target->call_operator_loc,
2989 .opening_loc = target->opening_loc,
2990 .arguments = target->arguments,
2991 .closing_loc = target->closing_loc,
2992 .block = (pm_block_argument_node_t *) target->block,
2993 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
2994 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
2998 // Here we're going to free the target, since it is no longer necessary.
2999 // However, we don't want to call `pm_node_destroy` because we want to keep
3000 // around all of its children since we just reused them.
3009static pm_call_or_write_node_t *
3010pm_call_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3011 assert(target->block == NULL);
3012 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3013 pm_call_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_call_or_write_node_t);
3015 *node = (pm_call_or_write_node_t) {
3016 .base = PM_NODE_INIT_NODES(parser, PM_CALL_OR_WRITE_NODE, FL(target), target, value),
3017 .receiver = target->receiver,
3018 .call_operator_loc = target->call_operator_loc,
3019 .message_loc = target->message_loc,
3021 .write_name = target->name,
3022 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3026 pm_call_write_read_name_init(parser, &node->read_name, &node->write_name);
3028 // Here we're going to free the target, since it is no longer necessary.
3029 // However, we don't want to call `pm_node_destroy` because we want to keep
3030 // around all of its children since we just reused them.
3039static pm_index_or_write_node_t *
3040pm_index_or_write_node_create(pm_parser_t *parser, pm_call_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3041 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3042 pm_index_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_index_or_write_node_t);
3044 pm_index_arguments_check(parser, target->arguments, target->block);
3046 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3047 *node = (pm_index_or_write_node_t) {
3048 .base = PM_NODE_INIT_NODES(parser, PM_INDEX_OR_WRITE_NODE, FL(target), target, value),
3049 .receiver = target->receiver,
3050 .call_operator_loc = target->call_operator_loc,
3051 .opening_loc = target->opening_loc,
3052 .arguments = target->arguments,
3053 .closing_loc = target->closing_loc,
3054 .block = (pm_block_argument_node_t *) target->block,
3055 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3059 // Here we're going to free the target, since it is no longer necessary.
3060 // However, we don't want to call `pm_node_destroy` because we want to keep
3061 // around all of its children since we just reused them.
3071static pm_call_target_node_t *
3072pm_call_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3073 pm_call_target_node_t *node = PM_NODE_ALLOC(parser, pm_call_target_node_t);
3075 *node = (pm_call_target_node_t) {
3076 .base = PM_NODE_INIT_NODE(parser, PM_CALL_TARGET_NODE, FL(target), target),
3077 .receiver = target->receiver,
3078 .call_operator_loc = target->call_operator_loc,
3079 .name = target->name,
3080 .message_loc = target->message_loc
3083 /* It is possible to get here where we have parsed an invalid syntax tree
3084 * where the call operator was not present. In that case we will have a
3085 * problem because it is a required location. In this case we need to fill
3086 * it in with a fake location so that the syntax tree remains valid. */
3087 if (node->call_operator_loc.start == NULL) {
3088 node->call_operator_loc = (pm_location_t) {
3089 .start = target->base.location.start,
3090 .end = target->base.location.start
3094 // Here we're going to free the target, since it is no longer necessary.
3095 // However, we don't want to call `pm_node_destroy` because we want to keep
3096 // around all of its children since we just reused them.
3106static pm_index_target_node_t *
3107pm_index_target_node_create(pm_parser_t *parser, pm_call_node_t *target) {
3108 pm_index_target_node_t *node = PM_NODE_ALLOC(parser, pm_index_target_node_t);
3110 pm_index_arguments_check(parser, target->arguments, target->block);
3111 assert(!target->block || PM_NODE_TYPE_P(target->block, PM_BLOCK_ARGUMENT_NODE));
3113 *node = (pm_index_target_node_t) {
3114 .base = PM_NODE_INIT_NODE(parser, PM_INDEX_TARGET_NODE, FL(target) | PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE, target),
3115 .receiver = target->receiver,
3116 .opening_loc = target->opening_loc,
3117 .arguments = target->arguments,
3118 .closing_loc = target->closing_loc,
3119 .block = (pm_block_argument_node_t *) target->block,
3122 // Here we're going to free the target, since it is no longer necessary.
3123 // However, we don't want to call `pm_node_destroy` because we want to keep
3124 // around all of its children since we just reused them.
3133static pm_capture_pattern_node_t *
3134pm_capture_pattern_node_create(pm_parser_t *parser, pm_node_t *value, pm_local_variable_target_node_t *target, const pm_token_t *operator) {
3135 pm_capture_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_capture_pattern_node_t);
3137 *node = (pm_capture_pattern_node_t) {
3138 .base = PM_NODE_INIT_NODES(parser, PM_CAPTURE_PATTERN_NODE, 0, value, target),
3141 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
3150static pm_case_node_t *
3151pm_case_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3152 pm_case_node_t *node = PM_NODE_ALLOC(parser, pm_case_node_t);
3154 *node = (pm_case_node_t) {
3155 .base = PM_NODE_INIT_TOKENS(parser, PM_CASE_NODE, 0, case_keyword, end_keyword),
3156 .predicate = predicate,
3157 .else_clause = NULL,
3158 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3159 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3170pm_case_node_condition_append(pm_case_node_t *node, pm_node_t *condition) {
3171 assert(PM_NODE_TYPE_P(condition, PM_WHEN_NODE));
3173 pm_node_list_append(&node->conditions, condition);
3174 node->base.location.end = condition->location.end;
3181pm_case_node_else_clause_set(pm_case_node_t *node, pm_else_node_t *else_clause) {
3182 node->else_clause = else_clause;
3183 node->base.location.end = else_clause->base.location.end;
3190pm_case_node_end_keyword_loc_set(pm_case_node_t *node, const pm_token_t *end_keyword) {
3191 node->base.location.end = end_keyword->end;
3192 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3198static pm_case_match_node_t *
3199pm_case_match_node_create(pm_parser_t *parser, const pm_token_t *case_keyword, pm_node_t *predicate, const pm_token_t *end_keyword) {
3200 pm_case_match_node_t *node = PM_NODE_ALLOC(parser, pm_case_match_node_t);
3202 *node = (pm_case_match_node_t) {
3203 .base = PM_NODE_INIT_TOKENS(parser, PM_CASE_MATCH_NODE, 0, case_keyword, end_keyword),
3204 .predicate = predicate,
3205 .else_clause = NULL,
3206 .case_keyword_loc = PM_LOCATION_TOKEN_VALUE(case_keyword),
3207 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3218pm_case_match_node_condition_append(pm_case_match_node_t *node, pm_node_t *condition) {
3219 assert(PM_NODE_TYPE_P(condition, PM_IN_NODE));
3221 pm_node_list_append(&node->conditions, condition);
3222 node->base.location.end = condition->location.end;
3229pm_case_match_node_else_clause_set(pm_case_match_node_t *node, pm_else_node_t *else_clause) {
3230 node->else_clause = else_clause;
3231 node->base.location.end = else_clause->base.location.end;
3238pm_case_match_node_end_keyword_loc_set(pm_case_match_node_t *node, const pm_token_t *end_keyword) {
3239 node->base.location.end = end_keyword->end;
3240 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
3246static pm_class_node_t *
3247pm_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) {
3248 pm_class_node_t *node = PM_NODE_ALLOC(parser, pm_class_node_t);
3250 *node = (pm_class_node_t) {
3251 .base = PM_NODE_INIT_TOKENS(parser, PM_CLASS_NODE, 0, class_keyword, end_keyword),
3253 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
3254 .constant_path = constant_path,
3255 .inheritance_operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(inheritance_operator),
3256 .superclass = superclass,
3258 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
3259 .name = pm_parser_constant_id_token(parser, name)
3268static pm_class_variable_and_write_node_t *
3269pm_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) {
3270 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3271 pm_class_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_and_write_node_t);
3273 *node = (pm_class_variable_and_write_node_t) {
3274 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_AND_WRITE_NODE, 0, target, value),
3275 .name = target->name,
3276 .name_loc = target->base.location,
3277 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3287static pm_class_variable_operator_write_node_t *
3288pm_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) {
3289 pm_class_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_operator_write_node_t);
3291 *node = (pm_class_variable_operator_write_node_t) {
3292 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
3293 .name = target->name,
3294 .name_loc = target->base.location,
3295 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3297 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3306static pm_class_variable_or_write_node_t *
3307pm_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) {
3308 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3309 pm_class_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_or_write_node_t);
3311 *node = (pm_class_variable_or_write_node_t) {
3312 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_OR_WRITE_NODE, 0, target, value),
3313 .name = target->name,
3314 .name_loc = target->base.location,
3315 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3325static pm_class_variable_read_node_t *
3326pm_class_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
3327 assert(token->type == PM_TOKEN_CLASS_VARIABLE);
3328 pm_class_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_read_node_t);
3330 *node = (pm_class_variable_read_node_t) {
3331 .base = PM_NODE_INIT_TOKEN(parser, PM_CLASS_VARIABLE_READ_NODE, 0, token),
3332 .name = pm_parser_constant_id_token(parser, token)
3344static inline pm_node_flags_t
3345pm_implicit_array_write_flags(const pm_node_t *node, pm_node_flags_t flags) {
3346 if (PM_NODE_TYPE_P(node, PM_ARRAY_NODE) && ((const pm_array_node_t *) node)->opening_loc.start == NULL) {
3355static pm_class_variable_write_node_t *
3356pm_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) {
3357 pm_class_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_class_variable_write_node_t);
3358 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3360 *node = (pm_class_variable_write_node_t) {
3361 .base = PM_NODE_INIT_NODES(parser, PM_CLASS_VARIABLE_WRITE_NODE, flags, read_node, value),
3362 .name = read_node->name,
3363 .name_loc = PM_LOCATION_NODE_VALUE(UP(read_node)),
3364 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3374static pm_constant_path_and_write_node_t *
3375pm_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) {
3376 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3377 pm_constant_path_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_and_write_node_t);
3379 *node = (pm_constant_path_and_write_node_t) {
3380 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_AND_WRITE_NODE, 0, target, value),
3382 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3392static pm_constant_path_operator_write_node_t *
3393pm_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) {
3394 pm_constant_path_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_operator_write_node_t);
3396 *node = (pm_constant_path_operator_write_node_t) {
3397 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_OPERATOR_WRITE_NODE, 0, target, value),
3399 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3401 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3410static pm_constant_path_or_write_node_t *
3411pm_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) {
3412 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3413 pm_constant_path_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_or_write_node_t);
3415 *node = (pm_constant_path_or_write_node_t) {
3416 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_OR_WRITE_NODE, 0, target, value),
3418 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3428static pm_constant_path_node_t *
3429pm_constant_path_node_create(pm_parser_t *parser, pm_node_t *parent, const pm_token_t *delimiter, const pm_token_t *name_token) {
3430 pm_assert_value_expression(parser, parent);
3431 pm_constant_path_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_node_t);
3433 pm_constant_id_t name = PM_CONSTANT_ID_UNSET;
3434 if (name_token->type == PM_TOKEN_CONSTANT) {
3435 name = pm_parser_constant_id_token(parser, name_token);
3438 if (parent == NULL) {
3439 *node = (pm_constant_path_node_t) {
3440 .base = PM_NODE_INIT_TOKENS(parser, PM_CONSTANT_PATH_NODE, 0, delimiter, name_token),
3443 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3444 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3447 *node = (pm_constant_path_node_t) {
3448 .base = PM_NODE_INIT_NODE_TOKEN(parser, PM_CONSTANT_PATH_NODE, 0, parent, name_token),
3451 .delimiter_loc = PM_LOCATION_TOKEN_VALUE(delimiter),
3452 .name_loc = PM_LOCATION_TOKEN_VALUE(name_token)
3462static pm_constant_path_write_node_t *
3463pm_constant_path_write_node_create(pm_parser_t *parser, pm_constant_path_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3464 pm_constant_path_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_path_write_node_t);
3465 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3467 *node = (pm_constant_path_write_node_t) {
3468 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_PATH_WRITE_NODE, flags, target, value),
3470 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3480static pm_constant_and_write_node_t *
3481pm_constant_and_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3482 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
3483 pm_constant_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_and_write_node_t);
3485 *node = (pm_constant_and_write_node_t) {
3486 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_AND_WRITE_NODE, 0, target, value),
3487 .name = target->name,
3488 .name_loc = target->base.location,
3489 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3499static pm_constant_operator_write_node_t *
3500pm_constant_operator_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3501 pm_constant_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_operator_write_node_t);
3503 *node = (pm_constant_operator_write_node_t) {
3504 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_OPERATOR_WRITE_NODE, 0, target, value),
3505 .name = target->name,
3506 .name_loc = target->base.location,
3507 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3509 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
3518static pm_constant_or_write_node_t *
3519pm_constant_or_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3520 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
3521 pm_constant_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_or_write_node_t);
3523 *node = (pm_constant_or_write_node_t) {
3524 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_OR_WRITE_NODE, 0, target, value),
3525 .name = target->name,
3526 .name_loc = target->base.location,
3527 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3537static pm_constant_read_node_t *
3538pm_constant_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
3539 assert(name->type == PM_TOKEN_CONSTANT || name->type == PM_TOKEN_MISSING);
3540 pm_constant_read_node_t *node = PM_NODE_ALLOC(parser, pm_constant_read_node_t);
3542 *node = (pm_constant_read_node_t) {
3543 .base = PM_NODE_INIT_TOKEN(parser, PM_CONSTANT_READ_NODE, 0, name),
3544 .name = pm_parser_constant_id_token(parser, name)
3553static pm_constant_write_node_t *
3554pm_constant_write_node_create(pm_parser_t *parser, pm_constant_read_node_t *target, const pm_token_t *operator, pm_node_t *value) {
3555 pm_constant_write_node_t *node = PM_NODE_ALLOC(parser, pm_constant_write_node_t);
3556 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
3558 *node = (pm_constant_write_node_t) {
3559 .base = PM_NODE_INIT_NODES(parser, PM_CONSTANT_WRITE_NODE, flags, target, value),
3560 .name = target->name,
3561 .name_loc = target->base.location,
3562 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3573pm_def_node_receiver_check(pm_parser_t *parser, const pm_node_t *node) {
3574 switch (PM_NODE_TYPE(node)) {
3575 case PM_BEGIN_NODE: {
3576 const pm_begin_node_t *cast = (pm_begin_node_t *) node;
3577 if (cast->statements != NULL) pm_def_node_receiver_check(parser, UP(cast->statements));
3580 case PM_PARENTHESES_NODE: {
3581 const pm_parentheses_node_t *cast = (const pm_parentheses_node_t *) node;
3582 if (cast->body != NULL) pm_def_node_receiver_check(parser, cast->body);
3585 case PM_STATEMENTS_NODE: {
3586 const pm_statements_node_t *cast = (const pm_statements_node_t *) node;
3587 pm_def_node_receiver_check(parser, cast->body.nodes[cast->body.size - 1]);
3592 case PM_IMAGINARY_NODE:
3593 case PM_INTEGER_NODE:
3594 case PM_INTERPOLATED_REGULAR_EXPRESSION_NODE:
3595 case PM_INTERPOLATED_STRING_NODE:
3596 case PM_INTERPOLATED_SYMBOL_NODE:
3597 case PM_INTERPOLATED_X_STRING_NODE:
3598 case PM_RATIONAL_NODE:
3599 case PM_REGULAR_EXPRESSION_NODE:
3600 case PM_SOURCE_ENCODING_NODE:
3601 case PM_SOURCE_FILE_NODE:
3602 case PM_SOURCE_LINE_NODE:
3603 case PM_STRING_NODE:
3604 case PM_SYMBOL_NODE:
3605 case PM_X_STRING_NODE:
3606 pm_parser_err_node(parser, node, PM_ERR_SINGLETON_FOR_LITERALS);
3616static pm_def_node_t *
3618 pm_parser_t *parser,
3619 pm_constant_id_t name,
3620 const pm_token_t *name_loc,
3621 pm_node_t *receiver,
3622 pm_parameters_node_t *parameters,
3624 pm_constant_id_list_t *locals,
3625 const pm_token_t *def_keyword,
3626 const pm_token_t *operator,
3627 const pm_token_t *lparen,
3628 const pm_token_t *rparen,
3629 const pm_token_t *equal,
3630 const pm_token_t *end_keyword
3632 pm_def_node_t *node = PM_NODE_ALLOC(parser, pm_def_node_t);
3634 if (receiver != NULL) {
3635 pm_def_node_receiver_check(parser, receiver);
3638 *node = (pm_def_node_t) {
3640 (end_keyword->type == PM_TOKEN_NOT_PROVIDED)
3641 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_DEF_NODE, 0, def_keyword, body)
3642 : PM_NODE_INIT_TOKENS(parser, PM_DEF_NODE, 0, def_keyword, end_keyword)
3645 .name_loc = PM_LOCATION_TOKEN_VALUE(name_loc),
3646 .receiver = receiver,
3647 .parameters = parameters,
3650 .def_keyword_loc = PM_LOCATION_TOKEN_VALUE(def_keyword),
3651 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
3652 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3653 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3654 .equal_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(equal),
3655 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3664static pm_defined_node_t *
3665pm_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) {
3666 pm_defined_node_t *node = PM_NODE_ALLOC(parser, pm_defined_node_t);
3668 *node = (pm_defined_node_t) {
3670 (rparen->type == PM_TOKEN_NOT_PROVIDED)
3671 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_DEFINED_NODE, 0, keyword, value)
3672 : PM_NODE_INIT_TOKENS(parser, PM_DEFINED_NODE, 0, keyword, rparen)
3674 .lparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(lparen),
3676 .rparen_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(rparen),
3677 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
3686static pm_else_node_t *
3687pm_else_node_create(pm_parser_t *parser, const pm_token_t *else_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3688 pm_else_node_t *node = PM_NODE_ALLOC(parser, pm_else_node_t);
3690 *node = (pm_else_node_t) {
3692 ((end_keyword->type == PM_TOKEN_NOT_PROVIDED) && (statements != NULL))
3693 ? PM_NODE_INIT_TOKEN_NODE(parser, PM_ELSE_NODE, 0, else_keyword, statements)
3694 : PM_NODE_INIT_TOKENS(parser, PM_ELSE_NODE, 0, else_keyword, end_keyword)
3696 .else_keyword_loc = PM_LOCATION_TOKEN_VALUE(else_keyword),
3697 .statements = statements,
3698 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
3707static pm_embedded_statements_node_t *
3708pm_embedded_statements_node_create(pm_parser_t *parser, const pm_token_t *opening, pm_statements_node_t *statements, const pm_token_t *closing) {
3709 pm_embedded_statements_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_statements_node_t);
3711 *node = (pm_embedded_statements_node_t) {
3712 .base = PM_NODE_INIT_TOKENS(parser, PM_EMBEDDED_STATEMENTS_NODE, 0, opening, closing),
3713 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
3714 .statements = statements,
3715 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
3724static pm_embedded_variable_node_t *
3725pm_embedded_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
3726 pm_embedded_variable_node_t *node = PM_NODE_ALLOC(parser, pm_embedded_variable_node_t);
3728 *node = (pm_embedded_variable_node_t) {
3729 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_EMBEDDED_VARIABLE_NODE, 0, operator, variable),
3730 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
3731 .variable = variable
3740static pm_ensure_node_t *
3741pm_ensure_node_create(pm_parser_t *parser, const pm_token_t *ensure_keyword, pm_statements_node_t *statements, const pm_token_t *end_keyword) {
3742 pm_ensure_node_t *node = PM_NODE_ALLOC(parser, pm_ensure_node_t);
3744 *node = (pm_ensure_node_t) {
3745 .base = PM_NODE_INIT_TOKENS(parser, PM_ENSURE_NODE, 0, ensure_keyword, end_keyword),
3746 .ensure_keyword_loc = PM_LOCATION_TOKEN_VALUE(ensure_keyword),
3747 .statements = statements,
3748 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
3757static pm_false_node_t *
3758pm_false_node_create(pm_parser_t *parser, const pm_token_t *token) {
3759 assert(token->type == PM_TOKEN_KEYWORD_FALSE);
3760 pm_false_node_t *node = PM_NODE_ALLOC(parser, pm_false_node_t);
3762 *node = (pm_false_node_t) {
3763 .base = PM_NODE_INIT_TOKEN(parser, PM_FALSE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
3773static pm_find_pattern_node_t *
3774pm_find_pattern_node_create(pm_parser_t *parser, pm_node_list_t *nodes) {
3775 pm_find_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_find_pattern_node_t);
3777 pm_node_t *left = nodes->nodes[0];
3778 assert(PM_NODE_TYPE_P(left, PM_SPLAT_NODE));
3779 pm_splat_node_t *left_splat_node = (pm_splat_node_t *) left;
3783 if (nodes->size == 1) {
3784 right = UP(pm_missing_node_create(parser, left->location.end, left->location.end));
3786 right = nodes->nodes[nodes->size - 1];
3787 assert(PM_NODE_TYPE_P(right, PM_SPLAT_NODE));
3790#if PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS
3791 // FindPatternNode#right is typed as SplatNode in this case, so replace the potential MissingNode with a SplatNode.
3792 // The resulting AST will anyway be ignored, but this file still needs to compile.
3793 pm_splat_node_t *right_splat_node = PM_NODE_TYPE_P(right, PM_SPLAT_NODE) ? (pm_splat_node_t *) right : left_splat_node;
3795 pm_node_t *right_splat_node = right;
3797 *node = (pm_find_pattern_node_t) {
3798 .base = PM_NODE_INIT_NODES(parser, PM_FIND_PATTERN_NODE, 0, left, right),
3800 .left = left_splat_node,
3801 .right = right_splat_node,
3803 .opening_loc = { 0 },
3804 .closing_loc = { 0 }
3807 // For now we're going to just copy over each pointer manually. This could be
3808 // much more efficient, as we could instead resize the node list to only point
3810 for (size_t index = 1; index < nodes->size - 1; index++) {
3811 pm_node_list_append(&node->requireds, nodes->nodes[index]);
3822pm_double_parse(pm_parser_t *parser, const pm_token_t *token) {
3823 ptrdiff_t diff = token->end - token->start;
3824 if (diff <= 0) return 0.0;
3826 // First, get a buffer of the content.
3827 size_t length = (size_t) diff;
3828 char *buffer = xmalloc(sizeof(char) * (length + 1));
3829 memcpy((void *) buffer, token->start, length);
3831 // Next, determine if we need to replace the decimal point because of
3832 // locale-specific options, and then normalize them if we have to.
3833 char decimal_point = *localeconv()->decimal_point;
3834 if (decimal_point != '.') {
3835 for (size_t index = 0; index < length; index++) {
3836 if (buffer[index] == '.') buffer[index] = decimal_point;
3840 // Next, handle underscores by removing them from the buffer.
3841 for (size_t index = 0; index < length; index++) {
3842 if (buffer[index] == '_') {
3843 memmove((void *) (buffer + index), (void *) (buffer + index + 1), length - index);
3848 // Null-terminate the buffer so that strtod cannot read off the end.
3849 buffer[length] = '\0';
3851 // Now, call strtod to parse the value. Note that CRuby has their own
3852 // version of strtod which avoids locales. We're okay using the locale-aware
3853 // version because we've already validated through the parser that the token
3854 // is in a valid format.
3857 double value = strtod(buffer, &eptr);
3859 // This should never happen, because we've already checked that the token
3860 // is in a valid format. However it's good to be safe.
3861 if ((eptr != buffer + length) || (errno != 0 && errno != ERANGE)) {
3862 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, (*token), PM_ERR_FLOAT_PARSE);
3863 xfree((void *) buffer);
3867 // If errno is set, then it should only be ERANGE. At this point we need to
3868 // check if it's infinity (it should be).
3869 if (errno == ERANGE && PRISM_ISINF(value)) {
3871 const char *ellipsis;
3877 warn_width = (int) length;
3881 pm_diagnostic_list_append_format(&parser->warning_list, token->start, token->end, PM_WARN_FLOAT_OUT_OF_RANGE, warn_width, (const char *) token->start, ellipsis);
3882 value = (value < 0.0) ? -HUGE_VAL : HUGE_VAL;
3885 // Finally we can free the buffer and return the value.
3886 xfree((void *) buffer);
3893static pm_float_node_t *
3894pm_float_node_create(pm_parser_t *parser, const pm_token_t *token) {
3895 assert(token->type == PM_TOKEN_FLOAT);
3896 pm_float_node_t *node = PM_NODE_ALLOC(parser, pm_float_node_t);
3898 *node = (pm_float_node_t) {
3899 .base = PM_NODE_INIT_TOKEN(parser, PM_FLOAT_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3900 .value = pm_double_parse(parser, token)
3909static pm_imaginary_node_t *
3910pm_float_node_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3911 assert(token->type == PM_TOKEN_FLOAT_IMAGINARY);
3913 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3914 *node = (pm_imaginary_node_t) {
3915 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3916 .numeric = UP(pm_float_node_create(parser, &((pm_token_t) {
3917 .type = PM_TOKEN_FLOAT,
3918 .start = token->start,
3919 .end = token->end - 1
3929static pm_rational_node_t *
3930pm_float_node_rational_create(pm_parser_t *parser, const pm_token_t *token) {
3931 assert(token->type == PM_TOKEN_FLOAT_RATIONAL);
3933 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
3934 *node = (pm_rational_node_t) {
3935 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, PM_INTEGER_BASE_FLAGS_DECIMAL | PM_NODE_FLAG_STATIC_LITERAL, token),
3937 .denominator = { 0 }
3940 const uint8_t *start = token->start;
3941 const uint8_t *end = token->end - 1; // r
3943 while (start < end && *start == '0') start++; // 0.1 -> .1
3944 while (end > start && end[-1] == '0') end--; // 1.0 -> 1.
3946 size_t length = (size_t) (end - start);
3948 node->denominator.value = 1;
3952 const uint8_t *point = memchr(start, '.', length);
3953 assert(point && "should have a decimal point");
3955 uint8_t *digits = xmalloc(length);
3956 if (digits == NULL) {
3957 fputs("[pm_float_node_rational_create] Failed to allocate memory", stderr);
3961 memcpy(digits, start, (unsigned long) (point - start));
3962 memcpy(digits + (point - start), point + 1, (unsigned long) (end - point - 1));
3963 pm_integer_parse(&node->numerator, PM_INTEGER_BASE_DEFAULT, digits, digits + length - 1);
3965 size_t fract_length = 0;
3966 for (const uint8_t *fract = point; fract < end; ++fract) {
3967 if (*fract != '_') ++fract_length;
3970 if (fract_length > 1) memset(digits + 1, '0', fract_length - 1);
3971 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + fract_length);
3974 pm_integers_reduce(&node->numerator, &node->denominator);
3982static pm_imaginary_node_t *
3983pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3984 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
3986 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3987 *node = (pm_imaginary_node_t) {
3988 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3989 .numeric = UP(pm_float_node_rational_create(parser, &((pm_token_t) {
3990 .type = PM_TOKEN_FLOAT_RATIONAL,
3991 .start = token->start,
3992 .end = token->end - 1
4002static pm_for_node_t *
4004 pm_parser_t *parser,
4006 pm_node_t *collection,
4007 pm_statements_node_t *statements,
4008 const pm_token_t *for_keyword,
4009 const pm_token_t *in_keyword,
4010 const pm_token_t *do_keyword,
4011 const pm_token_t *end_keyword
4013 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4015 *node = (pm_for_node_t) {
4016 .base = PM_NODE_INIT_TOKENS(parser, PM_FOR_NODE, 0, for_keyword, end_keyword),
4018 .collection = collection,
4019 .statements = statements,
4020 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4021 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4022 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4023 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4032static pm_forwarding_arguments_node_t *
4033pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4034 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4035 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4037 *node = (pm_forwarding_arguments_node_t) {
4038 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_ARGUMENTS_NODE, 0, token)
4047static pm_forwarding_parameter_node_t *
4048pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4049 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4050 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4052 *node = (pm_forwarding_parameter_node_t) {
4053 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_PARAMETER_NODE, 0, token)
4062static pm_forwarding_super_node_t *
4063pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4064 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4065 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4066 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4068 pm_block_node_t *block = NULL;
4069 if (arguments->block != NULL) {
4070 block = (pm_block_node_t *) arguments->block;
4073 *node = (pm_forwarding_super_node_t) {
4076 ? PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_SUPER_NODE, 0, token)
4077 : PM_NODE_INIT_TOKEN_NODE(parser, PM_FORWARDING_SUPER_NODE, 0, token, block)
4089static pm_hash_pattern_node_t *
4090pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4091 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4093 *node = (pm_hash_pattern_node_t) {
4094 .base = PM_NODE_INIT_TOKENS(parser, PM_HASH_PATTERN_NODE, 0, opening, closing),
4096 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4097 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4108static pm_hash_pattern_node_t *
4109pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4110 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4112 const uint8_t *start;
4115 if (elements->size > 0) {
4117 start = MIN(rest->location.start, elements->nodes[0]->location.start);
4118 end = MAX(rest->location.end, elements->nodes[elements->size - 1]->location.end);
4120 start = elements->nodes[0]->location.start;
4121 end = elements->nodes[elements->size - 1]->location.end;
4124 assert(rest != NULL);
4125 start = rest->location.start;
4126 end = rest->location.end;
4129 *node = (pm_hash_pattern_node_t) {
4130 .base = PM_NODE_INIT(parser, PM_HASH_PATTERN_NODE, 0, start, end),
4134 .opening_loc = { 0 },
4135 .closing_loc = { 0 }
4138 pm_node_list_concat(&node->elements, elements);
4145static pm_constant_id_t
4146pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4147 switch (PM_NODE_TYPE(target)) {
4148 case PM_GLOBAL_VARIABLE_READ_NODE:
4149 return ((pm_global_variable_read_node_t *) target)->name;
4150 case PM_BACK_REFERENCE_READ_NODE:
4151 return ((pm_back_reference_read_node_t *) target)->name;
4152 case PM_NUMBERED_REFERENCE_READ_NODE:
4153 // This will only ever happen in the event of a syntax error, but we
4154 // still need to provide something for the node.
4155 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4157 assert(false && "unreachable");
4158 return (pm_constant_id_t) -1;
4165static pm_global_variable_and_write_node_t *
4166pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4167 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4168 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4170 *node = (pm_global_variable_and_write_node_t) {
4171 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
4172 .name = pm_global_variable_write_name(parser, target),
4173 .name_loc = target->location,
4174 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4184static pm_global_variable_operator_write_node_t *
4185pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4186 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4188 *node = (pm_global_variable_operator_write_node_t) {
4189 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4190 .name = pm_global_variable_write_name(parser, target),
4191 .name_loc = target->location,
4192 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4194 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4203static pm_global_variable_or_write_node_t *
4204pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4205 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4206 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4208 *node = (pm_global_variable_or_write_node_t) {
4209 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
4210 .name = pm_global_variable_write_name(parser, target),
4211 .name_loc = target->location,
4212 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4222static pm_global_variable_read_node_t *
4223pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4224 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4226 *node = (pm_global_variable_read_node_t) {
4227 .base = PM_NODE_INIT_TOKEN(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0, name),
4228 .name = pm_parser_constant_id_token(parser, name)
4237static pm_global_variable_read_node_t *
4238pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4239 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4241 *node = (pm_global_variable_read_node_t) {
4242 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0),
4252static pm_global_variable_write_node_t *
4253pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4254 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4255 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4257 *node = (pm_global_variable_write_node_t) {
4258 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, flags, target, value),
4259 .name = pm_global_variable_write_name(parser, target),
4260 .name_loc = PM_LOCATION_NODE_VALUE(target),
4261 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4271static pm_global_variable_write_node_t *
4272pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4273 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4275 *node = (pm_global_variable_write_node_t) {
4276 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, 0),
4278 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4279 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4289static pm_hash_node_t *
4290pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4291 assert(opening != NULL);
4292 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4294 *node = (pm_hash_node_t) {
4295 .base = PM_NODE_INIT_TOKEN(parser, PM_HASH_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4296 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4297 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4308pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4309 pm_node_list_append(&hash->elements, element);
4311 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4312 if (static_literal) {
4313 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4314 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);
4315 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4316 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4319 if (!static_literal) {
4320 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4325pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4326 hash->base.location.end = token->end;
4327 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4333static pm_if_node_t *
4334pm_if_node_create(pm_parser_t *parser,
4335 const pm_token_t *if_keyword,
4336 pm_node_t *predicate,
4337 const pm_token_t *then_keyword,
4338 pm_statements_node_t *statements,
4339 pm_node_t *subsequent,
4340 const pm_token_t *end_keyword
4342 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4343 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4346 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4347 end = end_keyword->end;
4348 } else if (subsequent != NULL) {
4349 end = subsequent->location.end;
4350 } else if (pm_statements_node_body_length(statements) != 0) {
4351 end = statements->base.location.end;
4353 end = predicate->location.end;
4356 *node = (pm_if_node_t) {
4357 .base = PM_NODE_INIT(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, if_keyword->start, end),
4358 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4359 .predicate = predicate,
4360 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4361 .statements = statements,
4362 .subsequent = subsequent,
4363 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4372static pm_if_node_t *
4373pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4374 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4375 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4377 pm_statements_node_t *statements = pm_statements_node_create(parser);
4378 pm_statements_node_body_append(parser, statements, statement, true);
4380 *node = (pm_if_node_t) {
4381 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
4382 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4383 .predicate = predicate,
4384 .then_keyword_loc = { 0 },
4385 .statements = statements,
4387 .end_keyword_loc = { 0 }
4396static pm_if_node_t *
4397pm_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) {
4398 pm_assert_value_expression(parser, predicate);
4399 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4401 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4402 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4404 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4405 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4407 pm_token_t end_keyword = not_provided(parser);
4408 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4410 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4412 *node = (pm_if_node_t) {
4413 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, predicate, false_expression),
4414 .if_keyword_loc = { 0 },
4415 .predicate = predicate,
4416 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4417 .statements = if_statements,
4418 .subsequent = UP(else_node),
4419 .end_keyword_loc = { 0 }
4427pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4428 node->base.location.end = keyword->end;
4429 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4433pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4434 node->base.location.end = keyword->end;
4435 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4441static pm_implicit_node_t *
4442pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4443 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4445 *node = (pm_implicit_node_t) {
4446 .base = PM_NODE_INIT_NODE(parser, PM_IMPLICIT_NODE, 0, value),
4456static pm_implicit_rest_node_t *
4457pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4458 assert(token->type == PM_TOKEN_COMMA);
4460 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4462 *node = (pm_implicit_rest_node_t) {
4463 .base = PM_NODE_INIT_TOKEN(parser, PM_IMPLICIT_REST_NODE, 0, token)
4472static pm_integer_node_t *
4473pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4474 assert(token->type == PM_TOKEN_INTEGER);
4475 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4477 *node = (pm_integer_node_t) {
4478 .base = PM_NODE_INIT_TOKEN(parser, PM_INTEGER_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4482 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4484 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4485 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4486 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4487 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4488 default: assert(false && "unreachable"); break;
4491 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4499static pm_imaginary_node_t *
4500pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4501 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4503 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4504 *node = (pm_imaginary_node_t) {
4505 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4506 .numeric = UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4507 .type = PM_TOKEN_INTEGER,
4508 .start = token->start,
4509 .end = token->end - 1
4520static pm_rational_node_t *
4521pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4522 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4524 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4525 *node = (pm_rational_node_t) {
4526 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4528 .denominator = { .value = 1, 0 }
4531 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4533 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4534 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4535 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4536 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4537 default: assert(false && "unreachable"); break;
4540 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4549static pm_imaginary_node_t *
4550pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4551 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4553 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4554 *node = (pm_imaginary_node_t) {
4555 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4556 .numeric = UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4557 .type = PM_TOKEN_INTEGER_RATIONAL,
4558 .start = token->start,
4559 .end = token->end - 1
4569static pm_in_node_t *
4570pm_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) {
4571 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4574 if (statements != NULL) {
4575 end = statements->base.location.end;
4576 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4577 end = then_keyword->end;
4579 end = pattern->location.end;
4582 *node = (pm_in_node_t) {
4583 .base = PM_NODE_INIT(parser, PM_IN_NODE, 0, in_keyword->start, end),
4585 .statements = statements,
4586 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4587 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
4596static pm_instance_variable_and_write_node_t *
4597pm_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) {
4598 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4599 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
4601 *node = (pm_instance_variable_and_write_node_t) {
4602 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_AND_WRITE_NODE, 0, target, value),
4603 .name = target->name,
4604 .name_loc = target->base.location,
4605 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4615static pm_instance_variable_operator_write_node_t *
4616pm_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) {
4617 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
4619 *node = (pm_instance_variable_operator_write_node_t) {
4620 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4621 .name = target->name,
4622 .name_loc = target->base.location,
4623 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4625 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4634static pm_instance_variable_or_write_node_t *
4635pm_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) {
4636 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4637 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
4639 *node = (pm_instance_variable_or_write_node_t) {
4640 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OR_WRITE_NODE, 0, target, value),
4641 .name = target->name,
4642 .name_loc = target->base.location,
4643 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4653static pm_instance_variable_read_node_t *
4654pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4655 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4656 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
4658 *node = (pm_instance_variable_read_node_t) {
4659 .base = PM_NODE_INIT_TOKEN(parser, PM_INSTANCE_VARIABLE_READ_NODE, 0, token),
4660 .name = pm_parser_constant_id_token(parser, token)
4670static pm_instance_variable_write_node_t *
4671pm_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) {
4672 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
4673 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4675 *node = (pm_instance_variable_write_node_t) {
4676 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_WRITE_NODE, flags, read_node, value),
4677 .name = read_node->name,
4678 .name_loc = PM_LOCATION_NODE_VALUE(read_node),
4679 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4692pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4693 switch (PM_NODE_TYPE(part)) {
4694 case PM_STRING_NODE:
4695 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4697 case PM_EMBEDDED_STATEMENTS_NODE: {
4698 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4699 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4701 if (embedded == NULL) {
4702 // If there are no statements or more than one statement, then
4703 // we lose the static literal flag.
4704 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4705 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4706 // If the embedded statement is a string, then we can keep the
4707 // static literal flag and mark the string as frozen.
4708 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4709 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4710 // If the embedded statement is an interpolated string and it's
4711 // a static literal, then we can keep the static literal flag.
4713 // Otherwise we lose the static literal flag.
4714 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4719 case PM_EMBEDDED_VARIABLE_NODE:
4720 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4723 assert(false && "unexpected node type");
4727 pm_node_list_append(parts, part);
4733static pm_interpolated_regular_expression_node_t *
4734pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4735 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
4737 *node = (pm_interpolated_regular_expression_node_t) {
4738 .base = PM_NODE_INIT_TOKEN(parser, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4739 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4740 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
4748pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
4749 if (node->base.location.start > part->location.start) {
4750 node->base.location.start = part->location.start;
4752 if (node->base.location.end < part->location.end) {
4753 node->base.location.end = part->location.end;
4756 pm_interpolated_node_append(UP(node), &node->parts, part);
4760pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
4761 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
4762 node->base.location.end = closing->end;
4763 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
4790pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
4791#define CLEAR_FLAGS(node) \
4792 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))
4794#define MUTABLE_FLAGS(node) \
4795 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
4797 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4798 node->base.location.start = part->location.start;
4801 node->base.location.end = MAX(node->base.location.end, part->location.end);
4803 switch (PM_NODE_TYPE(part)) {
4804 case PM_STRING_NODE:
4805 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
4806 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
4807 // as long as this interpolation only consists of other string literals.
4808 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
4809 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4811 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4813 case PM_INTERPOLATED_STRING_NODE:
4814 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
4815 // If the string that we're concatenating is a static literal,
4816 // then we can keep the static literal flag for this string.
4818 // Otherwise, we lose the static literal flag here and we should
4819 // also clear the mutability flags.
4823 case PM_EMBEDDED_STATEMENTS_NODE: {
4824 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4825 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4827 if (embedded == NULL) {
4828 // If we're embedding multiple statements or no statements, then
4829 // the string is not longer a static literal.
4831 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4832 // If the embedded statement is a string, then we can make that
4833 // string as frozen and static literal, and not touch the static
4834 // literal status of this string.
4835 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4837 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4838 MUTABLE_FLAGS(node);
4840 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4841 // If the embedded statement is an interpolated string, but that
4842 // string is marked as static literal, then we can keep our
4843 // static literal status for this string.
4844 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4845 MUTABLE_FLAGS(node);
4848 // In all other cases, we lose the static literal flag here and
4855 case PM_EMBEDDED_VARIABLE_NODE:
4856 // Embedded variables clear static literal, which means we also
4857 // should clear the mutability flags.
4860 case PM_X_STRING_NODE:
4861 case PM_INTERPOLATED_X_STRING_NODE:
4862 case PM_SYMBOL_NODE:
4863 case PM_INTERPOLATED_SYMBOL_NODE:
4864 // These will only happen in error cases. But we want to handle it
4865 // here so that we don't fail the assertion.
4869 assert(false && "unexpected node type");
4873 pm_node_list_append(&node->parts, part);
4882static pm_interpolated_string_node_t *
4883pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4884 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
4885 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
4887 switch (parser->frozen_string_literal) {
4888 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
4889 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
4891 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
4892 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
4896 *node = (pm_interpolated_string_node_t) {
4897 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_STRING_NODE, flags, opening, closing),
4898 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4899 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4903 if (parts != NULL) {
4905 PM_NODE_LIST_FOREACH(parts, index, part) {
4906 pm_interpolated_string_node_append(node, part);
4917pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
4918 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4919 node->base.location.end = closing->end;
4923pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
4924 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4925 node->base.location.start = part->location.start;
4928 pm_interpolated_node_append(UP(node), &node->parts, part);
4929 node->base.location.end = MAX(node->base.location.end, part->location.end);
4933pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
4934 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4935 node->base.location.end = closing->end;
4941static pm_interpolated_symbol_node_t *
4942pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4943 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
4945 *node = (pm_interpolated_symbol_node_t) {
4946 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
4947 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4948 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4952 if (parts != NULL) {
4954 PM_NODE_LIST_FOREACH(parts, index, part) {
4955 pm_interpolated_symbol_node_append(node, part);
4965static pm_interpolated_x_string_node_t *
4966pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4967 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
4969 *node = (pm_interpolated_x_string_node_t) {
4970 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_X_STRING_NODE, 0, opening, closing),
4971 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4972 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4980pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
4981 pm_interpolated_node_append(UP(node), &node->parts, part);
4982 node->base.location.end = part->location.end;
4986pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
4987 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4988 node->base.location.end = closing->end;
4994static pm_it_local_variable_read_node_t *
4995pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4996 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
4998 *node = (pm_it_local_variable_read_node_t) {
4999 .base = PM_NODE_INIT_TOKEN(parser, PM_IT_LOCAL_VARIABLE_READ_NODE, 0, name),
5008static pm_it_parameters_node_t *
5009pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5010 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5012 *node = (pm_it_parameters_node_t) {
5013 .base = PM_NODE_INIT_TOKENS(parser, PM_IT_PARAMETERS_NODE, 0, opening, closing),
5022static pm_keyword_hash_node_t *
5023pm_keyword_hash_node_create(pm_parser_t *parser) {
5024 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5026 *node = (pm_keyword_hash_node_t) {
5027 .base = PM_NODE_INIT_UNSET(parser, PM_KEYWORD_HASH_NODE, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS),
5038pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5039 // If the element being added is not an AssocNode or does not have a symbol
5040 // key, then we want to turn the SYMBOL_KEYS flag off.
5041 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5042 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5045 pm_node_list_append(&hash->elements, element);
5046 if (hash->base.location.start == NULL) {
5047 hash->base.location.start = element->location.start;
5049 hash->base.location.end = element->location.end;
5055static pm_required_keyword_parameter_node_t *
5056pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5057 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5059 *node = (pm_required_keyword_parameter_node_t) {
5060 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_KEYWORD_PARAMETER_NODE, 0, name),
5061 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5062 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5071static pm_optional_keyword_parameter_node_t *
5072pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5073 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5075 *node = (pm_optional_keyword_parameter_node_t) {
5076 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_KEYWORD_PARAMETER_NODE, 0, name, value),
5077 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5078 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5088static pm_keyword_rest_parameter_node_t *
5089pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5090 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5092 *node = (pm_keyword_rest_parameter_node_t) {
5094 (name->type == PM_TOKEN_NOT_PROVIDED)
5095 ? PM_NODE_INIT_TOKEN(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator)
5096 : PM_NODE_INIT_TOKENS(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator, name)
5098 .name = pm_parser_optional_constant_id_token(parser, name),
5099 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5100 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5109static pm_lambda_node_t *
5110pm_lambda_node_create(
5111 pm_parser_t *parser,
5112 pm_constant_id_list_t *locals,
5113 const pm_token_t *operator,
5114 const pm_token_t *opening,
5115 const pm_token_t *closing,
5116 pm_node_t *parameters,
5119 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5121 *node = (pm_lambda_node_t) {
5122 .base = PM_NODE_INIT_TOKENS(parser, PM_LAMBDA_NODE, 0, operator, closing),
5124 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5125 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5126 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5127 .parameters = parameters,
5137static pm_local_variable_and_write_node_t *
5138pm_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) {
5139 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));
5140 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5141 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5143 *node = (pm_local_variable_and_write_node_t) {
5144 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
5145 .name_loc = target->location,
5146 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5158static pm_local_variable_operator_write_node_t *
5159pm_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) {
5160 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5162 *node = (pm_local_variable_operator_write_node_t) {
5163 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
5164 .name_loc = target->location,
5165 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5168 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5178static pm_local_variable_or_write_node_t *
5179pm_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) {
5180 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));
5181 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5182 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5184 *node = (pm_local_variable_or_write_node_t) {
5185 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
5186 .name_loc = target->location,
5187 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5199static pm_local_variable_read_node_t *
5200pm_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) {
5201 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5203 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5205 *node = (pm_local_variable_read_node_t) {
5206 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_READ_NODE, 0, name),
5217static pm_local_variable_read_node_t *
5218pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5219 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5220 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5227static pm_local_variable_read_node_t *
5228pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5229 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5230 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5236static pm_local_variable_write_node_t *
5237pm_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) {
5238 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5239 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5241 *node = (pm_local_variable_write_node_t) {
5242 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_LOCAL_VARIABLE_WRITE_NODE, flags, name_loc, value),
5246 .name_loc = *name_loc,
5247 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5257pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5258 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5266pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5267 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5275pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5276 if (pm_token_is_numbered_parameter(start, end)) {
5277 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5285static pm_local_variable_target_node_t *
5286pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5287 pm_refute_numbered_parameter(parser, location->start, location->end);
5288 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5290 *node = (pm_local_variable_target_node_t) {
5291 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_TARGET_NODE, 0, location),
5302static pm_match_predicate_node_t *
5303pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5304 pm_assert_value_expression(parser, value);
5306 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5308 *node = (pm_match_predicate_node_t) {
5309 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_PREDICATE_NODE, 0, value, pattern),
5312 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5321static pm_match_required_node_t *
5322pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5323 pm_assert_value_expression(parser, value);
5325 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5327 *node = (pm_match_required_node_t) {
5328 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_REQUIRED_NODE, 0, value, pattern),
5331 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5340static pm_match_write_node_t *
5341pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5342 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5344 *node = (pm_match_write_node_t) {
5345 .base = PM_NODE_INIT_NODE(parser, PM_MATCH_WRITE_NODE, 0, call),
5356static pm_module_node_t *
5357pm_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) {
5358 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5360 *node = (pm_module_node_t) {
5361 .base = PM_NODE_INIT_TOKENS(parser, PM_MODULE_NODE, 0, module_keyword, end_keyword),
5362 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5363 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5364 .constant_path = constant_path,
5366 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5367 .name = pm_parser_constant_id_token(parser, name)
5376static pm_multi_target_node_t *
5377pm_multi_target_node_create(pm_parser_t *parser) {
5378 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5380 *node = (pm_multi_target_node_t) {
5381 .base = PM_NODE_INIT_UNSET(parser, PM_MULTI_TARGET_NODE, 0),
5385 .lparen_loc = { 0 },
5396pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5397 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5398 if (node->rest == NULL) {
5399 node->rest = target;
5401 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5402 pm_node_list_append(&node->rights, target);
5404 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5405 if (node->rest == NULL) {
5406 node->rest = target;
5408 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5409 pm_node_list_append(&node->rights, target);
5411 } else if (node->rest == NULL) {
5412 pm_node_list_append(&node->lefts, target);
5414 pm_node_list_append(&node->rights, target);
5417 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
5418 node->base.location.start = target->location.start;
5421 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
5422 node->base.location.end = target->location.end;
5430pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
5431 node->base.location.start = lparen->start;
5432 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
5439pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
5440 node->base.location.end = rparen->end;
5441 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
5447static pm_multi_write_node_t *
5448pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5449 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
5450 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5452 *node = (pm_multi_write_node_t) {
5453 .base = PM_NODE_INIT_NODES(parser, PM_MULTI_WRITE_NODE, flags, target, value),
5454 .lefts = target->lefts,
5455 .rest = target->rest,
5456 .rights = target->rights,
5457 .lparen_loc = target->lparen_loc,
5458 .rparen_loc = target->rparen_loc,
5459 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5463 // Explicitly do not call pm_node_destroy here because we want to keep
5464 // around all of the information within the MultiWriteNode node.
5473static pm_next_node_t *
5474pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5475 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5476 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
5478 *node = (pm_next_node_t) {
5481 ? PM_NODE_INIT_TOKEN(parser, PM_NEXT_NODE, 0, keyword)
5482 : PM_NODE_INIT_TOKEN_NODE(parser, PM_NEXT_NODE, 0, keyword, arguments)
5484 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5485 .arguments = arguments
5494static pm_nil_node_t *
5495pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5496 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5497 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
5499 *node = (pm_nil_node_t) {
5500 .base = PM_NODE_INIT_TOKEN(parser, PM_NIL_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
5509static pm_no_keywords_parameter_node_t *
5510pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5511 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5512 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5513 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
5515 *node = (pm_no_keywords_parameter_node_t) {
5516 .base = PM_NODE_INIT_TOKENS(parser, PM_NO_KEYWORDS_PARAMETER_NODE, 0, operator, keyword),
5517 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5518 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
5527static pm_numbered_parameters_node_t *
5528pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
5529 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
5531 *node = (pm_numbered_parameters_node_t) {
5532 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_PARAMETERS_NODE, 0, location),
5543#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5552pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5553 const uint8_t *start = token->start + 1;
5554 const uint8_t *end = token->end;
5556 ptrdiff_t diff = end - start;
5558#if PTRDIFF_MAX > SIZE_MAX
5559 assert(diff < (ptrdiff_t) SIZE_MAX);
5561 size_t length = (size_t) diff;
5563 char *digits = xcalloc(length + 1, sizeof(char));
5564 memcpy(digits, start, length);
5565 digits[length] = '\0';
5569 unsigned long value = strtoul(digits, &endptr, 10);
5571 if ((digits == endptr) || (*endptr != '\0')) {
5572 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
5578 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5579 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5583 return (uint32_t) value;
5591static pm_numbered_reference_read_node_t *
5592pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5593 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5594 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
5596 *node = (pm_numbered_reference_read_node_t) {
5597 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_REFERENCE_READ_NODE, 0, name),
5598 .number = pm_numbered_reference_read_node_number(parser, name)
5607static pm_optional_parameter_node_t *
5608pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5609 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
5611 *node = (pm_optional_parameter_node_t) {
5612 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_PARAMETER_NODE, 0, name, value),
5613 .name = pm_parser_constant_id_token(parser, name),
5614 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5615 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5625static pm_or_node_t *
5626pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5627 pm_assert_value_expression(parser, left);
5629 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
5631 *node = (pm_or_node_t) {
5632 .base = PM_NODE_INIT_NODES(parser, PM_OR_NODE, 0, left, right),
5635 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5644static pm_parameters_node_t *
5645pm_parameters_node_create(pm_parser_t *parser) {
5646 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
5648 *node = (pm_parameters_node_t) {
5649 .base = PM_NODE_INIT_UNSET(parser, PM_PARAMETERS_NODE, 0),
5651 .keyword_rest = NULL,
5666pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5667 if (params->base.location.start == NULL) {
5668 params->base.location.start = param->location.start;
5670 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
5673 if (params->base.location.end == NULL) {
5674 params->base.location.end = param->location.end;
5676 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
5684pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
5685 pm_parameters_node_location_set(params, param);
5686 pm_node_list_append(¶ms->requireds, param);
5693pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
5694 pm_parameters_node_location_set(params, UP(param));
5695 pm_node_list_append(¶ms->optionals, UP(param));
5702pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
5703 pm_parameters_node_location_set(params, param);
5704 pm_node_list_append(¶ms->posts, param);
5711pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5712 pm_parameters_node_location_set(params, param);
5713 params->rest = param;
5720pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
5721 pm_parameters_node_location_set(params, param);
5722 pm_node_list_append(¶ms->keywords, param);
5729pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5730 assert(params->keyword_rest == NULL);
5731 pm_parameters_node_location_set(params, param);
5732 params->keyword_rest = param;
5739pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
5740 assert(params->block == NULL);
5741 pm_parameters_node_location_set(params, UP(param));
5742 params->block = param;
5748static pm_program_node_t *
5749pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
5750 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
5752 *node = (pm_program_node_t) {
5753 .base = PM_NODE_INIT_NODE(parser, PM_PROGRAM_NODE, 0, statements),
5755 .statements = statements
5764static pm_parentheses_node_t *
5765pm_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) {
5766 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
5768 *node = (pm_parentheses_node_t) {
5769 .base = PM_NODE_INIT_TOKENS(parser, PM_PARENTHESES_NODE, flags, opening, closing),
5771 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5772 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5781static pm_pinned_expression_node_t *
5782pm_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) {
5783 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
5785 *node = (pm_pinned_expression_node_t) {
5786 .base = PM_NODE_INIT_TOKENS(parser, PM_PINNED_EXPRESSION_NODE, 0, operator, rparen),
5787 .expression = expression,
5788 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5789 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
5790 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
5799static pm_pinned_variable_node_t *
5800pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
5801 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
5803 *node = (pm_pinned_variable_node_t) {
5804 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_PINNED_VARIABLE_NODE, 0, operator, variable),
5805 .variable = variable,
5806 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5815static pm_post_execution_node_t *
5816pm_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) {
5817 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
5819 *node = (pm_post_execution_node_t) {
5820 .base = PM_NODE_INIT_TOKENS(parser, PM_POST_EXECUTION_NODE, 0, keyword, closing),
5821 .statements = statements,
5822 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5823 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5824 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5833static pm_pre_execution_node_t *
5834pm_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) {
5835 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
5837 *node = (pm_pre_execution_node_t) {
5838 .base = PM_NODE_INIT_TOKENS(parser, PM_PRE_EXECUTION_NODE, 0, keyword, closing),
5839 .statements = statements,
5840 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5841 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5842 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5851static pm_range_node_t *
5852pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5853 pm_assert_value_expression(parser, left);
5854 pm_assert_value_expression(parser, right);
5856 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
5857 pm_node_flags_t flags = 0;
5859 // Indicate that this node is an exclusive range if the operator is `...`.
5860 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
5861 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
5864 // Indicate that this node is a static literal (i.e., can be compiled with
5865 // a putobject in CRuby) if the left and right are implicit nil, explicit
5866 // nil, or integers.
5868 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
5869 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
5871 flags |= PM_NODE_FLAG_STATIC_LITERAL;
5874 *node = (pm_range_node_t) {
5875 .base = PM_NODE_INIT(parser, PM_RANGE_NODE, flags, (left == NULL ? operator->start : left->location.start), (right == NULL ? operator->end : right->location.end)),
5878 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5887static pm_redo_node_t *
5888pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
5889 assert(token->type == PM_TOKEN_KEYWORD_REDO);
5890 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
5892 *node = (pm_redo_node_t) {
5893 .base = PM_NODE_INIT_TOKEN(parser, PM_REDO_NODE, 0, token)
5903static pm_regular_expression_node_t *
5904pm_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) {
5905 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
5906 pm_node_flags_t flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL;
5908 *node = (pm_regular_expression_node_t) {
5909 .base = PM_NODE_INIT_TOKENS(parser, PM_REGULAR_EXPRESSION_NODE, flags, opening, closing),
5910 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5911 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
5912 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5913 .unescaped = *unescaped
5922static inline pm_regular_expression_node_t *
5923pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
5924 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
5930static pm_required_parameter_node_t *
5931pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
5932 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
5934 *node = (pm_required_parameter_node_t) {
5935 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_PARAMETER_NODE, 0, token),
5936 .name = pm_parser_constant_id_token(parser, token)
5945static pm_rescue_modifier_node_t *
5946pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
5947 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
5949 *node = (pm_rescue_modifier_node_t) {
5950 .base = PM_NODE_INIT_NODES(parser, PM_RESCUE_MODIFIER_NODE, 0, expression, rescue_expression),
5951 .expression = expression,
5952 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5953 .rescue_expression = rescue_expression
5962static pm_rescue_node_t *
5963pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
5964 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
5966 *node = (pm_rescue_node_t) {
5967 .base = PM_NODE_INIT_TOKEN(parser, PM_RESCUE_NODE, 0, keyword),
5968 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5969 .operator_loc = { 0 },
5970 .then_keyword_loc = { 0 },
5981pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
5982 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
5989pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
5990 node->reference = reference;
5991 node->base.location.end = reference->location.end;
5998pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
5999 node->statements = statements;
6000 if (pm_statements_node_body_length(statements) > 0) {
6001 node->base.location.end = statements->base.location.end;
6009pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6010 node->subsequent = subsequent;
6011 node->base.location.end = subsequent->base.location.end;
6018pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6019 pm_node_list_append(&node->exceptions, exception);
6020 node->base.location.end = exception->location.end;
6026static pm_rest_parameter_node_t *
6027pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6028 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6030 *node = (pm_rest_parameter_node_t) {
6032 (name->type == PM_TOKEN_NOT_PROVIDED)
6033 ? PM_NODE_INIT_TOKEN(parser, PM_REST_PARAMETER_NODE, 0, operator)
6034 : PM_NODE_INIT_TOKENS(parser, PM_REST_PARAMETER_NODE, 0, operator, name)
6036 .name = pm_parser_optional_constant_id_token(parser, name),
6037 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6038 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6047static pm_retry_node_t *
6048pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6049 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6050 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6052 *node = (pm_retry_node_t) {
6053 .base = PM_NODE_INIT_TOKEN(parser, PM_RETRY_NODE, 0, token)
6062static pm_return_node_t *
6063pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6064 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6066 *node = (pm_return_node_t) {
6069 ? PM_NODE_INIT_TOKEN(parser, PM_RETURN_NODE, 0, keyword)
6070 : PM_NODE_INIT_TOKEN_NODE(parser, PM_RETURN_NODE, 0, keyword, arguments)
6072 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6073 .arguments = arguments
6082static pm_self_node_t *
6083pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6084 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6085 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6087 *node = (pm_self_node_t) {
6088 .base = PM_NODE_INIT_TOKEN(parser, PM_SELF_NODE, 0, token)
6097static pm_shareable_constant_node_t *
6098pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6099 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6101 *node = (pm_shareable_constant_node_t) {
6102 .base = PM_NODE_INIT_NODE(parser, PM_SHAREABLE_CONSTANT_NODE, (pm_node_flags_t) value, write),
6112static pm_singleton_class_node_t *
6113pm_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) {
6114 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6116 *node = (pm_singleton_class_node_t) {
6117 .base = PM_NODE_INIT_TOKENS(parser, PM_SINGLETON_CLASS_NODE, 0, class_keyword, end_keyword),
6119 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6120 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6121 .expression = expression,
6123 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6132static pm_source_encoding_node_t *
6133pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6134 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6135 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6137 *node = (pm_source_encoding_node_t) {
6138 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_ENCODING_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6147static pm_source_file_node_t*
6148pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6149 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6150 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6152 pm_node_flags_t flags = 0;
6154 switch (parser->frozen_string_literal) {
6155 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6156 flags |= PM_STRING_FLAGS_MUTABLE;
6158 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6159 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6163 *node = (pm_source_file_node_t) {
6164 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_FILE_NODE, flags, file_keyword),
6165 .filepath = parser->filepath
6174static pm_source_line_node_t *
6175pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6176 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6177 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6179 *node = (pm_source_line_node_t) {
6180 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_LINE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6189static pm_splat_node_t *
6190pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6191 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6193 *node = (pm_splat_node_t) {
6195 (expression == NULL)
6196 ? PM_NODE_INIT_TOKEN(parser, PM_SPLAT_NODE, 0, operator)
6197 : PM_NODE_INIT_TOKEN_NODE(parser, PM_SPLAT_NODE, 0, operator, expression)
6199 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6200 .expression = expression
6209static pm_statements_node_t *
6210pm_statements_node_create(pm_parser_t *parser) {
6211 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6213 *node = (pm_statements_node_t) {
6214 .base = PM_NODE_INIT_BASE(parser, PM_STATEMENTS_NODE, 0),
6225pm_statements_node_body_length(pm_statements_node_t *node) {
6226 return node && node->body.size;
6233pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6234 node->base.location = (pm_location_t) { .start = start, .end = end };
6242pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6243 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6244 node->base.location.start = statement->location.start;
6247 if (statement->location.end > node->base.location.end) {
6248 node->base.location.end = statement->location.end;
6256pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6257 pm_statements_node_body_update(node, statement);
6259 if (node->body.size > 0) {
6260 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6262 switch (PM_NODE_TYPE(previous)) {
6267 case PM_RETURN_NODE:
6268 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6275 pm_node_list_append(&node->body, statement);
6276 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6283pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
6284 pm_statements_node_body_update(node, statement);
6285 pm_node_list_prepend(&node->body, statement);
6286 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6292static inline pm_string_node_t *
6293pm_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) {
6294 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
6295 pm_node_flags_t flags = 0;
6297 switch (parser->frozen_string_literal) {
6298 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6299 flags = PM_STRING_FLAGS_MUTABLE;
6301 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6302 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6306 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start);
6307 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end);
6309 *node = (pm_string_node_t) {
6310 .base = PM_NODE_INIT(parser, PM_STRING_NODE, flags, start, end),
6311 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6312 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6313 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6314 .unescaped = *string
6323static pm_string_node_t *
6324pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6325 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6332static pm_string_node_t *
6333pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6334 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6335 parser->current_string = PM_STRING_EMPTY;
6342static pm_super_node_t *
6343pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6344 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6345 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
6347 const uint8_t *end = pm_arguments_end(arguments);
6349 assert(false && "unreachable");
6352 *node = (pm_super_node_t) {
6353 .base = PM_NODE_INIT(parser, PM_SUPER_NODE, 0, keyword->start, end),
6354 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6355 .lparen_loc = arguments->opening_loc,
6356 .arguments = arguments->arguments,
6357 .rparen_loc = arguments->closing_loc,
6358 .block = arguments->block
6369pm_ascii_only_p(const pm_string_t *contents) {
6370 const size_t length = pm_string_length(contents);
6371 const uint8_t *source = pm_string_source(contents);
6373 for (size_t index = 0; index < length; index++) {
6374 if (source[index] & 0x80) return false;
6384parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6385 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6386 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6389 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6402parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6403 const pm_encoding_t *encoding = parser->encoding;
6405 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6406 size_t width = encoding->char_width(cursor, end - cursor);
6409 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6426static inline pm_node_flags_t
6427parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6428 if (parser->explicit_encoding != NULL) {
6429 // A Symbol may optionally have its encoding explicitly set. This will
6430 // happen if an escape sequence results in a non-ASCII code point.
6431 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6432 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6433 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6434 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6435 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6436 } else if (validate) {
6437 parse_symbol_encoding_validate_other(parser, location, contents);
6439 } else if (pm_ascii_only_p(contents)) {
6440 // Ruby stipulates that all source files must use an ASCII-compatible
6441 // encoding. Thus, all symbols appearing in source are eligible for
6442 // "downgrading" to US-ASCII.
6443 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6444 } else if (validate) {
6445 parse_symbol_encoding_validate_other(parser, location, contents);
6451static pm_node_flags_t
6452parse_and_validate_regular_expression_encoding_modifier(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags, char modifier, const pm_encoding_t *modifier_encoding) {
6453 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
6454 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
6455 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
6456 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
6458 // There's special validation logic used if a string does not contain any character escape sequences.
6459 if (parser->explicit_encoding == NULL) {
6460 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
6461 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
6462 // the US-ASCII encoding.
6464 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
6467 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6469 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6471 } else if (parser->encoding != modifier_encoding) {
6472 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
6474 if (modifier == 'n' && !ascii_only) {
6475 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_NON_ESCAPED_MBC, (int) pm_string_length(source), (const char *) pm_string_source(source));
6482 // TODO (nirvdrum 21-Feb-2024): To validate regexp sources with character escape sequences we need to know whether hex or Unicode escape sequences were used and Prism doesn't currently provide that data. We handle a subset of unambiguous cases in the meanwhile.
6483 bool mixed_encoding = false;
6485 if (mixed_encoding) {
6486 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6487 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
6488 // TODO (nirvdrum 21-Feb-2024): Validate the content is valid in the modifier encoding. Do this on-demand so we don't pay the cost of computation unnecessarily.
6489 bool valid_string_in_modifier_encoding = true;
6491 if (!valid_string_in_modifier_encoding) {
6492 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6494 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6495 // TODO (nirvdrum 21-Feb-2024): There's currently no way to tell if the source used hex or Unicode character escapes from `explicit_encoding` alone. If the source encoding was already UTF-8, both character escape types would set `explicit_encoding` to UTF-8, but need to be processed differently. Skip for now.
6496 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
6497 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INCOMPAT_CHAR_ENCODING, (int) pm_string_length(source), (const char *) pm_string_source(source));
6501 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
6511static pm_node_flags_t
6512parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
6513 // TODO (nirvdrum 22-Feb-2024): CRuby reports a special Regexp-specific error for invalid Unicode ranges. We either need to scan again or modify the "invalid Unicode escape sequence" message we already report.
6514 bool valid_unicode_range = true;
6515 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
6516 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_INVALID_UNICODE_RANGE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6520 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
6521 // to multi-byte characters are allowed.
6522 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
6523 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
6524 // following error message appearing twice. We do the same for compatibility.
6525 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6536 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
6537 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
6540 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
6541 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
6544 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
6545 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
6548 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
6549 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
6552 // At this point no encoding modifiers will be present on the regular expression as they would have already
6553 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
6554 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
6556 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
6559 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
6560 // or by specifying a modifier.
6562 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
6563 if (parser->explicit_encoding != NULL) {
6564 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6565 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
6566 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6567 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
6578static pm_symbol_node_t *
6579pm_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) {
6580 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6582 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start);
6583 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end);
6585 *node = (pm_symbol_node_t) {
6586 .base = PM_NODE_INIT(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | flags, start, end),
6587 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6588 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
6589 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6590 .unescaped = *unescaped
6599static inline pm_symbol_node_t *
6600pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6601 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6607static pm_symbol_node_t *
6608pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6609 pm_symbol_node_t *node = pm_symbol_node_create_unescaped(parser, opening, value, closing, &parser->current_string, parse_symbol_encoding(parser, value, &parser->current_string, false));
6610 parser->current_string = PM_STRING_EMPTY;
6617static pm_symbol_node_t *
6618pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6619 pm_symbol_node_t *node;
6621 switch (token->type) {
6622 case PM_TOKEN_LABEL: {
6623 pm_token_t opening = not_provided(parser);
6624 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6626 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6627 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6629 assert((label.end - label.start) >= 0);
6630 pm_string_shared_init(&node->unescaped, label.start, label.end);
6631 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
6635 case PM_TOKEN_MISSING: {
6636 pm_token_t opening = not_provided(parser);
6637 pm_token_t closing = not_provided(parser);
6639 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
6640 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6644 assert(false && "unreachable");
6655static pm_symbol_node_t *
6656pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6657 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6659 *node = (pm_symbol_node_t) {
6660 .base = PM_NODE_INIT_BASE(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING),
6661 .value_loc = PM_LOCATION_NULL_VALUE(parser),
6665 pm_string_constant_init(&node->unescaped, content, strlen(content));
6673pm_symbol_node_label_p(pm_node_t *node) {
6674 const uint8_t *end = NULL;
6676 switch (PM_NODE_TYPE(node)) {
6677 case PM_SYMBOL_NODE:
6678 end = ((pm_symbol_node_t *) node)->closing_loc.end;
6680 case PM_INTERPOLATED_SYMBOL_NODE:
6681 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
6687 return (end != NULL) && (end[-1] == ':');
6693static pm_symbol_node_t *
6694pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6695 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6697 *new_node = (pm_symbol_node_t) {
6698 .base = PM_NODE_INIT_TOKENS(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
6699 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6700 .value_loc = node->content_loc,
6701 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6702 .unescaped = node->unescaped
6705 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
6706 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
6708 // We are explicitly _not_ using pm_node_destroy here because we don't want
6709 // to trash the unescaped string. We could instead copy the string if we
6710 // know that it is owned, but we're taking the fast path for now.
6719static pm_string_node_t *
6720pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6721 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
6722 pm_node_flags_t flags = 0;
6724 switch (parser->frozen_string_literal) {
6725 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6726 flags = PM_STRING_FLAGS_MUTABLE;
6728 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6729 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6733 *new_node = (pm_string_node_t) {
6734 .base = PM_NODE_INIT_NODE(parser, PM_STRING_NODE, flags, node),
6735 .opening_loc = node->opening_loc,
6736 .content_loc = node->value_loc,
6737 .closing_loc = node->closing_loc,
6738 .unescaped = node->unescaped
6741 // We are explicitly _not_ using pm_node_destroy here because we don't want
6742 // to trash the unescaped string. We could instead copy the string if we
6743 // know that it is owned, but we're taking the fast path for now.
6752static pm_true_node_t *
6753pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6754 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6755 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6757 *node = (pm_true_node_t) {
6758 .base = PM_NODE_INIT_TOKEN(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6767static pm_true_node_t *
6768pm_true_node_synthesized_create(pm_parser_t *parser) {
6769 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6771 *node = (pm_true_node_t) {
6772 .base = PM_NODE_INIT_BASE(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL)
6781static pm_undef_node_t *
6782pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6783 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6784 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
6786 *node = (pm_undef_node_t) {
6787 .base = PM_NODE_INIT_TOKEN(parser, PM_UNDEF_NODE, 0, token),
6788 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
6799pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
6800 node->base.location.end = name->location.end;
6801 pm_node_list_append(&node->names, name);
6807static pm_unless_node_t *
6808pm_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) {
6809 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6811 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6812 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6814 *node = (pm_unless_node_t) {
6815 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, keyword, end),
6816 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6817 .predicate = predicate,
6818 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
6819 .statements = statements,
6820 .else_clause = NULL,
6821 .end_keyword_loc = { 0 }
6830static pm_unless_node_t *
6831pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6832 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6833 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6835 pm_statements_node_t *statements = pm_statements_node_create(parser);
6836 pm_statements_node_body_append(parser, statements, statement, true);
6838 *node = (pm_unless_node_t) {
6839 .base = PM_NODE_INIT_NODES(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
6840 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
6841 .predicate = predicate,
6842 .then_keyword_loc = { 0 },
6843 .statements = statements,
6844 .else_clause = NULL,
6845 .end_keyword_loc = { 0 }
6852pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
6853 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
6854 node->base.location.end = end_keyword->end;
6863pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
6864 assert(parser->current_block_exits != NULL);
6866 // All of the block exits that we want to remove should be within the
6867 // statements, and since we are modifying the statements, we shouldn't have
6868 // to check the end location.
6869 const uint8_t *start = statements->base.location.start;
6871 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
6872 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
6873 if (block_exit->location.start < start) break;
6875 // Implicitly remove from the list by lowering the size.
6876 parser->current_block_exits->size--;
6883static pm_until_node_t *
6884pm_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) {
6885 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6886 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6888 *node = (pm_until_node_t) {
6889 .base = PM_NODE_INIT_TOKENS(parser, PM_UNTIL_NODE, flags, keyword, closing),
6890 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6891 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6892 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6893 .predicate = predicate,
6894 .statements = statements
6903static pm_until_node_t *
6904pm_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) {
6905 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6906 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6907 pm_loop_modifier_block_exits(parser, statements);
6909 *node = (pm_until_node_t) {
6910 .base = PM_NODE_INIT_NODES(parser, PM_UNTIL_NODE, flags, statements, predicate),
6911 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6912 .do_keyword_loc = { 0 },
6913 .closing_loc = { 0 },
6914 .predicate = predicate,
6915 .statements = statements
6924static pm_when_node_t *
6925pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6926 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
6928 *node = (pm_when_node_t) {
6929 .base = PM_NODE_INIT_TOKEN(parser, PM_WHEN_NODE, 0, keyword),
6930 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6932 .then_keyword_loc = { 0 },
6943pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
6944 node->base.location.end = condition->location.end;
6945 pm_node_list_append(&node->conditions, condition);
6952pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
6953 node->base.location.end = then_keyword->end;
6954 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
6961pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
6962 if (statements->base.location.end > node->base.location.end) {
6963 node->base.location.end = statements->base.location.end;
6966 node->statements = statements;
6972static pm_while_node_t *
6973pm_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) {
6974 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6975 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6977 *node = (pm_while_node_t) {
6978 .base = PM_NODE_INIT_TOKENS(parser, PM_WHILE_NODE, flags, keyword, closing),
6979 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6980 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6981 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6982 .predicate = predicate,
6983 .statements = statements
6992static pm_while_node_t *
6993pm_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) {
6994 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6995 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6996 pm_loop_modifier_block_exits(parser, statements);
6998 *node = (pm_while_node_t) {
6999 .base = PM_NODE_INIT_NODES(parser, PM_WHILE_NODE, flags, statements, predicate),
7000 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7001 .do_keyword_loc = { 0 },
7002 .closing_loc = { 0 },
7003 .predicate = predicate,
7004 .statements = statements
7013static pm_while_node_t *
7014pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7015 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7017 *node = (pm_while_node_t) {
7018 .base = PM_NODE_INIT_BASE(parser, PM_WHILE_NODE, 0),
7019 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7020 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7021 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7022 .predicate = predicate,
7023 .statements = statements
7033static pm_x_string_node_t *
7034pm_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) {
7035 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7037 *node = (pm_x_string_node_t) {
7038 .base = PM_NODE_INIT_TOKENS(parser, PM_X_STRING_NODE, PM_STRING_FLAGS_FROZEN, opening, closing),
7039 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7040 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7041 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7042 .unescaped = *unescaped
7051static inline pm_x_string_node_t *
7052pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7053 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7059static pm_yield_node_t *
7060pm_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) {
7061 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7064 if (rparen_loc->start != NULL) {
7065 end = rparen_loc->end;
7066 } else if (arguments != NULL) {
7067 end = arguments->base.location.end;
7068 } else if (lparen_loc->start != NULL) {
7069 end = lparen_loc->end;
7074 *node = (pm_yield_node_t) {
7075 .base = PM_NODE_INIT(parser, PM_YIELD_NODE, 0, keyword->start, end),
7076 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7077 .lparen_loc = *lparen_loc,
7078 .arguments = arguments,
7079 .rparen_loc = *rparen_loc
7090pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7091 pm_scope_t *scope = parser->current_scope;
7094 while (scope != NULL) {
7095 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7096 if (scope->closed) break;
7098 scope = scope->previous;
7111pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7112 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7119pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7120 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7126static pm_constant_id_t
7127pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7128 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7129 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7136static inline pm_constant_id_t
7137pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7138 return pm_parser_local_add_location(parser, token->start, token->end, reads);
7144static pm_constant_id_t
7145pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7146 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7147 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7154static pm_constant_id_t
7155pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7156 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7157 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7169pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7170 // We want to check whether the parameter name is a numbered parameter or
7172 pm_refute_numbered_parameter(parser, name->start, name->end);
7174 // Otherwise we'll fetch the constant id for the parameter name and check
7175 // whether it's already in the current scope.
7176 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7178 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7179 // Add an error if the parameter doesn't start with _ and has been seen before
7180 if ((name->start < name->end) && (*name->start != '_')) {
7181 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7192pm_parser_scope_pop(pm_parser_t *parser) {
7193 pm_scope_t *scope = parser->current_scope;
7194 parser->current_scope = scope->previous;
7195 pm_locals_free(&scope->locals);
7196 pm_node_list_free(&scope->implicit_parameters);
7200/******************************************************************************/
7202/******************************************************************************/
7208pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7209 *stack = (*stack << 1) | (value & 1);
7216pm_state_stack_pop(pm_state_stack_t *stack) {
7224pm_state_stack_p(const pm_state_stack_t *stack) {
7229pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7230 // Use the negation of the value to prevent stack overflow.
7231 pm_state_stack_push(&parser->accepts_block_stack, !value);
7235pm_accepts_block_stack_pop(pm_parser_t *parser) {
7236 pm_state_stack_pop(&parser->accepts_block_stack);
7240pm_accepts_block_stack_p(pm_parser_t *parser) {
7241 return !pm_state_stack_p(&parser->accepts_block_stack);
7245pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7246 pm_state_stack_push(&parser->do_loop_stack, value);
7250pm_do_loop_stack_pop(pm_parser_t *parser) {
7251 pm_state_stack_pop(&parser->do_loop_stack);
7255pm_do_loop_stack_p(pm_parser_t *parser) {
7256 return pm_state_stack_p(&parser->do_loop_stack);
7259/******************************************************************************/
7260/* Lexer check helpers */
7261/******************************************************************************/
7267static inline uint8_t
7268peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7269 if (cursor < parser->end) {
7281static inline uint8_t
7282peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7283 return peek_at(parser, parser->current.end + offset);
7290static inline uint8_t
7291peek(const pm_parser_t *parser) {
7292 return peek_at(parser, parser->current.end);
7300match(pm_parser_t *parser, uint8_t value) {
7301 if (peek(parser) == value) {
7302 parser->current.end++;
7313match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7314 if (peek_at(parser, cursor) == '\n') {
7317 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7329match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7330 return match_eol_at(parser, parser->current.end + offset);
7339match_eol(pm_parser_t *parser) {
7340 return match_eol_at(parser, parser->current.end);
7346static inline const uint8_t *
7347next_newline(const uint8_t *cursor, ptrdiff_t length) {
7348 assert(length >= 0);
7350 // Note that it's okay for us to use memchr here to look for \n because none
7351 // of the encodings that we support have \n as a component of a multi-byte
7353 return memchr(cursor, '\n', (size_t) length);
7360ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7361 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));
7369parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7370 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7372 if (encoding != NULL) {
7373 if (parser->encoding != encoding) {
7374 parser->encoding = encoding;
7375 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7378 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7390parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7391 const uint8_t *cursor = parser->current.start + 1;
7392 const uint8_t *end = parser->current.end;
7394 bool separator = false;
7396 if (end - cursor <= 6) return;
7397 switch (cursor[6]) {
7398 case 'C': case 'c': cursor += 6; continue;
7399 case 'O': case 'o': cursor += 5; continue;
7400 case 'D': case 'd': cursor += 4; continue;
7401 case 'I': case 'i': cursor += 3; continue;
7402 case 'N': case 'n': cursor += 2; continue;
7403 case 'G': case 'g': cursor += 1; continue;
7410 if (pm_char_is_whitespace(*cursor)) break;
7413 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7419 if (++cursor >= end) return;
7420 } while (pm_char_is_whitespace(*cursor));
7422 if (separator) break;
7423 if (*cursor != '=' && *cursor != ':') return;
7429 const uint8_t *value_start = cursor;
7430 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7432 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7433 // If we were unable to parse the encoding value, then we've got an
7434 // issue because we didn't understand the encoding that the user was
7435 // trying to use. In this case we'll keep using the default encoding but
7436 // add an error to the parser to indicate an unsuccessful parse.
7437 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7442 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7443 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7444 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7445} pm_magic_comment_boolean_value_t;
7451static pm_magic_comment_boolean_value_t
7452parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7453 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7454 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7455 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7456 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7458 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7463pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7464 return b == '\'' || b == '"' || b == ':' || b == ';';
7472static inline const uint8_t *
7473parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7474 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
7475 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
7494parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7499 if (end - start <= 7)
return false;
7501 const uint8_t *cursor;
7502 bool indicator =
false;
7504 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7507 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7518 while (cursor < end) {
7519 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7521 const uint8_t *key_start = cursor;
7522 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7524 const uint8_t *key_end = cursor;
7525 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7526 if (cursor == end)
break;
7528 if (*cursor ==
':') {
7531 if (!indicator)
return false;
7535 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7536 if (cursor == end)
break;
7538 const uint8_t *value_start;
7539 const uint8_t *value_end;
7541 if (*cursor ==
'"') {
7542 value_start = ++cursor;
7543 for (; cursor < end && *cursor !=
'"'; cursor++) {
7544 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7547 if (cursor < end && *cursor ==
'"') cursor++;
7549 value_start = cursor;
7550 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7555 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7557 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7558 if (cursor != end)
return false;
7564 const size_t key_length = (size_t) (key_end - key_start);
7568 pm_string_shared_init(&key, key_start, key_end);
7570 uint8_t *buffer =
xmalloc(key_length);
7571 if (buffer == NULL)
break;
7573 memcpy(buffer, key_start, key_length);
7574 buffer[dash - key_start] =
'_';
7576 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
7577 buffer[dash - key_start] =
'_';
7580 pm_string_owned_init(&key, buffer, key_length);
7585 const uint8_t *key_source = pm_string_source(&key);
7586 uint32_t value_length = (uint32_t) (value_end - value_start);
7592 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7593 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7595 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7599 if (key_length == 11) {
7600 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7601 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7602 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7603 PM_PARSER_WARN_TOKEN_FORMAT(
7606 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7608 (
const char *) key_source,
7610 (
const char *) value_start
7613 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7616 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7621 }
else if (key_length == 21) {
7622 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7625 if (semantic_token_seen) {
7626 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7628 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7629 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7630 PM_PARSER_WARN_TOKEN_FORMAT(
7633 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7635 (
const char *) key_source,
7637 (
const char *) value_start
7640 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7643 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7649 }
else if (key_length == 24) {
7650 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7652 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7654 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
7655 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7656 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7657 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7658 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7659 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7660 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7661 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7662 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7663 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7665 PM_PARSER_WARN_TOKEN_FORMAT(
7668 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7670 (
const char *) key_source,
7672 (
const char *) value_start
7680 pm_string_free(&key);
7700static const uint32_t context_terminators[] = {
7702 [
PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7705 [
PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7707 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7711 [
PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7712 [
PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7713 [
PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7714 [
PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7717 [
PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7718 [
PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7721 [
PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7726 [
PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7730 [
PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7732 [
PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7735 [
PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7738 [
PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7741 [
PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7745 [
PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7748 [
PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7751 [
PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7753 [
PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7760 return token->
type < 32 && (context_terminators[context] & (1U << token->
type));
7771 while (context_node != NULL) {
7772 if (context_terminator(context_node->
context, token))
return context_node->
context;
7773 context_node = context_node->
prev;
7782 if (context_node == NULL)
return false;
7807 while (context_node != NULL) {
7808 if (context_node->
context == context)
return true;
7809 context_node = context_node->
prev;
7819 while (context_node != NULL) {
7820 switch (context_node->
context) {
7841 context_node = context_node->
prev;
7856 assert(
false &&
"unreachable");
7914 assert(
false &&
"unreachable");
7923pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
7924 if (invalid != NULL) {
7925 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
7926 pm_parser_err(parser, invalid, invalid + 1, diag_id);
7931pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7932 const uint8_t *invalid = NULL;
7933 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
7934 pm_strspn_number_validate(parser,
string, length, invalid);
7939pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7940 const uint8_t *invalid = NULL;
7941 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
7942 pm_strspn_number_validate(parser,
string, length, invalid);
7947pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7948 const uint8_t *invalid = NULL;
7949 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
7950 pm_strspn_number_validate(parser,
string, length, invalid);
7955pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7956 const uint8_t *invalid = NULL;
7957 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
7958 pm_strspn_number_validate(parser,
string, length, invalid);
7962static pm_token_type_t
7963lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
7964 pm_token_type_t
type = PM_TOKEN_INTEGER;
7968 if (peek(parser) ==
'.') {
7969 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7972 type = PM_TOKEN_FLOAT;
7982 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
7983 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
7986 if (pm_char_is_decimal_digit(peek(parser))) {
7990 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
7992 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8000 type = PM_TOKEN_FLOAT;
8006static pm_token_type_t
8007lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8008 pm_token_type_t
type = PM_TOKEN_INTEGER;
8011 if (peek_offset(parser, -1) ==
'0') {
8017 if (pm_char_is_decimal_digit(peek(parser))) {
8021 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8030 if (pm_char_is_binary_digit(peek(parser))) {
8034 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8044 if (pm_char_is_octal_digit(peek(parser))) {
8048 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8072 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8076 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8079 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8084 type = lex_optional_float_suffix(parser, seen_e);
8091 type = lex_optional_float_suffix(parser, seen_e);
8101 type = lex_optional_float_suffix(parser, seen_e);
8107 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8108 const uint8_t *fraction_start = parser->
current.
end;
8109 const uint8_t *fraction_end = parser->
current.
end + 2;
8110 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8111 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
8117static pm_token_type_t
8119 pm_token_type_t
type = PM_TOKEN_INTEGER;
8123 bool seen_e =
false;
8124 type = lex_numeric_prefix(parser, &seen_e);
8127 pm_token_type_t suffix_type =
type;
8129 if (
type == PM_TOKEN_INTEGER) {
8130 if (match(parser,
'r')) {
8131 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8133 if (match(parser,
'i')) {
8134 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8136 }
else if (match(parser,
'i')) {
8137 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8140 if (!seen_e && match(parser,
'r')) {
8141 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8143 if (match(parser,
'i')) {
8144 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8146 }
else if (match(parser,
'i')) {
8147 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8151 const uint8_t b = peek(parser);
8152 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8162static pm_token_type_t
8165 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8166 return PM_TOKEN_GLOBAL_VARIABLE;
8171 bool allow_multiple =
true;
8191 return PM_TOKEN_GLOBAL_VARIABLE;
8198 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8211 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
8214 return PM_TOKEN_GLOBAL_VARIABLE;
8227 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8231 allow_multiple =
false;
8239 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.
end, parser->
end - parser->
current.
end)) > 0);
8240 }
else if (pm_char_is_whitespace(peek(parser))) {
8243 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8252 return PM_TOKEN_GLOBAL_VARIABLE;
8269static inline pm_token_type_t
8270lex_keyword(
pm_parser_t *parser,
const uint8_t *current_start,
const char *value,
size_t vlen,
pm_lex_state_t state, pm_token_type_t
type, pm_token_type_t modifier_type) {
8271 if (memcmp(current_start, value, vlen) == 0) {
8274 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
8275 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8277 lex_state_set(parser, state);
8278 if (state == PM_LEX_STATE_BEG) {
8282 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8283 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8284 return modifier_type;
8291 return PM_TOKEN_EOF;
8294static pm_token_type_t
8295lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8298 const uint8_t *end = parser->
end;
8300 const uint8_t *current_end = parser->
current.
end;
8303 if (encoding_changed) {
8304 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8305 current_end += width;
8308 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8309 current_end += width;
8316 width = (size_t) (current_end - current_start);
8318 if (current_end < end) {
8319 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8325 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8326 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8330 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8331 (void) match(parser,
':');
8332 return PM_TOKEN_LABEL;
8335 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8336 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8337 return PM_TOKEN_KEYWORD_DEFINED;
8341 return PM_TOKEN_METHOD_NAME;
8344 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,
'=')) {
8347 return PM_TOKEN_IDENTIFIER;
8351 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8352 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8356 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8357 (void) match(parser,
':');
8358 return PM_TOKEN_LABEL;
8362 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8363 pm_token_type_t
type;
8366 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8367 if (pm_do_loop_stack_p(parser)) {
8368 return PM_TOKEN_KEYWORD_DO_LOOP;
8370 return PM_TOKEN_KEYWORD_DO;
8373 if ((
type = lex_keyword(parser, current_start,
"if", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IF, PM_TOKEN_KEYWORD_IF_MODIFIER)) != PM_TOKEN_EOF)
return type;
8374 if ((
type = lex_keyword(parser, current_start,
"in", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_IN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8375 if ((
type = lex_keyword(parser, current_start,
"or", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_OR, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8378 if ((
type = lex_keyword(parser, current_start,
"and", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_AND, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8379 if ((
type = lex_keyword(parser, current_start,
"def", width, PM_LEX_STATE_FNAME, PM_TOKEN_KEYWORD_DEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8380 if ((
type = lex_keyword(parser, current_start,
"end", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8381 if ((
type = lex_keyword(parser, current_start,
"END", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_END_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8382 if ((
type = lex_keyword(parser, current_start,
"for", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_FOR, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8383 if ((
type = lex_keyword(parser, current_start,
"nil", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_NIL, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8384 if ((
type = lex_keyword(parser, current_start,
"not", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_NOT, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8387 if ((
type = lex_keyword(parser, current_start,
"case", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_CASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8388 if ((
type = lex_keyword(parser, current_start,
"else", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8389 if ((
type = lex_keyword(parser, current_start,
"next", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_NEXT, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8390 if ((
type = lex_keyword(parser, current_start,
"redo", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_REDO, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8391 if ((
type = lex_keyword(parser, current_start,
"self", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_SELF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8392 if ((
type = lex_keyword(parser, current_start,
"then", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8393 if ((
type = lex_keyword(parser, current_start,
"true", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_TRUE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8394 if ((
type = lex_keyword(parser, current_start,
"when", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8397 if ((
type = lex_keyword(parser, current_start,
"alias", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_ALIAS, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8398 if ((
type = lex_keyword(parser, current_start,
"begin", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_BEGIN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8399 if ((
type = lex_keyword(parser, current_start,
"BEGIN", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_BEGIN_UPCASE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8400 if ((
type = lex_keyword(parser, current_start,
"break", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_BREAK, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8401 if ((
type = lex_keyword(parser, current_start,
"class", width, PM_LEX_STATE_CLASS, PM_TOKEN_KEYWORD_CLASS, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8402 if ((
type = lex_keyword(parser, current_start,
"elsif", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8403 if ((
type = lex_keyword(parser, current_start,
"false", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_FALSE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8404 if ((
type = lex_keyword(parser, current_start,
"retry", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD_RETRY, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8405 if ((
type = lex_keyword(parser, current_start,
"super", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_SUPER, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8406 if ((
type = lex_keyword(parser, current_start,
"undef", width, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM, PM_TOKEN_KEYWORD_UNDEF, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8407 if ((
type = lex_keyword(parser, current_start,
"until", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNTIL, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) != PM_TOKEN_EOF)
return type;
8408 if ((
type = lex_keyword(parser, current_start,
"while", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_WHILE, PM_TOKEN_KEYWORD_WHILE_MODIFIER)) != PM_TOKEN_EOF)
return type;
8409 if ((
type = lex_keyword(parser, current_start,
"yield", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_YIELD, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8412 if ((
type = lex_keyword(parser, current_start,
"ensure", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8413 if ((
type = lex_keyword(parser, current_start,
"module", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_MODULE, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8414 if ((
type = lex_keyword(parser, current_start,
"rescue", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) != PM_TOKEN_EOF)
return type;
8415 if ((
type = lex_keyword(parser, current_start,
"return", width, PM_LEX_STATE_MID, PM_TOKEN_KEYWORD_RETURN, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8416 if ((
type = lex_keyword(parser, current_start,
"unless", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_UNLESS, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) != PM_TOKEN_EOF)
return type;
8419 if ((
type = lex_keyword(parser, current_start,
"__LINE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___LINE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8420 if ((
type = lex_keyword(parser, current_start,
"__FILE__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___FILE__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8423 if ((
type = lex_keyword(parser, current_start,
"__ENCODING__", width, PM_LEX_STATE_END, PM_TOKEN_KEYWORD___ENCODING__, PM_TOKEN_EOF)) != PM_TOKEN_EOF)
return type;
8428 if (encoding_changed) {
8429 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8431 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8457static pm_token_type_t
8458lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8461 if (pound + 1 >= parser->
end) {
8463 return PM_TOKEN_STRING_CONTENT;
8472 if (pound + 2 >= parser->
end) {
8474 return PM_TOKEN_STRING_CONTENT;
8479 const uint8_t *variable = pound + 2;
8480 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
8482 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
8488 return PM_TOKEN_STRING_CONTENT;
8493 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8495 return PM_TOKEN_EMBVAR;
8502 return PM_TOKEN_NOT_PROVIDED;
8507 if (pound + 2 >= parser->
end) {
8509 return PM_TOKEN_STRING_CONTENT;
8515 const uint8_t *check = pound + 2;
8517 if (pound[2] ==
'-') {
8518 if (pound + 3 >= parser->
end) {
8520 return PM_TOKEN_STRING_CONTENT;
8531 char_is_identifier_start(parser, check, parser->
end - check) ||
8532 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8539 return PM_TOKEN_STRING_CONTENT;
8544 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8546 return PM_TOKEN_EMBVAR;
8552 return PM_TOKEN_NOT_PROVIDED;
8559 return PM_TOKEN_STRING_CONTENT;
8566 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8569 pm_do_loop_stack_push(parser,
false);
8570 return PM_TOKEN_EMBEXPR_BEGIN;
8576 return PM_TOKEN_NOT_PROVIDED;
8580static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8581static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8582static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8583static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8584static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8589static const bool ascii_printable_chars[] = {
8590 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8591 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8592 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8593 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8594 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8595 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
8596 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8597 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
8601char_is_ascii_printable(
const uint8_t b) {
8602 return (b < 0x80) && ascii_printable_chars[b];
8609static inline uint8_t
8610escape_hexadecimal_digit(
const uint8_t value) {
8611 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8619static inline uint32_t
8622 for (
size_t index = 0; index < length; index++) {
8623 if (index != 0) value <<= 4;
8624 value |= escape_hexadecimal_digit(
string[index]);
8629 if (value >= 0xD800 && value <= 0xDFFF) {
8630 if (error_location != NULL) {
8631 pm_parser_err(parser, error_location->
start, error_location->
end, PM_ERR_ESCAPE_INVALID_UNICODE);
8633 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
8644static inline uint8_t
8645escape_byte(uint8_t value,
const uint8_t flags) {
8646 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8647 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8655escape_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) {
8659 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8667 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8668 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
8669 pm_buffer_append_byte(buffer, 0xEF);
8670 pm_buffer_append_byte(buffer, 0xBF);
8671 pm_buffer_append_byte(buffer, 0xBD);
8683 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
8689 pm_buffer_append_byte(buffer,
byte);
8709 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8710 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
8713 escape_write_byte_encoded(parser, buffer,
byte);
8729 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.
end++, flags));
8730 }
else if (width > 1) {
8732 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
8733 pm_buffer_append_bytes(b, parser->
current.
end, width);
8739 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8749escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
8750#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
8752 PM_PARSER_WARN_TOKEN_FORMAT(
8755 PM_WARN_INVALID_CHARACTER,
8769 uint8_t peeked = peek(parser);
8773 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
8778 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
8783 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
8788 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
8793 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
8798 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
8803 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
8808 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
8813 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
8818 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
8823 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
8826 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
8827 uint8_t value = (uint8_t) (*parser->
current.
end -
'0');
8830 if (pm_char_is_octal_digit(peek(parser))) {
8831 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.
end -
'0'));
8834 if (pm_char_is_octal_digit(peek(parser))) {
8835 value = ((uint8_t) (value << 3)) | ((uint8_t) (*parser->
current.
end -
'0'));
8840 value = escape_byte(value, flags);
8841 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
8845 const uint8_t *start = parser->
current.
end - 1;
8848 uint8_t
byte = peek(parser);
8850 if (pm_char_is_hexadecimal_digit(
byte)) {
8851 uint8_t value = escape_hexadecimal_digit(
byte);
8854 byte = peek(parser);
8855 if (pm_char_is_hexadecimal_digit(
byte)) {
8856 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
8860 value = escape_byte(value, flags);
8861 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8862 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
8863 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
8865 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.
end - start));
8869 escape_write_byte_encoded(parser, buffer, value);
8871 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
8877 const uint8_t *start = parser->
current.
end - 1;
8881 const uint8_t *start = parser->
current.
end - 2;
8882 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.
end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8883 }
else if (peek(parser) ==
'{') {
8884 const uint8_t *unicode_codepoints_start = parser->
current.
end - 2;
8891 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
8902 const uint8_t *extra_codepoints_start = NULL;
8903 int codepoints_count = 0;
8906 const uint8_t *unicode_start = parser->
current.
end;
8907 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.
end, parser->
end - parser->
current.
end);
8909 if (hexadecimal_length > 6) {
8911 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
8912 }
else if (hexadecimal_length == 0) {
8915 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8919 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.
end - start));
8921 pm_parser_err(parser, parser->
current.
end, parser->
current.
end, PM_ERR_ESCAPE_INVALID_UNICODE);
8922 pm_parser_err(parser, parser->
current.
end, parser->
current.
end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8930 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
8931 extra_codepoints_start = unicode_start;
8934 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL);
8935 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.
end, value);
8942 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
8943 pm_parser_err(parser, extra_codepoints_start, parser->
current.
end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
8947 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.
end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.
end - start), start);
8948 }
else if (peek(parser) ==
'}') {
8951 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8955 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.
end - start));
8957 pm_parser_err(parser, unicode_codepoints_start, parser->
current.
end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8961 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8962 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.
end - unicode_codepoints_start));
8968 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8969 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.
end - start));
8971 const uint8_t *start = parser->
current.
end - 2;
8972 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.
end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8974 }
else if (length == 4) {
8975 uint32_t value = escape_unicode(parser, parser->
current.
end, 4, NULL);
8977 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8978 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.
end + 4 - start));
8981 escape_write_unicode(parser, buffer, flags, start, parser->
current.
end + 4, value);
8986 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8990 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.
end - start));
8992 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
9001 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9002 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9006 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9010 uint8_t peeked = peek(parser);
9014 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9020 if (match(parser,
'u') || match(parser,
'U')) {
9025 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9029 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9030 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9034 escape_read_warn(parser, flags, 0,
"\\t");
9035 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9038 if (!char_is_ascii_printable(peeked)) {
9039 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9044 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9051 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9052 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9055 if (peek(parser) !=
'-') {
9057 pm_parser_err(parser, parser->
current.
start, parser->
current.
end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9063 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9067 uint8_t peeked = peek(parser);
9071 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9077 if (match(parser,
'u') || match(parser,
'U')) {
9082 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9086 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9087 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9091 escape_read_warn(parser, flags, 0,
"\\t");
9092 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9095 if (!char_is_ascii_printable(peeked)) {
9097 pm_parser_err(parser, parser->
current.
start, parser->
current.
end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9102 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9109 if (flags & PM_ESCAPE_FLAG_META) {
9110 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9113 if (peek(parser) !=
'-') {
9121 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9125 uint8_t peeked = peek(parser);
9130 if (match(parser,
'u') || match(parser,
'U')) {
9135 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9139 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9140 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9144 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9145 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9148 if (!char_is_ascii_printable(peeked)) {
9155 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9160 if (peek_offset(parser, 1) ==
'\n') {
9162 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
9168 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9174 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9176 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9208static pm_token_type_t
9210 if (lex_state_end_p(parser)) {
9211 lex_state_set(parser, PM_LEX_STATE_BEG);
9212 return PM_TOKEN_QUESTION_MARK;
9216 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9218 return PM_TOKEN_CHARACTER_LITERAL;
9221 if (pm_char_is_whitespace(*parser->
current.
end)) {
9222 lex_state_set(parser, PM_LEX_STATE_BEG);
9223 return PM_TOKEN_QUESTION_MARK;
9226 lex_state_set(parser, PM_LEX_STATE_BEG);
9228 if (match(parser,
'\\')) {
9229 lex_state_set(parser, PM_LEX_STATE_END);
9232 pm_buffer_init_capacity(&buffer, 3);
9234 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9237 return PM_TOKEN_CHARACTER_LITERAL;
9247 !char_is_identifier(parser, parser->
current.
end + encoding_width, parser->
end - (parser->
current.
end + encoding_width))
9250 lex_state_set(parser, PM_LEX_STATE_END);
9253 return PM_TOKEN_CHARACTER_LITERAL;
9257 return PM_TOKEN_QUESTION_MARK;
9264static pm_token_type_t
9266 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9267 const uint8_t *end = parser->
end;
9270 if ((width = char_is_identifier_start(parser, parser->
current.
end, end - parser->
current.
end)) > 0) {
9273 while ((width = char_is_identifier(parser, parser->
current.
end, end - parser->
current.
end)) > 0) {
9277 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9279 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9285 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9286 pm_parser_err_token(parser, &parser->
current, diag_id);
9291 if (parser->lex_modes.
current->mode == PM_LEX_EMBVAR) {
9292 lex_mode_pop(parser);
9314 if (comment == NULL)
return NULL;
9329static pm_token_type_t
9334 if (newline == NULL) {
9337 pm_newline_list_append(&parser->
newline_list, newline);
9342 parser_lex_callback(parser);
9345 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9346 if (comment == NULL)
return PM_TOKEN_EOF;
9356 (memcmp(parser->
current.
end,
"=end", 4) == 0) &&
9359 pm_char_is_whitespace(parser->
current.
end[4]) ||
9367 if (newline == NULL) {
9370 pm_newline_list_append(&parser->
newline_list, newline);
9375 parser_lex_callback(parser);
9380 return PM_TOKEN_EMBDOC_END;
9387 if (newline == NULL) {
9390 pm_newline_list_append(&parser->
newline_list, newline);
9395 parser_lex_callback(parser);
9398 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9403 return PM_TOKEN_EOF;
9414 parser_lex_callback(parser);
9440 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9441 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9504 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9526 return (width == 0 ? 1 : width);
9534 size_t width = parser_char_width(parser);
9541 size_t width = parser_char_width(parser);
9548pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
9549 for (
size_t index = 0; index < length; index++) {
9550 if (value[index] & 0x80)
return false;
9564 pm_string_owned_init(&parser->
current_string, (uint8_t *) pm_buffer_value(&token_buffer->
buffer), pm_buffer_length(&token_buffer->
buffer));
9585 if (token_buffer->
cursor == NULL) {
9589 pm_token_buffer_copy(parser, token_buffer);
9601 pm_regexp_token_buffer_copy(parser, token_buffer);
9605#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9617 const uint8_t *start;
9618 if (token_buffer->
cursor == NULL) {
9619 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9622 start = token_buffer->
cursor;
9625 const uint8_t *end = parser->
current.
end - 1;
9626 assert(end >= start);
9627 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9629 token_buffer->
cursor = end;
9634 const uint8_t *start;
9636 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9637 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9643 const uint8_t *end = parser->
current.
end - 1;
9644 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9645 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9650#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9658 size_t whitespace = 0;
9661 case PM_HEREDOC_INDENT_NONE:
9666 case PM_HEREDOC_INDENT_DASH:
9668 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
9670 case PM_HEREDOC_INDENT_TILDE:
9673 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
9674 if (**cursor ==
'\t') {
9675 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
9694 size_t eol_length = match_eol(parser);
9701 parser_flush_heredoc_end(parser);
9711 if (eol_length == 2) {
9726#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
9745 bool lexed_comment =
false;
9752 switch (parser->lex_modes.
current->mode) {
9753 case PM_LEX_DEFAULT:
9754 case PM_LEX_EMBEXPR:
9771 bool space_seen =
false;
9775 bool chomping =
true;
9786 if (match_eol_offset(parser, 1)) {
9789 pm_parser_warn(parser, parser->
current.
end, parser->
current.
end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
9795 size_t eol_length = match_eol_offset(parser, 1);
9805 }
else if (pm_char_is_inline_whitespace(*parser->
current.
end)) {
9847 parser->
current.
end = ending == NULL ? parser->
end : ending;
9852 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
9857 parser_lex_callback(parser);
9869 parser_lex_magic_comment_encoding(parser);
9873 lexed_comment =
true;
9879 size_t eol_length = match_eol_at(parser, parser->
current.
end - 1);
9891 if (!lexed_comment) {
9901 parser_flush_heredoc_end(parser);
9906 switch (lex_state_ignored_p(parser)) {
9907 case PM_IGNORED_NEWLINE_NONE:
9909 case PM_IGNORED_NEWLINE_PATTERN:
9911 if (!lexed_comment) parser_lex_ignored_newline(parser);
9912 lex_state_set(parser, PM_LEX_STATE_BEG);
9918 case PM_IGNORED_NEWLINE_ALL:
9919 if (!lexed_comment) parser_lex_ignored_newline(parser);
9920 lexed_comment =
false;
9921 goto lex_next_token;
9929 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
9931 if (next_content < parser->end) {
9937 if (next_content[0] ==
'#') {
9939 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
9941 while (following && (following + 1 < parser->
end)) {
9943 following += pm_strspn_inline_whitespace(following, parser->
end - following);
9947 if (peek_at(parser, following) !=
'#')
break;
9951 following = next_newline(following, parser->
end - following);
9956 if (lex_state_ignored_p(parser)) {
9957 if (!lexed_comment) parser_lex_ignored_newline(parser);
9958 lexed_comment =
false;
9959 goto lex_next_token;
9965 (peek_at(parser, following) ==
'.') ||
9966 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
9968 if (!lexed_comment) parser_lex_ignored_newline(parser);
9969 lexed_comment =
false;
9970 goto lex_next_token;
9980 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
9981 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
9983 peek_at(parser, following) ==
'a' &&
9984 peek_at(parser, following + 1) ==
'n' &&
9985 peek_at(parser, following + 2) ==
'd' &&
9986 peek_at(parser, next_content + 3) !=
'!' &&
9987 peek_at(parser, next_content + 3) !=
'?' &&
9988 !char_is_identifier(parser, following + 3, parser->
end - (following + 3))
9991 peek_at(parser, following) ==
'o' &&
9992 peek_at(parser, following + 1) ==
'r' &&
9993 peek_at(parser, next_content + 2) !=
'!' &&
9994 peek_at(parser, next_content + 2) !=
'?' &&
9995 !char_is_identifier(parser, following + 2, parser->
end - (following + 2))
9999 if (!lexed_comment) parser_lex_ignored_newline(parser);
10000 lexed_comment =
false;
10001 goto lex_next_token;
10007 if (next_content[0] ==
'.') {
10011 if (peek_at(parser, next_content + 1) ==
'.') {
10012 if (!lexed_comment) parser_lex_ignored_newline(parser);
10013 lex_state_set(parser, PM_LEX_STATE_BEG);
10019 if (!lexed_comment) parser_lex_ignored_newline(parser);
10020 lex_state_set(parser, PM_LEX_STATE_DOT);
10029 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10030 if (!lexed_comment) parser_lex_ignored_newline(parser);
10031 lex_state_set(parser, PM_LEX_STATE_DOT);
10035 LEX(PM_TOKEN_AMPERSAND_DOT);
10041 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10042 if (!lexed_comment) parser_lex_ignored_newline(parser);
10043 lex_state_set(parser, PM_LEX_STATE_BEG);
10047 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10052 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10053 if (!lexed_comment) parser_lex_ignored_newline(parser);
10054 lex_state_set(parser, PM_LEX_STATE_BEG);
10058 LEX(PM_TOKEN_PIPE_PIPE);
10064 peek_at(parser, next_content) ==
'a' &&
10065 peek_at(parser, next_content + 1) ==
'n' &&
10066 peek_at(parser, next_content + 2) ==
'd' &&
10067 peek_at(parser, next_content + 3) !=
'!' &&
10068 peek_at(parser, next_content + 3) !=
'?' &&
10069 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10071 if (!lexed_comment) parser_lex_ignored_newline(parser);
10072 lex_state_set(parser, PM_LEX_STATE_BEG);
10077 LEX(PM_TOKEN_KEYWORD_AND);
10083 peek_at(parser, next_content) ==
'o' &&
10084 peek_at(parser, next_content + 1) ==
'r' &&
10085 peek_at(parser, next_content + 2) !=
'!' &&
10086 peek_at(parser, next_content + 2) !=
'?' &&
10087 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10089 if (!lexed_comment) parser_lex_ignored_newline(parser);
10090 lex_state_set(parser, PM_LEX_STATE_BEG);
10095 LEX(PM_TOKEN_KEYWORD_OR);
10102 lex_state_set(parser, PM_LEX_STATE_BEG);
10105 if (!lexed_comment) parser_lex_callback(parser);
10115 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10116 LEX(PM_TOKEN_COMMA);
10120 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10122 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10123 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10127 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10128 pm_do_loop_stack_push(parser,
false);
10135 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10136 pm_do_loop_stack_pop(parser);
10137 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10141 lex_state_set(parser, PM_LEX_STATE_BEG);
10143 LEX(PM_TOKEN_SEMICOLON);
10148 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10150 if (lex_state_operator_p(parser)) {
10151 if (match(parser,
']')) {
10153 lex_state_set(parser, PM_LEX_STATE_ARG);
10154 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10157 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10161 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10162 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10165 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10166 pm_do_loop_stack_push(parser,
false);
10172 lex_state_set(parser, PM_LEX_STATE_END);
10173 pm_do_loop_stack_pop(parser);
10174 LEX(PM_TOKEN_BRACKET_RIGHT);
10178 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10183 lex_state_set(parser, PM_LEX_STATE_BEG);
10184 type = PM_TOKEN_LAMBDA_BEGIN;
10185 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10187 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10188 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10191 lex_state_set(parser, PM_LEX_STATE_BEG);
10192 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10195 lex_state_set(parser, PM_LEX_STATE_BEG);
10198 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10203 pm_do_loop_stack_push(parser,
false);
10211 pm_do_loop_stack_pop(parser);
10214 lex_mode_pop(parser);
10215 LEX(PM_TOKEN_EMBEXPR_END);
10219 lex_state_set(parser, PM_LEX_STATE_END);
10220 LEX(PM_TOKEN_BRACE_RIGHT);
10224 if (match(parser,
'*')) {
10225 if (match(parser,
'=')) {
10226 lex_state_set(parser, PM_LEX_STATE_BEG);
10227 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10230 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10232 if (lex_state_spcarg_p(parser, space_seen)) {
10233 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10234 type = PM_TOKEN_USTAR_STAR;
10235 }
else if (lex_state_beg_p(parser)) {
10236 type = PM_TOKEN_USTAR_STAR;
10237 }
else if (ambiguous_operator_p(parser, space_seen)) {
10238 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10241 if (lex_state_operator_p(parser)) {
10242 lex_state_set(parser, PM_LEX_STATE_ARG);
10244 lex_state_set(parser, PM_LEX_STATE_BEG);
10250 if (match(parser,
'=')) {
10251 lex_state_set(parser, PM_LEX_STATE_BEG);
10252 LEX(PM_TOKEN_STAR_EQUAL);
10255 pm_token_type_t
type = PM_TOKEN_STAR;
10257 if (lex_state_spcarg_p(parser, space_seen)) {
10258 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10259 type = PM_TOKEN_USTAR;
10260 }
else if (lex_state_beg_p(parser)) {
10261 type = PM_TOKEN_USTAR;
10262 }
else if (ambiguous_operator_p(parser, space_seen)) {
10263 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10266 if (lex_state_operator_p(parser)) {
10267 lex_state_set(parser, PM_LEX_STATE_ARG);
10269 lex_state_set(parser, PM_LEX_STATE_BEG);
10277 if (lex_state_operator_p(parser)) {
10278 lex_state_set(parser, PM_LEX_STATE_ARG);
10279 if (match(parser,
'@')) {
10280 LEX(PM_TOKEN_BANG);
10283 lex_state_set(parser, PM_LEX_STATE_BEG);
10286 if (match(parser,
'=')) {
10287 LEX(PM_TOKEN_BANG_EQUAL);
10290 if (match(parser,
'~')) {
10291 LEX(PM_TOKEN_BANG_TILDE);
10294 LEX(PM_TOKEN_BANG);
10299 current_token_starts_line(parser) &&
10301 memcmp(parser->
current.
end,
"begin", 5) == 0 &&
10302 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10304 pm_token_type_t
type = lex_embdoc(parser);
10305 if (
type == PM_TOKEN_EOF) {
10309 goto lex_next_token;
10312 if (lex_state_operator_p(parser)) {
10313 lex_state_set(parser, PM_LEX_STATE_ARG);
10315 lex_state_set(parser, PM_LEX_STATE_BEG);
10318 if (match(parser,
'>')) {
10319 LEX(PM_TOKEN_EQUAL_GREATER);
10322 if (match(parser,
'~')) {
10323 LEX(PM_TOKEN_EQUAL_TILDE);
10326 if (match(parser,
'=')) {
10327 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10330 LEX(PM_TOKEN_EQUAL);
10334 if (match(parser,
'<')) {
10336 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10337 !lex_state_end_p(parser) &&
10338 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10345 if (match(parser,
'-')) {
10346 indent = PM_HEREDOC_INDENT_DASH;
10348 else if (match(parser,
'~')) {
10349 indent = PM_HEREDOC_INDENT_TILDE;
10352 if (match(parser,
'`')) {
10353 quote = PM_HEREDOC_QUOTE_BACKTICK;
10355 else if (match(parser,
'"')) {
10356 quote = PM_HEREDOC_QUOTE_DOUBLE;
10358 else if (match(parser,
'\'')) {
10359 quote = PM_HEREDOC_QUOTE_SINGLE;
10362 const uint8_t *ident_start = parser->
current.
end;
10367 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.
end, parser->
end - parser->
current.
end)) == 0) {
10370 if (quote == PM_HEREDOC_QUOTE_NONE) {
10385 size_t ident_length = (size_t) (parser->
current.
end - ident_start);
10386 bool ident_error =
false;
10388 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10389 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
10390 ident_error =
true;
10395 .mode = PM_LEX_HEREDOC,
10398 .ident_start = ident_start,
10399 .ident_length = ident_length,
10404 .common_whitespace = NULL,
10405 .line_continuation =
false
10412 if (body_start == NULL) {
10417 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10418 body_start = parser->
end;
10422 pm_newline_list_append(&parser->
newline_list, body_start);
10431 LEX(PM_TOKEN_HEREDOC_START);
10435 if (match(parser,
'=')) {
10436 lex_state_set(parser, PM_LEX_STATE_BEG);
10437 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10440 if (ambiguous_operator_p(parser, space_seen)) {
10441 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10444 if (lex_state_operator_p(parser)) {
10445 lex_state_set(parser, PM_LEX_STATE_ARG);
10447 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10448 lex_state_set(parser, PM_LEX_STATE_BEG);
10451 LEX(PM_TOKEN_LESS_LESS);
10454 if (lex_state_operator_p(parser)) {
10455 lex_state_set(parser, PM_LEX_STATE_ARG);
10457 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10458 lex_state_set(parser, PM_LEX_STATE_BEG);
10461 if (match(parser,
'=')) {
10462 if (match(parser,
'>')) {
10463 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10466 LEX(PM_TOKEN_LESS_EQUAL);
10469 LEX(PM_TOKEN_LESS);
10473 if (match(parser,
'>')) {
10474 if (lex_state_operator_p(parser)) {
10475 lex_state_set(parser, PM_LEX_STATE_ARG);
10477 lex_state_set(parser, PM_LEX_STATE_BEG);
10479 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10482 if (lex_state_operator_p(parser)) {
10483 lex_state_set(parser, PM_LEX_STATE_ARG);
10485 lex_state_set(parser, PM_LEX_STATE_BEG);
10488 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10492 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10493 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10494 LEX(PM_TOKEN_STRING_BEGIN);
10499 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10500 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10501 LEX(PM_TOKEN_BACKTICK);
10504 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10505 if (previous_command_start) {
10506 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10508 lex_state_set(parser, PM_LEX_STATE_ARG);
10511 LEX(PM_TOKEN_BACKTICK);
10514 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10515 LEX(PM_TOKEN_BACKTICK);
10520 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10521 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10522 LEX(PM_TOKEN_STRING_BEGIN);
10527 LEX(lex_question_mark(parser));
10531 if (match(parser,
'&')) {
10532 lex_state_set(parser, PM_LEX_STATE_BEG);
10534 if (match(parser,
'=')) {
10535 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10538 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10541 if (match(parser,
'=')) {
10542 lex_state_set(parser, PM_LEX_STATE_BEG);
10543 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10546 if (match(parser,
'.')) {
10547 lex_state_set(parser, PM_LEX_STATE_DOT);
10548 LEX(PM_TOKEN_AMPERSAND_DOT);
10551 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10552 if (lex_state_spcarg_p(parser, space_seen)) {
10553 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10554 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10556 const uint8_t delim = peek_offset(parser, 1);
10558 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.
end + 1, parser->
end - (parser->
current.
end + 1))) {
10559 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10563 type = PM_TOKEN_UAMPERSAND;
10564 }
else if (lex_state_beg_p(parser)) {
10565 type = PM_TOKEN_UAMPERSAND;
10566 }
else if (ambiguous_operator_p(parser, space_seen)) {
10567 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10570 if (lex_state_operator_p(parser)) {
10571 lex_state_set(parser, PM_LEX_STATE_ARG);
10573 lex_state_set(parser, PM_LEX_STATE_BEG);
10581 if (match(parser,
'|')) {
10582 if (match(parser,
'=')) {
10583 lex_state_set(parser, PM_LEX_STATE_BEG);
10584 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10587 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10589 LEX(PM_TOKEN_PIPE);
10592 lex_state_set(parser, PM_LEX_STATE_BEG);
10593 LEX(PM_TOKEN_PIPE_PIPE);
10596 if (match(parser,
'=')) {
10597 lex_state_set(parser, PM_LEX_STATE_BEG);
10598 LEX(PM_TOKEN_PIPE_EQUAL);
10601 if (lex_state_operator_p(parser)) {
10602 lex_state_set(parser, PM_LEX_STATE_ARG);
10604 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10607 LEX(PM_TOKEN_PIPE);
10611 if (lex_state_operator_p(parser)) {
10612 lex_state_set(parser, PM_LEX_STATE_ARG);
10614 if (match(parser,
'@')) {
10615 LEX(PM_TOKEN_UPLUS);
10618 LEX(PM_TOKEN_PLUS);
10621 if (match(parser,
'=')) {
10622 lex_state_set(parser, PM_LEX_STATE_BEG);
10623 LEX(PM_TOKEN_PLUS_EQUAL);
10627 lex_state_beg_p(parser) ||
10628 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) :
false)
10630 lex_state_set(parser, PM_LEX_STATE_BEG);
10632 if (pm_char_is_decimal_digit(peek(parser))) {
10634 pm_token_type_t
type = lex_numeric(parser);
10635 lex_state_set(parser, PM_LEX_STATE_END);
10639 LEX(PM_TOKEN_UPLUS);
10642 if (ambiguous_operator_p(parser, space_seen)) {
10643 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
10646 lex_state_set(parser, PM_LEX_STATE_BEG);
10647 LEX(PM_TOKEN_PLUS);
10652 if (lex_state_operator_p(parser)) {
10653 lex_state_set(parser, PM_LEX_STATE_ARG);
10655 if (match(parser,
'@')) {
10656 LEX(PM_TOKEN_UMINUS);
10659 LEX(PM_TOKEN_MINUS);
10662 if (match(parser,
'=')) {
10663 lex_state_set(parser, PM_LEX_STATE_BEG);
10664 LEX(PM_TOKEN_MINUS_EQUAL);
10667 if (match(parser,
'>')) {
10668 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10669 LEX(PM_TOKEN_MINUS_GREATER);
10672 bool spcarg = lex_state_spcarg_p(parser, space_seen);
10673 bool is_beg = lex_state_beg_p(parser);
10674 if (!is_beg && spcarg) {
10675 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
10678 if (is_beg || spcarg) {
10679 lex_state_set(parser, PM_LEX_STATE_BEG);
10680 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
10683 if (ambiguous_operator_p(parser, space_seen)) {
10684 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
10687 lex_state_set(parser, PM_LEX_STATE_BEG);
10688 LEX(PM_TOKEN_MINUS);
10693 bool beg_p = lex_state_beg_p(parser);
10695 if (match(parser,
'.')) {
10696 if (match(parser,
'.')) {
10699 if (lex_state_p(parser, PM_LEX_STATE_END)) {
10700 lex_state_set(parser, PM_LEX_STATE_BEG);
10702 lex_state_set(parser, PM_LEX_STATE_ENDARG);
10704 LEX(PM_TOKEN_UDOT_DOT_DOT);
10708 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
10711 lex_state_set(parser, PM_LEX_STATE_BEG);
10712 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
10715 lex_state_set(parser, PM_LEX_STATE_BEG);
10716 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
10719 lex_state_set(parser, PM_LEX_STATE_DOT);
10734 pm_token_type_t
type = lex_numeric(parser);
10735 lex_state_set(parser, PM_LEX_STATE_END);
10741 if (match(parser,
':')) {
10742 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)) {
10743 lex_state_set(parser, PM_LEX_STATE_BEG);
10744 LEX(PM_TOKEN_UCOLON_COLON);
10747 lex_state_set(parser, PM_LEX_STATE_DOT);
10748 LEX(PM_TOKEN_COLON_COLON);
10751 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
10752 lex_state_set(parser, PM_LEX_STATE_BEG);
10753 LEX(PM_TOKEN_COLON);
10756 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
10757 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.
end);
10761 lex_state_set(parser, PM_LEX_STATE_FNAME);
10762 LEX(PM_TOKEN_SYMBOL_BEGIN);
10766 if (lex_state_beg_p(parser)) {
10767 lex_mode_push_regexp(parser,
'\0',
'/');
10768 LEX(PM_TOKEN_REGEXP_BEGIN);
10771 if (match(parser,
'=')) {
10772 lex_state_set(parser, PM_LEX_STATE_BEG);
10773 LEX(PM_TOKEN_SLASH_EQUAL);
10776 if (lex_state_spcarg_p(parser, space_seen)) {
10779 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
10781 lex_mode_push_regexp(parser,
'\0',
'/');
10782 LEX(PM_TOKEN_REGEXP_BEGIN);
10785 if (ambiguous_operator_p(parser, space_seen)) {
10786 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
10789 if (lex_state_operator_p(parser)) {
10790 lex_state_set(parser, PM_LEX_STATE_ARG);
10792 lex_state_set(parser, PM_LEX_STATE_BEG);
10795 LEX(PM_TOKEN_SLASH);
10799 if (lex_state_operator_p(parser)) {
10800 lex_state_set(parser, PM_LEX_STATE_ARG);
10802 lex_state_set(parser, PM_LEX_STATE_BEG);
10804 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
10808 if (lex_state_operator_p(parser)) {
10809 (void) match(parser,
'@');
10810 lex_state_set(parser, PM_LEX_STATE_ARG);
10812 lex_state_set(parser, PM_LEX_STATE_BEG);
10815 LEX(PM_TOKEN_TILDE);
10823 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.
end >= parser->
end)) {
10824 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
10825 LEX(PM_TOKEN_PERCENT);
10828 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
10829 lex_state_set(parser, PM_LEX_STATE_BEG);
10830 LEX(PM_TOKEN_PERCENT_EQUAL);
10832 lex_state_beg_p(parser) ||
10833 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
10834 lex_state_spcarg_p(parser, space_seen)
10838 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10841 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10842 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10843 LEX(PM_TOKEN_STRING_BEGIN);
10848 uint8_t delimiter = peek_offset(parser, 1);
10850 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10851 goto lex_next_token;
10854 switch (peek(parser)) {
10859 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10861 lex_mode_push_list_eof(parser);
10864 LEX(PM_TOKEN_PERCENT_LOWER_I);
10870 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10872 lex_mode_push_list_eof(parser);
10875 LEX(PM_TOKEN_PERCENT_UPPER_I);
10881 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10882 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10884 lex_mode_push_regexp(parser,
'\0',
'\0');
10887 LEX(PM_TOKEN_REGEXP_BEGIN);
10893 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10894 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10896 lex_mode_push_string_eof(parser);
10899 LEX(PM_TOKEN_STRING_BEGIN);
10905 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10906 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10908 lex_mode_push_string_eof(parser);
10911 LEX(PM_TOKEN_STRING_BEGIN);
10917 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10918 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10919 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
10921 lex_mode_push_string_eof(parser);
10924 LEX(PM_TOKEN_SYMBOL_BEGIN);
10930 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10932 lex_mode_push_list_eof(parser);
10935 LEX(PM_TOKEN_PERCENT_LOWER_W);
10941 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10943 lex_mode_push_list_eof(parser);
10946 LEX(PM_TOKEN_PERCENT_UPPER_W);
10952 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10953 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10955 lex_mode_push_string_eof(parser);
10958 LEX(PM_TOKEN_PERCENT_LOWER_X);
10965 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10966 goto lex_next_token;
10970 if (ambiguous_operator_p(parser, space_seen)) {
10971 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
10974 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
10975 LEX(PM_TOKEN_PERCENT);
10980 pm_token_type_t
type = lex_global_variable(parser);
10984 if (parser->lex_modes.
current->mode == PM_LEX_EMBVAR) {
10985 lex_mode_pop(parser);
10988 lex_state_set(parser, PM_LEX_STATE_END);
10994 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
10995 LEX(lex_at_variable(parser));
11007 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.
start);
11012 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
11016 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
11020 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11024 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11027 if (peek_at(parser, parser->
current.
start + 2) !=
'\n') {
11029 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11034 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11037 }
else if (char_is_ascii_printable(*parser->
current.
start)) {
11038 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.
start);
11040 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.
start);
11043 goto lex_next_token;
11049 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11057 current_token_starts_line(parser) &&
11064 const uint8_t *cursor = parser->
current.
end;
11065 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11066 pm_newline_list_append(&parser->
newline_list, cursor++);
11071 parser_lex_callback(parser);
11081 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11082 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11083 if (previous_command_start) {
11084 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11086 lex_state_set(parser, PM_LEX_STATE_ARG);
11088 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11089 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11091 lex_state_set(parser, PM_LEX_STATE_END);
11096 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11097 (
type == PM_TOKEN_IDENTIFIER) &&
11098 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11101 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11108 case PM_LEX_LIST: {
11123 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11130 if (whitespace > 0) {
11132 if (peek_offset(parser, -1) ==
'\n') {
11134 parser_flush_heredoc_end(parser);
11136 LEX(PM_TOKEN_WORDS_SEP);
11148 const uint8_t *breakpoints = lex_mode->as.list.breakpoints;
11149 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.
end, breakpoints, parser->
end - parser->
current.
end,
true);
11155 while (breakpoint != NULL) {
11158 if (pm_char_is_whitespace(*breakpoint)) {
11160 pm_token_buffer_flush(parser, &token_buffer);
11161 LEX(PM_TOKEN_STRING_CONTENT);
11166 if (*breakpoint == lex_mode->as.list.terminator) {
11169 if (lex_mode->as.list.nesting > 0) {
11172 lex_mode->as.list.nesting--;
11180 pm_token_buffer_flush(parser, &token_buffer);
11181 LEX(PM_TOKEN_STRING_CONTENT);
11187 lex_mode_pop(parser);
11188 lex_state_set(parser, PM_LEX_STATE_END);
11189 LEX(PM_TOKEN_STRING_END);
11193 if (*breakpoint ==
'\0') {
11194 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11201 if (*breakpoint ==
'\\') {
11211 pm_token_buffer_escape(parser, &token_buffer);
11212 uint8_t peeked = peek(parser);
11220 pm_token_buffer_push_byte(&token_buffer, peeked);
11225 if (peek(parser) !=
'\n') {
11226 pm_token_buffer_push_byte(&token_buffer,
'\r');
11231 pm_token_buffer_push_byte(&token_buffer,
'\n');
11237 parser_flush_heredoc_end(parser);
11238 pm_token_buffer_copy(parser, &token_buffer);
11239 LEX(PM_TOKEN_STRING_CONTENT);
11248 if (peeked == lex_mode->as.list.incrementor || peeked == lex_mode->as.list.terminator) {
11249 pm_token_buffer_push_byte(&token_buffer, peeked);
11251 }
else if (lex_mode->as.list.interpolation) {
11252 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11254 pm_token_buffer_push_byte(&token_buffer,
'\\');
11255 pm_token_buffer_push_escaped(&token_buffer, parser);
11267 if (*breakpoint ==
'#') {
11268 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11270 if (
type == PM_TOKEN_NOT_PROVIDED) {
11279 if (
type == PM_TOKEN_STRING_CONTENT) {
11280 pm_token_buffer_flush(parser, &token_buffer);
11288 assert(*breakpoint == lex_mode->as.list.incrementor);
11291 lex_mode->as.list.nesting++;
11296 pm_token_buffer_flush(parser, &token_buffer);
11297 LEX(PM_TOKEN_STRING_CONTENT);
11303 pm_token_buffer_flush(parser, &token_buffer);
11304 LEX(PM_TOKEN_STRING_CONTENT);
11306 case PM_LEX_REGEXP: {
11328 const uint8_t *breakpoints = lex_mode->as.regexp.breakpoints;
11329 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.
end, breakpoints, parser->
end - parser->
current.
end,
false);
11332 while (breakpoint != NULL) {
11333 uint8_t term = lex_mode->as.regexp.terminator;
11334 bool is_terminator = (*breakpoint == term);
11339 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11340 if (term ==
'\n') {
11341 is_terminator =
true;
11347 if (term ==
'\r') {
11348 is_terminator =
false;
11354 if (is_terminator) {
11355 if (lex_mode->as.regexp.nesting > 0) {
11358 lex_mode->as.regexp.nesting--;
11367 pm_regexp_token_buffer_flush(parser, &token_buffer);
11368 LEX(PM_TOKEN_STRING_CONTENT);
11372 size_t eol_length = match_eol_at(parser, breakpoint);
11374 parser->
current.
end = breakpoint + eol_length;
11390 lex_mode_pop(parser);
11391 lex_state_set(parser, PM_LEX_STATE_END);
11392 LEX(PM_TOKEN_REGEXP_END);
11397 if (*breakpoint && *breakpoint == lex_mode->as.regexp.incrementor) {
11400 lex_mode->as.regexp.nesting++;
11404 switch (*breakpoint) {
11411 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11419 pm_regexp_token_buffer_escape(parser, &token_buffer);
11427 pm_newline_list_append(&parser->
newline_list, breakpoint);
11434 parser_flush_heredoc_end(parser);
11435 pm_regexp_token_buffer_flush(parser, &token_buffer);
11436 LEX(PM_TOKEN_STRING_CONTENT);
11450 pm_regexp_token_buffer_escape(parser, &token_buffer);
11451 uint8_t peeked = peek(parser);
11456 if (peek(parser) !=
'\n') {
11457 if (lex_mode->as.regexp.terminator !=
'\r') {
11458 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11460 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11461 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11470 parser_flush_heredoc_end(parser);
11471 pm_regexp_token_buffer_copy(parser, &token_buffer);
11472 LEX(PM_TOKEN_STRING_CONTENT);
11488 if (lex_mode->as.regexp.terminator == peeked) {
11493 case '$':
case ')':
case '*':
case '+':
11494 case '.':
case '>':
case '?':
case ']':
11495 case '^':
case '|':
case '}':
11496 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11502 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11503 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11508 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11509 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11520 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11522 if (
type == PM_TOKEN_NOT_PROVIDED) {
11531 if (
type == PM_TOKEN_STRING_CONTENT) {
11532 pm_regexp_token_buffer_flush(parser, &token_buffer);
11538 assert(
false &&
"unreachable");
11544 pm_regexp_token_buffer_flush(parser, &token_buffer);
11545 LEX(PM_TOKEN_STRING_CONTENT);
11551 pm_regexp_token_buffer_flush(parser, &token_buffer);
11552 LEX(PM_TOKEN_STRING_CONTENT);
11554 case PM_LEX_STRING: {
11573 const uint8_t *breakpoints = lex_mode->as.string.breakpoints;
11574 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.
end, breakpoints, parser->
end - parser->
current.
end,
true);
11580 while (breakpoint != NULL) {
11583 if (lex_mode->as.string.incrementor !=
'\0' && *breakpoint == lex_mode->as.string.incrementor) {
11584 lex_mode->as.string.nesting++;
11590 uint8_t term = lex_mode->as.string.terminator;
11591 bool is_terminator = (*breakpoint == term);
11596 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11597 if (term ==
'\n') {
11598 is_terminator =
true;
11604 if (term ==
'\r') {
11605 is_terminator =
false;
11612 if (is_terminator) {
11615 if (lex_mode->as.string.nesting > 0) {
11618 lex_mode->as.string.nesting--;
11626 pm_token_buffer_flush(parser, &token_buffer);
11627 LEX(PM_TOKEN_STRING_CONTENT);
11632 size_t eol_length = match_eol_at(parser, breakpoint);
11634 parser->
current.
end = breakpoint + eol_length;
11646 if (lex_mode->as.string.label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
11648 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
11649 lex_mode_pop(parser);
11650 LEX(PM_TOKEN_LABEL_END);
11657 parser_flush_heredoc_end(parser);
11660 lex_state_set(parser, PM_LEX_STATE_END);
11661 lex_mode_pop(parser);
11662 LEX(PM_TOKEN_STRING_END);
11665 switch (*breakpoint) {
11672 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11682 pm_token_buffer_escape(parser, &token_buffer);
11683 token_buffer.
cursor = breakpoint;
11692 pm_newline_list_append(&parser->
newline_list, breakpoint);
11699 parser_flush_heredoc_end(parser);
11700 pm_token_buffer_flush(parser, &token_buffer);
11701 LEX(PM_TOKEN_STRING_CONTENT);
11713 pm_token_buffer_escape(parser, &token_buffer);
11714 uint8_t peeked = peek(parser);
11718 pm_token_buffer_push_byte(&token_buffer,
'\\');
11723 if (peek(parser) !=
'\n') {
11724 if (!lex_mode->as.string.interpolation) {
11725 pm_token_buffer_push_byte(&token_buffer,
'\\');
11727 pm_token_buffer_push_byte(&token_buffer,
'\r');
11732 if (!lex_mode->as.string.interpolation) {
11733 pm_token_buffer_push_byte(&token_buffer,
'\\');
11734 pm_token_buffer_push_byte(&token_buffer,
'\n');
11741 parser_flush_heredoc_end(parser);
11742 pm_token_buffer_copy(parser, &token_buffer);
11743 LEX(PM_TOKEN_STRING_CONTENT);
11752 if (lex_mode->as.string.incrementor !=
'\0' && peeked == lex_mode->as.string.incrementor) {
11753 pm_token_buffer_push_byte(&token_buffer, peeked);
11755 }
else if (lex_mode->as.string.terminator !=
'\0' && peeked == lex_mode->as.string.terminator) {
11756 pm_token_buffer_push_byte(&token_buffer, peeked);
11758 }
else if (lex_mode->as.string.interpolation) {
11759 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11761 pm_token_buffer_push_byte(&token_buffer,
'\\');
11762 pm_token_buffer_push_escaped(&token_buffer, parser);
11773 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11775 if (
type == PM_TOKEN_NOT_PROVIDED) {
11784 if (
type == PM_TOKEN_STRING_CONTENT) {
11785 pm_token_buffer_flush(parser, &token_buffer);
11791 assert(
false &&
"unreachable");
11796 pm_token_buffer_flush(parser, &token_buffer);
11797 LEX(PM_TOKEN_STRING_CONTENT);
11803 pm_token_buffer_flush(parser, &token_buffer);
11804 LEX(PM_TOKEN_STRING_CONTENT);
11806 case PM_LEX_HEREDOC: {
11822 bool line_continuation = lex_mode->as.heredoc.line_continuation;
11823 lex_mode->as.heredoc.line_continuation =
false;
11831 parser->
next_start = lex_mode->as.heredoc.next_start;
11833 lex_state_set(parser, PM_LEX_STATE_END);
11834 lex_mode_pop(parser);
11835 LEX(PM_TOKEN_HEREDOC_END);
11838 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
11843 if (current_token_starts_line(parser)) {
11846 if (!line_continuation && (start + ident_length <= parser->end)) {
11847 const uint8_t *newline = next_newline(start, parser->
end - start);
11848 const uint8_t *ident_end = newline;
11849 const uint8_t *terminator_end = newline;
11851 if (newline == NULL) {
11852 terminator_end = parser->
end;
11853 ident_end = parser->
end;
11856 if (newline[-1] ==
'\r') {
11861 const uint8_t *terminator_start = ident_end - ident_length;
11862 const uint8_t *cursor = start;
11864 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11865 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11871 (cursor == terminator_start) &&
11872 (memcmp(terminator_start, ident_start, ident_length) == 0)
11874 if (newline != NULL) {
11875 pm_newline_list_append(&parser->
newline_list, newline);
11879 if (*lex_mode->as.heredoc.next_start ==
'\\') {
11882 parser->
next_start = lex_mode->as.heredoc.next_start;
11886 lex_state_set(parser, PM_LEX_STATE_END);
11887 lex_mode_pop(parser);
11888 LEX(PM_TOKEN_HEREDOC_END);
11892 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
11894 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
11895 lex_mode->as.heredoc.common_whitespace != NULL &&
11896 (*lex_mode->as.heredoc.common_whitespace > whitespace) &&
11897 peek_at(parser, start) !=
'\n'
11899 *lex_mode->as.heredoc.common_whitespace = whitespace;
11906 uint8_t breakpoints[] =
"\r\n\\#";
11909 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11910 breakpoints[3] =
'\0';
11913 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.
end, breakpoints, parser->
end - parser->
current.
end,
true);
11915 bool was_line_continuation =
false;
11917 while (breakpoint != NULL) {
11918 switch (*breakpoint) {
11927 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11935 pm_token_buffer_escape(parser, &token_buffer);
11936 token_buffer.
cursor = breakpoint;
11941 parser_flush_heredoc_end(parser);
11943 pm_token_buffer_flush(parser, &token_buffer);
11944 LEX(PM_TOKEN_STRING_CONTENT);
11947 pm_newline_list_append(&parser->
newline_list, breakpoint);
11951 const uint8_t *start = breakpoint + 1;
11953 if (!was_line_continuation && (start + ident_length <= parser->end)) {
11956 const uint8_t *newline = next_newline(start, parser->
end - start);
11958 if (newline == NULL) {
11959 newline = parser->
end;
11960 }
else if (newline[-1] ==
'\r') {
11965 const uint8_t *terminator_start = newline - ident_length;
11969 const uint8_t *cursor = start;
11971 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11972 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11978 cursor == terminator_start &&
11979 (memcmp(terminator_start, ident_start, ident_length) == 0)
11982 pm_token_buffer_flush(parser, &token_buffer);
11983 LEX(PM_TOKEN_STRING_CONTENT);
11987 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->as.heredoc.base.indent);
11994 if (lex_mode->as.heredoc.base.indent == PM_HEREDOC_INDENT_TILDE) {
11995 if ((lex_mode->as.heredoc.common_whitespace != NULL) && (*lex_mode->as.heredoc.common_whitespace > whitespace) && peek_at(parser, start) !=
'\n') {
11996 *lex_mode->as.heredoc.common_whitespace = whitespace;
12000 pm_token_buffer_flush(parser, &token_buffer);
12001 LEX(PM_TOKEN_STRING_CONTENT);
12026 pm_token_buffer_escape(parser, &token_buffer);
12027 uint8_t peeked = peek(parser);
12029 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12033 if (peek(parser) !=
'\n') {
12034 pm_token_buffer_push_byte(&token_buffer,
'\\');
12035 pm_token_buffer_push_byte(&token_buffer,
'\r');
12040 pm_token_buffer_push_byte(&token_buffer,
'\\');
12041 pm_token_buffer_push_byte(&token_buffer,
'\n');
12046 pm_token_buffer_push_byte(&token_buffer,
'\\');
12047 pm_token_buffer_push_escaped(&token_buffer, parser);
12054 if (peek(parser) !=
'\n') {
12055 pm_token_buffer_push_byte(&token_buffer,
'\r');
12063 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12073 pm_token_buffer_flush(parser, &token_buffer);
12078 lex_mode->as.heredoc.line_continuation =
true;
12079 LEX(PM_TOKEN_STRING_CONTENT);
12082 was_line_continuation =
true;
12087 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12097 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12099 if (
type == PM_TOKEN_NOT_PROVIDED) {
12109 if (
type == PM_TOKEN_STRING_CONTENT) {
12110 pm_token_buffer_flush(parser, &token_buffer);
12116 assert(
false &&
"unreachable");
12119 was_line_continuation =
false;
12124 pm_token_buffer_flush(parser, &token_buffer);
12125 LEX(PM_TOKEN_STRING_CONTENT);
12131 pm_token_buffer_flush(parser, &token_buffer);
12132 LEX(PM_TOKEN_STRING_CONTENT);
12136 assert(
false &&
"unreachable");
12154 PM_BINDING_POWER_UNSET = 0,
12155 PM_BINDING_POWER_STATEMENT = 2,
12156 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12157 PM_BINDING_POWER_MODIFIER = 6,
12158 PM_BINDING_POWER_COMPOSITION = 8,
12159 PM_BINDING_POWER_NOT = 10,
12160 PM_BINDING_POWER_MATCH = 12,
12161 PM_BINDING_POWER_DEFINED = 14,
12162 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12163 PM_BINDING_POWER_ASSIGNMENT = 18,
12164 PM_BINDING_POWER_TERNARY = 20,
12165 PM_BINDING_POWER_RANGE = 22,
12166 PM_BINDING_POWER_LOGICAL_OR = 24,
12167 PM_BINDING_POWER_LOGICAL_AND = 26,
12168 PM_BINDING_POWER_EQUALITY = 28,
12169 PM_BINDING_POWER_COMPARISON = 30,
12170 PM_BINDING_POWER_BITWISE_OR = 32,
12171 PM_BINDING_POWER_BITWISE_AND = 34,
12172 PM_BINDING_POWER_SHIFT = 36,
12173 PM_BINDING_POWER_TERM = 38,
12174 PM_BINDING_POWER_FACTOR = 40,
12175 PM_BINDING_POWER_UMINUS = 42,
12176 PM_BINDING_POWER_EXPONENT = 44,
12177 PM_BINDING_POWER_UNARY = 46,
12178 PM_BINDING_POWER_INDEX = 48,
12179 PM_BINDING_POWER_CALL = 50,
12180 PM_BINDING_POWER_MAX = 52
12181} pm_binding_power_t;
12204#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12205#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12206#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12207#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12208#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12212 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12215 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12216 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12217 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12218 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12221 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12222 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12225 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12226 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12229 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12230 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12231 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12232 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12233 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12234 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12235 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12236 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12237 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12238 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12239 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12240 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12241 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12242 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12245 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12248 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12249 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12250 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12251 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12254 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12257 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12260 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12261 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12262 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12263 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12264 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12265 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12268 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12269 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12270 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12271 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12274 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12275 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12278 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12281 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12282 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12285 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12286 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12289 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12290 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12291 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12292 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12295 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12296 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12299 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12300 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12303 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12304 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12305 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12308 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12311 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12312 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12313 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12316#undef BINDING_POWER_ASSIGNMENT
12317#undef LEFT_ASSOCIATIVE
12318#undef RIGHT_ASSOCIATIVE
12319#undef RIGHT_ASSOCIATIVE_UNARY
12333match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12334 return match1(parser, type1) || match1(parser, type2);
12341match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12342 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12349match4(
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) {
12350 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12357match7(
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) {
12358 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
12365match8(
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) {
12366 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);
12377 if (match1(parser,
type)) {
12378 parser_lex(parser);
12389accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12390 if (match2(parser, type1, type2)) {
12391 parser_lex(parser);
12410 if (accept1(parser,
type))
return;
12413 pm_parser_err(parser, location, location, diag_id);
12425 if (accept2(parser, type1, type2))
return;
12428 pm_parser_err(parser, location, location, diag_id);
12439expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12440 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12441 parser_lex(parser);
12443 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12457 if (accept1(parser,
type))
return;
12459 pm_parser_err(parser, opening->
start, opening->
end, diag_id);
12466parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth);
12473parse_value_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth) {
12474 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
12475 pm_assert_value_expression(parser, node);
12498token_begins_expression_p(pm_token_type_t
type) {
12500 case PM_TOKEN_EQUAL_GREATER:
12501 case PM_TOKEN_KEYWORD_IN:
12505 case PM_TOKEN_BRACE_RIGHT:
12506 case PM_TOKEN_BRACKET_RIGHT:
12507 case PM_TOKEN_COLON:
12508 case PM_TOKEN_COMMA:
12509 case PM_TOKEN_EMBEXPR_END:
12511 case PM_TOKEN_LAMBDA_BEGIN:
12512 case PM_TOKEN_KEYWORD_DO:
12513 case PM_TOKEN_KEYWORD_DO_LOOP:
12514 case PM_TOKEN_KEYWORD_END:
12515 case PM_TOKEN_KEYWORD_ELSE:
12516 case PM_TOKEN_KEYWORD_ELSIF:
12517 case PM_TOKEN_KEYWORD_ENSURE:
12518 case PM_TOKEN_KEYWORD_THEN:
12519 case PM_TOKEN_KEYWORD_RESCUE:
12520 case PM_TOKEN_KEYWORD_WHEN:
12521 case PM_TOKEN_NEWLINE:
12522 case PM_TOKEN_PARENTHESIS_RIGHT:
12523 case PM_TOKEN_SEMICOLON:
12529 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12531 case PM_TOKEN_UAMPERSAND:
12535 case PM_TOKEN_UCOLON_COLON:
12536 case PM_TOKEN_UMINUS:
12537 case PM_TOKEN_UMINUS_NUM:
12538 case PM_TOKEN_UPLUS:
12539 case PM_TOKEN_BANG:
12540 case PM_TOKEN_TILDE:
12541 case PM_TOKEN_UDOT_DOT:
12542 case PM_TOKEN_UDOT_DOT_DOT:
12549 return pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET;
12558parse_starred_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
pm_diagnostic_id_t diag_id, uint16_t depth) {
12559 if (accept1(parser, PM_TOKEN_USTAR)) {
12561 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
12562 return UP(pm_splat_node_create(parser, &
operator, expression));
12565 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
12569pm_node_unreference_each(
const pm_node_t *node,
void *data) {
12570 switch (PM_NODE_TYPE(node)) {
12575 case PM_BREAK_NODE:
12577 case PM_REDO_NODE: {
12581 while (index < parser->current_block_exits->size) {
12584 if (block_exit == node) {
12607 case PM_LOCAL_VARIABLE_READ_NODE:
12608 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12612 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
12613 if (implicit_parameters->
nodes[index] == node) {
12617 if (index != implicit_parameters->
size - 1) {
12618 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(pm_node_t *));
12621 implicit_parameters->
size--;
12639pm_node_unreference(
pm_parser_t *parser,
const pm_node_t *node) {
12640 pm_visit_node(node, pm_node_unreference_each, parser);
12654 size_t length = constant->
length;
12655 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
12656 if (name == NULL)
return;
12658 memcpy(name, constant->
start, length);
12659 name[length] =
'=';
12664 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
12674parse_unwriteable_target(
pm_parser_t *parser, pm_node_t *target) {
12675 switch (PM_NODE_TYPE(target)) {
12676 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12677 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12678 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12679 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12680 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12681 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12682 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
12687 pm_local_variable_target_node_t *result = pm_local_variable_target_node_create(parser, &target->
location, name, 0);
12689 pm_node_destroy(parser, target);
12702parse_target(
pm_parser_t *parser, pm_node_t *target,
bool multiple,
bool splat_parent) {
12703 switch (PM_NODE_TYPE(target)) {
12704 case PM_MISSING_NODE:
12706 case PM_SOURCE_ENCODING_NODE:
12707 case PM_FALSE_NODE:
12708 case PM_SOURCE_FILE_NODE:
12709 case PM_SOURCE_LINE_NODE:
12712 case PM_TRUE_NODE: {
12715 return parse_unwriteable_target(parser, target);
12717 case PM_CLASS_VARIABLE_READ_NODE:
12718 assert(
sizeof(pm_class_variable_target_node_t) ==
sizeof(pm_class_variable_read_node_t));
12719 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
12721 case PM_CONSTANT_PATH_NODE:
12722 if (context_def_p(parser)) {
12723 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12726 assert(
sizeof(pm_constant_path_target_node_t) ==
sizeof(pm_constant_path_node_t));
12727 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
12730 case PM_CONSTANT_READ_NODE:
12731 if (context_def_p(parser)) {
12732 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12735 assert(
sizeof(pm_constant_target_node_t) ==
sizeof(pm_constant_read_node_t));
12736 target->
type = PM_CONSTANT_TARGET_NODE;
12739 case PM_BACK_REFERENCE_READ_NODE:
12740 case PM_NUMBERED_REFERENCE_READ_NODE:
12741 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12743 case PM_GLOBAL_VARIABLE_READ_NODE:
12744 assert(
sizeof(pm_global_variable_target_node_t) ==
sizeof(pm_global_variable_read_node_t));
12745 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
12747 case PM_LOCAL_VARIABLE_READ_NODE: {
12750 pm_node_unreference(parser, target);
12753 const pm_local_variable_read_node_t *cast = (
const pm_local_variable_read_node_t *) target;
12754 uint32_t name = cast->
name;
12755 uint32_t depth = cast->
depth;
12756 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
12758 assert(
sizeof(pm_local_variable_target_node_t) ==
sizeof(pm_local_variable_read_node_t));
12759 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
12763 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12765 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
12767 pm_node_unreference(parser, target);
12768 pm_node_destroy(parser, target);
12772 case PM_INSTANCE_VARIABLE_READ_NODE:
12773 assert(
sizeof(pm_instance_variable_target_node_t) ==
sizeof(pm_instance_variable_read_node_t));
12774 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
12776 case PM_MULTI_TARGET_NODE:
12777 if (splat_parent) {
12780 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12784 case PM_SPLAT_NODE: {
12785 pm_splat_node_t *splat = (pm_splat_node_t *) target;
12793 case PM_CALL_NODE: {
12794 pm_call_node_t *call = (pm_call_node_t *) target;
12805 (call->
block == NULL)
12820 pm_node_destroy(parser, target);
12822 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
12826 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
12827 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
12830 parse_write_name(parser, &call->
name);
12831 return UP(pm_call_target_node_create(parser, call));
12838 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12839 return UP(pm_index_target_node_create(parser, call));
12847 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12857parse_target_validate(
pm_parser_t *parser, pm_node_t *target,
bool multiple) {
12858 pm_node_t *result = parse_target(parser, target, multiple,
false);
12863 !match1(parser, PM_TOKEN_EQUAL) &&
12865 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
12867 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
12878parse_shareable_constant_write(
pm_parser_t *parser, pm_node_t *write) {
12881 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
12882 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
12893 switch (PM_NODE_TYPE(target)) {
12894 case PM_MISSING_NODE:
12895 pm_node_destroy(parser, value);
12897 case PM_CLASS_VARIABLE_READ_NODE: {
12898 pm_class_variable_write_node_t *node = pm_class_variable_write_node_create(parser, (pm_class_variable_read_node_t *) target,
operator, value);
12899 pm_node_destroy(parser, target);
12902 case PM_CONSTANT_PATH_NODE: {
12903 pm_node_t *node = UP(pm_constant_path_write_node_create(parser, (pm_constant_path_node_t *) target,
operator, value));
12905 if (context_def_p(parser)) {
12906 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12909 return parse_shareable_constant_write(parser, node);
12911 case PM_CONSTANT_READ_NODE: {
12912 pm_node_t *node = UP(pm_constant_write_node_create(parser, (pm_constant_read_node_t *) target,
operator, value));
12914 if (context_def_p(parser)) {
12915 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12918 pm_node_destroy(parser, target);
12919 return parse_shareable_constant_write(parser, node);
12921 case PM_BACK_REFERENCE_READ_NODE:
12922 case PM_NUMBERED_REFERENCE_READ_NODE:
12923 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12925 case PM_GLOBAL_VARIABLE_READ_NODE: {
12926 pm_global_variable_write_node_t *node = pm_global_variable_write_node_create(parser, target,
operator, value);
12927 pm_node_destroy(parser, target);
12930 case PM_LOCAL_VARIABLE_READ_NODE: {
12931 pm_local_variable_read_node_t *local_read = (pm_local_variable_read_node_t *) target;
12936 uint32_t depth = local_read->
depth;
12937 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
12940 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
12942 pm_node_unreference(parser, target);
12945 pm_locals_unread(&scope->
locals, name);
12946 pm_node_destroy(parser, target);
12948 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator));
12950 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12952 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
12954 pm_node_unreference(parser, target);
12955 pm_node_destroy(parser, target);
12959 case PM_INSTANCE_VARIABLE_READ_NODE: {
12960 pm_node_t *write_node = UP(pm_instance_variable_write_node_create(parser, (pm_instance_variable_read_node_t *) target,
operator, value));
12961 pm_node_destroy(parser, target);
12964 case PM_MULTI_TARGET_NODE:
12965 return UP(pm_multi_write_node_create(parser, (pm_multi_target_node_t *) target,
operator, value));
12966 case PM_SPLAT_NODE: {
12967 pm_splat_node_t *splat = (pm_splat_node_t *) target;
12973 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
12974 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
12976 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
12978 case PM_CALL_NODE: {
12979 pm_call_node_t *call = (pm_call_node_t *) target;
12990 (call->
block == NULL)
13004 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
13005 pm_node_destroy(parser, target);
13008 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator));
13010 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13025 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
13028 pm_arguments_node_arguments_append(arguments, value);
13030 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13032 parse_write_name(parser, &call->
name);
13033 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13042 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13044 call->
arguments = pm_arguments_node_create(parser);
13047 pm_arguments_node_arguments_append(call->
arguments, value);
13051 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13052 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13056 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13071 pm_node_unreference(parser, value);
13072 pm_node_destroy(parser, value);
13079 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13091parse_unwriteable_write(
pm_parser_t *parser, pm_node_t *target,
const pm_token_t *equals, pm_node_t *value) {
13092 switch (PM_NODE_TYPE(target)) {
13093 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13094 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13095 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13096 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13097 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13098 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13099 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13104 pm_local_variable_write_node_t *result = pm_local_variable_write_node_create(parser, name, 0, value, &target->
location, equals);
13106 pm_node_destroy(parser, target);
13121parse_targets(
pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13122 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13124 pm_multi_target_node_t *result = pm_multi_target_node_create(parser);
13125 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13127 while (accept1(parser, PM_TOKEN_COMMA)) {
13128 if (accept1(parser, PM_TOKEN_USTAR)) {
13133 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13137 pm_node_t *name = NULL;
13139 if (token_begins_expression_p(parser->
current.
type)) {
13140 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13141 name = parse_target(parser, name,
true,
true);
13144 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13145 pm_multi_target_node_targets_append(parser, result, splat);
13147 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13149 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13150 target = parse_target(parser, target,
true,
false);
13152 pm_multi_target_node_targets_append(parser, result, target);
13153 context_pop(parser);
13154 }
else if (token_begins_expression_p(parser->
current.
type)) {
13155 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13156 target = parse_target(parser, target,
true,
false);
13158 pm_multi_target_node_targets_append(parser, result, target);
13159 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13162 pm_node_t *rest = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13163 pm_multi_target_node_targets_append(parser, result, rest);
13176parse_targets_validate(
pm_parser_t *parser, pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13177 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13178 accept1(parser, PM_TOKEN_NEWLINE);
13181 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13182 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13191static pm_statements_node_t *
13195 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13198 if (context_terminator(context, &parser->
current))
return NULL;
13200 pm_statements_node_t *statements = pm_statements_node_create(parser);
13204 context_push(parser, context);
13207 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13208 pm_statements_node_body_append(parser, statements, node,
true);
13221 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13224 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13225 if (context_terminator(context, &parser->
current))
break;
13235 if (context_terminator(context, &parser->
current))
break;
13247 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
13248 parser_lex(parser);
13254 if (match1(parser, PM_TOKEN_EOF)) {
13259 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13260 if (context_terminator(context, &parser->
current))
break;
13261 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13271 context_pop(parser);
13272 bool last_value =
true;
13276 last_value =
false;
13281 pm_void_statements_check(parser, statements, last_value);
13292 const pm_node_t *duplicated = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
true);
13294 if (duplicated != NULL) {
13298 pm_diagnostic_list_append_format(
13302 PM_WARN_DUPLICATED_HASH_KEY,
13303 (
int) pm_buffer_length(&buffer),
13304 pm_buffer_value(&buffer),
13308 pm_buffer_free(&buffer);
13318 pm_node_t *previous;
13320 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
13321 pm_diagnostic_list_append_format(
13325 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13337 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13338 bool contains_keyword_splat =
false;
13341 pm_node_t *element;
13344 case PM_TOKEN_USTAR_STAR: {
13345 parser_lex(parser);
13347 pm_node_t *value = NULL;
13349 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
13355 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13356 }
else if (token_begins_expression_p(parser->
current.
type)) {
13357 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13359 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13362 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13363 contains_keyword_splat =
true;
13366 case PM_TOKEN_LABEL: {
13368 parser_lex(parser);
13370 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13371 pm_hash_key_static_literals_add(parser, literals, key);
13374 pm_node_t *value = NULL;
13376 if (token_begins_expression_p(parser->
current.
type)) {
13377 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13380 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13381 value = UP(pm_constant_read_node_create(parser, &constant));
13384 pm_token_t identifier = { .type = PM_TOKEN_IDENTIFIER, .start = label.
start, .end = label.
end - 1 };
13386 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13387 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13389 depth = pm_parser_local_depth(parser, &identifier);
13393 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13395 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13400 value = UP(pm_implicit_node_create(parser, value));
13403 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13407 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
13411 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13412 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13415 pm_hash_key_static_literals_add(parser, literals, key);
13418 if (pm_symbol_node_label_p(key)) {
13419 operator = not_provided(parser);
13421 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13425 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13426 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13431 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13432 pm_hash_node_elements_append((pm_hash_node_t *) node, element);
13434 pm_keyword_hash_node_elements_append((pm_keyword_hash_node_t *) node, element);
13438 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13442 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13446 if (token_begins_expression_p(parser->
current.
type))
continue;
13452 return contains_keyword_splat;
13456argument_allowed_for_bare_hash(
pm_parser_t *parser, pm_node_t *argument) {
13457 if (pm_symbol_node_label_p(argument)) {
13461 switch (PM_NODE_TYPE(argument)) {
13462 case PM_CALL_NODE: {
13463 pm_call_node_t *cast = (pm_call_node_t *) argument;
13465 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13468 if (cast->
block != NULL) {
13476 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
13485 arguments->
arguments = pm_arguments_node_create(parser);
13488 pm_arguments_node_arguments_append(arguments->
arguments, argument);
13495parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
13496 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.
type].left;
13501 match2(parser, terminator, PM_TOKEN_EOF) ||
13502 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
13508 bool parsed_first_argument =
false;
13509 bool parsed_bare_hash =
false;
13510 bool parsed_block_argument =
false;
13511 bool parsed_forwarding_arguments =
false;
13513 while (!match1(parser, PM_TOKEN_EOF)) {
13514 if (parsed_forwarding_arguments) {
13515 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
13518 pm_node_t *argument = NULL;
13521 case PM_TOKEN_USTAR_STAR:
13522 case PM_TOKEN_LABEL: {
13523 if (parsed_bare_hash) {
13524 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
13527 pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
13528 argument = UP(hash);
13531 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
13533 parse_arguments_append(parser, arguments, argument);
13535 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13536 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13537 pm_node_flag_set(UP(arguments->
arguments), flags);
13539 pm_static_literals_free(&hash_keys);
13540 parsed_bare_hash =
true;
13544 case PM_TOKEN_UAMPERSAND: {
13545 parser_lex(parser);
13547 pm_node_t *expression = NULL;
13549 if (token_begins_expression_p(parser->
current.
type)) {
13550 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13552 pm_parser_scope_forwarding_block_check(parser, &
operator);
13555 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
13556 if (parsed_block_argument) {
13557 parse_arguments_append(parser, arguments, argument);
13559 arguments->
block = argument;
13562 if (match1(parser, PM_TOKEN_COMMA)) {
13563 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
13566 parsed_block_argument =
true;
13569 case PM_TOKEN_USTAR: {
13570 parser_lex(parser);
13573 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
13574 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
13575 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
13576 if (parsed_bare_hash) {
13577 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13580 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
13582 if (parsed_bare_hash) {
13583 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13586 argument = UP(pm_splat_node_create(parser, &
operator, expression));
13589 parse_arguments_append(parser, arguments, argument);
13592 case PM_TOKEN_UDOT_DOT_DOT: {
13593 if (accepts_forwarding) {
13594 parser_lex(parser);
13596 if (token_begins_expression_p(parser->
current.
type)) {
13601 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
13606 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
13607 pm_range_node_t *range = (pm_range_node_t *) right;
13608 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
13611 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
13613 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
13614 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
13615 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
13618 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->
previous));
13619 parse_arguments_append(parser, arguments, argument);
13620 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
13622 parsed_forwarding_arguments =
true;
13629 if (argument == NULL) {
13630 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13633 bool contains_keywords =
false;
13634 bool contains_keyword_splat =
false;
13636 if (argument_allowed_for_bare_hash(parser, argument)){
13637 if (parsed_bare_hash) {
13638 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
13642 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
13645 operator = not_provided(parser);
13648 pm_keyword_hash_node_t *bare_hash = pm_keyword_hash_node_create(parser);
13649 contains_keywords =
true;
13653 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
13656 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13657 argument = UP(pm_assoc_node_create(parser, argument, &
operator, value));
13659 pm_keyword_hash_node_elements_append(bare_hash, argument);
13660 argument = UP(bare_hash);
13663 if (accept1(parser, PM_TOKEN_COMMA) && (
13664 token_begins_expression_p(parser->
current.
type) ||
13665 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
13667 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
13670 pm_static_literals_free(&hash_keys);
13671 parsed_bare_hash =
true;
13674 parse_arguments_append(parser, arguments, argument);
13676 pm_node_flags_t flags = 0;
13677 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13678 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13679 pm_node_flag_set(UP(arguments->
arguments), flags);
13685 parsed_first_argument =
true;
13688 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
13693 bool accepted_newline =
false;
13694 if (terminator != PM_TOKEN_EOF) {
13695 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
13698 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
13702 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
13705 if (accepted_newline) {
13706 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13712 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
13713 pm_call_node_t *call = (pm_call_node_t *) argument;
13715 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13727 if (match1(parser, terminator))
break;
13741static pm_multi_target_node_t *
13742parse_required_destructured_parameter(
pm_parser_t *parser) {
13743 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
13745 pm_multi_target_node_t *node = pm_multi_target_node_create(parser);
13746 pm_multi_target_node_opening_set(node, &parser->
previous);
13755 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
13756 param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13757 pm_multi_target_node_targets_append(parser, node, param);
13758 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13762 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13763 param = UP(parse_required_destructured_parameter(parser));
13764 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
13766 pm_node_t *value = NULL;
13768 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13770 value = UP(pm_required_parameter_node_create(parser, &name));
13771 if (pm_parser_parameter_name_check(parser, &name)) {
13772 pm_node_flag_set_repeated_parameter(value);
13774 pm_parser_local_add_token(parser, &name, 1);
13777 param = UP(pm_splat_node_create(parser, &star, value));
13779 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
13782 param = UP(pm_required_parameter_node_create(parser, &name));
13783 if (pm_parser_parameter_name_check(parser, &name)) {
13784 pm_node_flag_set_repeated_parameter(param);
13786 pm_parser_local_add_token(parser, &name, 1);
13789 pm_multi_target_node_targets_append(parser, node, param);
13790 }
while (accept1(parser, PM_TOKEN_COMMA));
13792 accept1(parser, PM_TOKEN_NEWLINE);
13793 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
13794 pm_multi_target_node_closing_set(node, &parser->
previous);
13804 PM_PARAMETERS_NO_CHANGE = 0,
13805 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
13806 PM_PARAMETERS_ORDER_KEYWORDS_REST,
13807 PM_PARAMETERS_ORDER_KEYWORDS,
13808 PM_PARAMETERS_ORDER_REST,
13809 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13810 PM_PARAMETERS_ORDER_OPTIONAL,
13811 PM_PARAMETERS_ORDER_NAMED,
13812 PM_PARAMETERS_ORDER_NONE,
13813} pm_parameters_order_t;
13818static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
13819 [0] = PM_PARAMETERS_NO_CHANGE,
13820 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13821 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13822 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13823 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
13824 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
13825 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
13826 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
13827 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13828 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13829 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
13830 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
13842 pm_parameters_order_t state = parameters_ordering[token->
type];
13843 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
13847 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13848 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
13850 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13854 if (token->
type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13855 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
13857 }
else if (token->
type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
13858 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
13860 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
13862 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
13866 if (state < *current) *current = state;
13873static pm_parameters_node_t *
13876 pm_binding_power_t binding_power,
13877 bool uses_parentheses,
13878 bool allows_trailing_comma,
13879 bool allows_forwarding_parameters,
13880 bool accepts_blocks_in_defaults,
13885 pm_do_loop_stack_push(parser,
false);
13887 pm_parameters_node_t *params = pm_parameters_node_create(parser);
13888 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
13891 bool parsing =
true;
13894 case PM_TOKEN_PARENTHESIS_LEFT: {
13895 update_parameter_state(parser, &parser->
current, &order);
13896 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
13898 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13899 pm_parameters_node_requireds_append(params, param);
13901 pm_parameters_node_posts_append(params, param);
13905 case PM_TOKEN_UAMPERSAND:
13906 case PM_TOKEN_AMPERSAND: {
13907 update_parameter_state(parser, &parser->
current, &order);
13908 parser_lex(parser);
13913 bool repeated =
false;
13914 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13916 repeated = pm_parser_parameter_name_check(parser, &name);
13917 pm_parser_local_add_token(parser, &name, 1);
13919 name = not_provided(parser);
13923 pm_block_parameter_node_t *param = pm_block_parameter_node_create(parser, &name, &
operator);
13925 pm_node_flag_set_repeated_parameter(UP(param));
13927 if (params->
block == NULL) {
13928 pm_parameters_node_block_set(params, param);
13930 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_BLOCK_MULTI);
13931 pm_parameters_node_posts_append(params, UP(param));
13936 case PM_TOKEN_UDOT_DOT_DOT: {
13937 if (!allows_forwarding_parameters) {
13938 pm_parser_err_current(parser, diag_id_forwarding);
13941 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
13942 parser_lex(parser);
13945 pm_forwarding_parameter_node_t *param = pm_forwarding_parameter_node_create(parser, &parser->
previous);
13951 pm_parameters_node_posts_append(params, keyword_rest);
13952 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
13956 pm_parameters_node_keyword_rest_set(params, UP(param));
13959 case PM_TOKEN_CLASS_VARIABLE:
13960 case PM_TOKEN_IDENTIFIER:
13961 case PM_TOKEN_CONSTANT:
13962 case PM_TOKEN_INSTANCE_VARIABLE:
13963 case PM_TOKEN_GLOBAL_VARIABLE:
13964 case PM_TOKEN_METHOD_NAME: {
13965 parser_lex(parser);
13967 case PM_TOKEN_CONSTANT:
13968 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
13970 case PM_TOKEN_INSTANCE_VARIABLE:
13971 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
13973 case PM_TOKEN_GLOBAL_VARIABLE:
13974 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
13976 case PM_TOKEN_CLASS_VARIABLE:
13977 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
13979 case PM_TOKEN_METHOD_NAME:
13980 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
13986 update_parameter_state(parser, &parser->
current, &order);
13988 update_parameter_state(parser, &parser->
previous, &order);
13992 bool repeated = pm_parser_parameter_name_check(parser, &name);
13993 pm_parser_local_add_token(parser, &name, 1);
13995 if (match1(parser, PM_TOKEN_EQUAL)) {
13998 parser_lex(parser);
14003 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14004 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
14005 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14007 pm_optional_parameter_node_t *param = pm_optional_parameter_node_create(parser, &name, &
operator, value);
14010 pm_node_flag_set_repeated_parameter(UP(param));
14012 pm_parameters_node_optionals_append(params, param);
14018 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
14021 context_pop(parser);
14030 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14031 pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
14033 pm_node_flag_set_repeated_parameter(UP(param));
14035 pm_parameters_node_requireds_append(params, UP(param));
14037 pm_required_parameter_node_t *param = pm_required_parameter_node_create(parser, &name);
14039 pm_node_flag_set_repeated_parameter(UP(param));
14041 pm_parameters_node_posts_append(params, UP(param));
14046 case PM_TOKEN_LABEL: {
14047 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14048 update_parameter_state(parser, &parser->
current, &order);
14051 parser_lex(parser);
14058 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14059 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14060 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14063 bool repeated = pm_parser_parameter_name_check(parser, &local);
14064 pm_parser_local_add_token(parser, &local, 1);
14067 case PM_TOKEN_COMMA:
14068 case PM_TOKEN_PARENTHESIS_RIGHT:
14069 case PM_TOKEN_PIPE: {
14070 context_pop(parser);
14072 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14074 pm_node_flag_set_repeated_parameter(param);
14077 pm_parameters_node_keywords_append(params, param);
14080 case PM_TOKEN_SEMICOLON:
14081 case PM_TOKEN_NEWLINE: {
14082 context_pop(parser);
14084 if (uses_parentheses) {
14089 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14091 pm_node_flag_set_repeated_parameter(param);
14094 pm_parameters_node_keywords_append(params, param);
14100 if (token_begins_expression_p(parser->
current.
type)) {
14104 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14105 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14106 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14109 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14112 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14115 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14119 pm_node_flag_set_repeated_parameter(param);
14122 context_pop(parser);
14123 pm_parameters_node_keywords_append(params, param);
14138 case PM_TOKEN_USTAR:
14139 case PM_TOKEN_STAR: {
14140 update_parameter_state(parser, &parser->
current, &order);
14141 parser_lex(parser);
14145 bool repeated =
false;
14147 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14149 repeated = pm_parser_parameter_name_check(parser, &name);
14150 pm_parser_local_add_token(parser, &name, 1);
14152 name = not_provided(parser);
14156 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, &name));
14158 pm_node_flag_set_repeated_parameter(param);
14161 if (params->
rest == NULL) {
14162 pm_parameters_node_rest_set(params, param);
14164 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14165 pm_parameters_node_posts_append(params, param);
14170 case PM_TOKEN_STAR_STAR:
14171 case PM_TOKEN_USTAR_STAR: {
14172 pm_parameters_order_t previous_order = order;
14173 update_parameter_state(parser, &parser->
current, &order);
14174 parser_lex(parser);
14179 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14180 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14181 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14184 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
14188 bool repeated =
false;
14189 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14191 repeated = pm_parser_parameter_name_check(parser, &name);
14192 pm_parser_local_add_token(parser, &name, 1);
14194 name = not_provided(parser);
14198 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, &name));
14200 pm_node_flag_set_repeated_parameter(param);
14205 pm_parameters_node_keyword_rest_set(params, param);
14207 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14208 pm_parameters_node_posts_append(params, param);
14215 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14218 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
14220 if (params->
rest == NULL) {
14221 pm_parameters_node_rest_set(params, param);
14223 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14224 pm_parameters_node_posts_append(params, UP(param));
14227 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14238 if (!parsing)
break;
14240 bool accepted_newline =
false;
14241 if (uses_parentheses) {
14242 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14245 if (accept1(parser, PM_TOKEN_COMMA)) {
14248 if (accepted_newline) {
14249 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14257 pm_do_loop_stack_pop(parser);
14261 pm_node_destroy(parser, UP(params));
14293token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14295 const uint8_t *end = token->
start;
14299 newline_index == 0 &&
14300 parser->
start[0] == 0xef &&
14301 parser->
start[1] == 0xbb &&
14302 parser->
start[2] == 0xbf
14305 int64_t column = 0;
14306 for (; cursor < end; cursor++) {
14309 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14316 if (break_on_non_space)
return -1;
14329parser_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) {
14334 size_t closing_newline_index = token_newline_index(parser);
14335 if (opening_newline_index == closing_newline_index)
return;
14340 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14341 if (!if_after_else && (opening_column == -1))
return;
14348 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14349 if ((closing_column == -1) || (opening_column == closing_column))
return;
14353 if (allow_indent && (closing_column > opening_column))
return;
14356 PM_PARSER_WARN_FORMAT(
14358 closing_token->
start,
14359 closing_token->
end,
14360 PM_WARN_INDENTATION_MISMATCH,
14361 (
int) (closing_token->
end - closing_token->
start),
14362 (
const char *) closing_token->
start,
14363 (
int) (opening_token->
end - opening_token->
start),
14364 (
const char *) opening_token->
start,
14365 ((int32_t) opening_newline_index) + parser->
start_line
14370 PM_RESCUES_BEGIN = 1,
14377} pm_rescues_type_t;
14384parse_rescues(
pm_parser_t *parser,
size_t opening_newline_index,
const pm_token_t *opening, pm_begin_node_t *parent_node, pm_rescues_type_t
type, uint16_t depth) {
14385 pm_rescue_node_t *current = NULL;
14387 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
14388 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14389 parser_lex(parser);
14391 pm_rescue_node_t *rescue = pm_rescue_node_create(parser, &parser->
previous);
14394 case PM_TOKEN_EQUAL_GREATER: {
14398 parser_lex(parser);
14399 pm_rescue_node_operator_set(rescue, &parser->
previous);
14401 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14402 reference = parse_target(parser, reference,
false,
false);
14404 pm_rescue_node_reference_set(rescue, reference);
14407 case PM_TOKEN_NEWLINE:
14408 case PM_TOKEN_SEMICOLON:
14409 case PM_TOKEN_KEYWORD_THEN:
14414 if (token_begins_expression_p(parser->
current.
type) || match1(parser, PM_TOKEN_USTAR)) {
14419 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
14420 pm_rescue_node_exceptions_append(rescue, expression);
14424 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
14428 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14429 pm_rescue_node_operator_set(rescue, &parser->
previous);
14431 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14432 reference = parse_target(parser, reference,
false,
false);
14434 pm_rescue_node_reference_set(rescue, reference);
14437 }
while (accept1(parser, PM_TOKEN_COMMA));
14442 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14443 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
14447 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
14451 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
14452 pm_accepts_block_stack_push(parser,
true);
14466 pm_statements_node_t *statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14467 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
14469 pm_accepts_block_stack_pop(parser);
14470 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14473 if (current == NULL) {
14474 pm_begin_node_rescue_clause_set(parent_node, rescue);
14476 pm_rescue_node_subsequent_set(current, rescue);
14485 if (current != NULL) {
14489 while (clause != NULL) {
14496 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
14497 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14498 opening_newline_index = token_newline_index(parser);
14500 else_keyword = parser->
current;
14501 opening = &else_keyword;
14503 parser_lex(parser);
14504 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14506 pm_statements_node_t *else_statements = NULL;
14507 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
14508 pm_accepts_block_stack_push(parser,
true);
14522 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14523 pm_accepts_block_stack_pop(parser);
14525 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14528 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
14529 pm_begin_node_else_clause_set(parent_node, else_clause);
14533 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
14536 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
14537 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14540 parser_lex(parser);
14541 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14543 pm_statements_node_t *ensure_statements = NULL;
14544 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14545 pm_accepts_block_stack_push(parser,
true);
14559 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14560 pm_accepts_block_stack_pop(parser);
14562 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14565 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
14566 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
14569 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
14570 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14571 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
14574 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
14582static pm_begin_node_t *
14583parse_rescues_implicit_begin(
pm_parser_t *parser,
size_t opening_newline_index,
const pm_token_t *opening,
const uint8_t *start, pm_statements_node_t *statements, pm_rescues_type_t
type, uint16_t depth) {
14584 pm_token_t begin_keyword = not_provided(parser);
14585 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
14587 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
14596static pm_block_parameters_node_t *
14597parse_block_parameters(
14599 bool allows_trailing_comma,
14601 bool is_lambda_literal,
14602 bool accepts_blocks_in_defaults,
14605 pm_parameters_node_t *parameters = NULL;
14606 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
14607 if (!is_lambda_literal) {
14610 parameters = parse_parameters(
14612 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
14614 allows_trailing_comma,
14616 accepts_blocks_in_defaults,
14618 is_lambda_literal ? PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_LAMBDA : PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES_BLOCK,
14619 (uint16_t) (depth + 1)
14621 if (!is_lambda_literal) {
14622 context_pop(parser);
14626 pm_block_parameters_node_t *block_parameters = pm_block_parameters_node_create(parser, parameters, opening);
14627 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
14628 accept1(parser, PM_TOKEN_NEWLINE);
14630 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
14633 case PM_TOKEN_CONSTANT:
14634 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14635 parser_lex(parser);
14637 case PM_TOKEN_INSTANCE_VARIABLE:
14638 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14639 parser_lex(parser);
14641 case PM_TOKEN_GLOBAL_VARIABLE:
14642 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14643 parser_lex(parser);
14645 case PM_TOKEN_CLASS_VARIABLE:
14646 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14647 parser_lex(parser);
14650 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
14654 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
14655 pm_parser_local_add_token(parser, &parser->
previous, 1);
14657 pm_block_local_variable_node_t *local = pm_block_local_variable_node_create(parser, &parser->
previous);
14658 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
14660 pm_block_parameters_node_append_local(block_parameters, local);
14661 }
while (accept1(parser, PM_TOKEN_COMMA));
14665 return block_parameters;
14673outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
14675 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
14686static const char *
const pm_numbered_parameter_names[] = {
14687 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
14701 if (parameters != NULL) {
14703 if (implicit_parameters->
size > 0) {
14704 pm_node_t *node = implicit_parameters->
nodes[0];
14706 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14707 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
14708 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14709 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
14711 assert(
false &&
"unreachable");
14720 if (implicit_parameters->
size == 0) {
14727 uint8_t numbered_parameter = 0;
14728 bool it_parameter =
false;
14730 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
14731 pm_node_t *node = implicit_parameters->
nodes[index];
14733 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14734 if (it_parameter) {
14735 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
14736 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
14737 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
14739 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
14741 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
14743 assert(
false &&
"unreachable");
14745 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14746 if (numbered_parameter > 0) {
14747 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
14749 it_parameter =
true;
14754 if (numbered_parameter > 0) {
14758 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
14762 return UP(pm_numbered_parameters_node_create(parser, &location, numbered_parameter));
14765 if (it_parameter) {
14766 return UP(pm_it_parameters_node_create(parser, opening, closing));
14775static pm_block_node_t *
14776parse_block(
pm_parser_t *parser, uint16_t depth) {
14778 accept1(parser, PM_TOKEN_NEWLINE);
14780 pm_accepts_block_stack_push(parser,
true);
14781 pm_parser_scope_push(parser,
false);
14783 pm_block_parameters_node_t *block_parameters = NULL;
14785 if (accept1(parser, PM_TOKEN_PIPE)) {
14787 if (match1(parser, PM_TOKEN_PIPE)) {
14788 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
14790 parser_lex(parser);
14792 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
14793 accept1(parser, PM_TOKEN_NEWLINE);
14795 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
14798 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
14801 accept1(parser, PM_TOKEN_NEWLINE);
14802 pm_node_t *statements = NULL;
14804 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
14805 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
14809 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
14811 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14812 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
14813 pm_accepts_block_stack_push(parser,
true);
14815 pm_accepts_block_stack_pop(parser);
14818 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
14819 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
14820 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
14824 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
14828 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
14829 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->
previous);
14831 pm_parser_scope_pop(parser);
14832 pm_accepts_block_stack_pop(parser);
14834 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
14843parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
14844 bool found =
false;
14846 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14850 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14853 pm_accepts_block_stack_push(parser,
true);
14854 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
14856 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14862 pm_accepts_block_stack_pop(parser);
14865 }
else if (accepts_command_call && (token_begins_expression_p(parser->
current.
type) || match3(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR, PM_TOKEN_UAMPERSAND)) && !match1(parser, PM_TOKEN_BRACE_LEFT)) {
14867 pm_accepts_block_stack_push(parser,
false);
14872 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
14877 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
14881 pm_accepts_block_stack_pop(parser);
14887 if (accepts_block) {
14888 pm_block_node_t *block = NULL;
14890 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
14892 block = parse_block(parser, (uint16_t) (depth + 1));
14893 pm_arguments_validate_block(parser, arguments, block);
14894 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
14896 block = parse_block(parser, (uint16_t) (depth + 1));
14899 if (block != NULL) {
14901 arguments->
block = UP(block);
14903 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
14905 if (arguments->
block != NULL) {
14907 arguments->
arguments = pm_arguments_node_create(parser);
14909 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
14911 arguments->
block = UP(block);
14924parse_return(
pm_parser_t *parser, pm_node_t *node) {
14925 bool in_sclass =
false;
14927 switch (context_node->
context) {
14972 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14995 assert(
false &&
"unreachable");
15000 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
15009parse_block_exit(
pm_parser_t *parser, pm_node_t *node) {
15011 switch (context_node->
context) {
15086 assert(
false &&
"unreachable");
15096static pm_node_list_t *
15097push_block_exits(
pm_parser_t *parser, pm_node_list_t *current_block_exits) {
15100 return previous_block_exits;
15109flush_block_exits(
pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
15110 pm_node_t *block_exit;
15114 switch (PM_NODE_TYPE(block_exit)) {
15115 case PM_BREAK_NODE:
type =
"break";
break;
15116 case PM_NEXT_NODE:
type =
"next";
break;
15117 case PM_REDO_NODE:
type =
"redo";
break;
15118 default: assert(
false &&
"unreachable");
type =
"";
break;
15121 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15132pop_block_exits(
pm_parser_t *parser, pm_node_list_t *previous_block_exits) {
15133 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15138 }
else if (previous_block_exits != NULL) {
15150 flush_block_exits(parser, previous_block_exits);
15154static inline pm_node_t *
15158 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15161 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15163 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15164 predicate_closed =
true;
15168 if (!predicate_closed) {
15169 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15172 context_pop(parser);
15176static inline pm_node_t *
15177parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15178 pm_node_list_t current_block_exits = { 0 };
15179 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15182 pm_token_t then_keyword = not_provided(parser);
15184 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15185 pm_statements_node_t *statements = NULL;
15187 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15188 pm_accepts_block_stack_push(parser,
true);
15189 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15190 pm_accepts_block_stack_pop(parser);
15191 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15194 pm_token_t end_keyword = not_provided(parser);
15195 pm_node_t *parent = NULL;
15199 parent = UP(pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15202 parent = UP(pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements));
15205 assert(
false &&
"unreachable");
15209 pm_node_t *current = parent;
15214 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15215 if (parser_end_of_line_p(parser)) {
15216 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15219 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15221 parser_lex(parser);
15223 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15224 pm_accepts_block_stack_push(parser,
true);
15226 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_ELSIF, (uint16_t) (depth + 1));
15227 pm_accepts_block_stack_pop(parser);
15228 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15230 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15231 ((pm_if_node_t *) current)->subsequent = elsif;
15236 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15237 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15238 opening_newline_index = token_newline_index(parser);
15240 parser_lex(parser);
15243 pm_accepts_block_stack_push(parser,
true);
15244 pm_statements_node_t *else_statements = parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1));
15245 pm_accepts_block_stack_pop(parser);
15247 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15248 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15249 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
15251 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15255 ((pm_if_node_t *) current)->subsequent = UP(else_node);
15258 ((pm_unless_node_t *) parent)->else_clause = else_node;
15261 assert(
false &&
"unreachable");
15265 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15266 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
15272 pm_node_t *current = parent;
15273 bool recursing =
true;
15275 while (recursing) {
15276 switch (PM_NODE_TYPE(current)) {
15278 pm_if_node_end_keyword_loc_set((pm_if_node_t *) current, &parser->
previous);
15279 current = ((pm_if_node_t *) current)->subsequent;
15280 recursing = current != NULL;
15283 pm_else_node_end_keyword_loc_set((pm_else_node_t *) current, &parser->
previous);
15295 pm_unless_node_end_keyword_loc_set((pm_unless_node_t *) parent, &parser->
previous);
15298 assert(
false &&
"unreachable");
15302 pop_block_exits(parser, previous_block_exits);
15303 pm_node_list_free(¤t_block_exits);
15312#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15313 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15314 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15315 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15316 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15317 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15318 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15319 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15320 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15321 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15322 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15328#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15329 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15330 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15331 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15332 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15333 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15334 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15335 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15342#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15343 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15344 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15345 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15346 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15347 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15348 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15349 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15350 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15356#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15357 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15358 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15359 case PM_TOKEN_CLASS_VARIABLE
15365#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15366 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15367 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15368 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15372PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15378static inline pm_node_flags_t
15379parse_unescaped_encoding(
const pm_parser_t *parser) {
15384 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15390 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15401parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15409 case PM_TOKEN_STRING_CONTENT: {
15413 pm_node_t *node = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
15414 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15416 parser_lex(parser);
15425 case PM_TOKEN_EMBEXPR_BEGIN: {
15434 lex_state_set(parser, PM_LEX_STATE_BEG);
15435 parser_lex(parser);
15438 pm_statements_node_t *statements = NULL;
15440 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
15441 pm_accepts_block_stack_push(parser,
true);
15443 pm_accepts_block_stack_pop(parser);
15447 lex_state_set(parser, state);
15449 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15455 if (statements != NULL && statements->
body.
size == 1) {
15456 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15459 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &closing));
15468 case PM_TOKEN_EMBVAR: {
15473 lex_state_set(parser, PM_LEX_STATE_BEG);
15474 parser_lex(parser);
15477 pm_node_t *variable;
15482 case PM_TOKEN_BACK_REFERENCE:
15483 parser_lex(parser);
15484 variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15488 case PM_TOKEN_NUMBERED_REFERENCE:
15489 parser_lex(parser);
15490 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15494 case PM_TOKEN_GLOBAL_VARIABLE:
15495 parser_lex(parser);
15496 variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15500 case PM_TOKEN_INSTANCE_VARIABLE:
15501 parser_lex(parser);
15502 variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
15506 case PM_TOKEN_CLASS_VARIABLE:
15507 parser_lex(parser);
15508 variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
15514 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15519 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15522 parser_lex(parser);
15523 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15533static const uint8_t *
15534parse_operator_symbol_name(
const pm_token_t *name) {
15535 switch (name->
type) {
15536 case PM_TOKEN_TILDE:
15537 case PM_TOKEN_BANG:
15538 if (name->
end[-1] ==
'@')
return name->
end - 1;
15548 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, opening, &parser->
current, &closing);
15550 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
15552 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15553 parser_lex(parser);
15556 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15570 if (lex_mode->mode != PM_LEX_STRING) {
15571 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15574 case PM_CASE_OPERATOR:
15575 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15576 case PM_TOKEN_IDENTIFIER:
15577 case PM_TOKEN_CONSTANT:
15578 case PM_TOKEN_INSTANCE_VARIABLE:
15579 case PM_TOKEN_METHOD_NAME:
15580 case PM_TOKEN_CLASS_VARIABLE:
15581 case PM_TOKEN_GLOBAL_VARIABLE:
15582 case PM_TOKEN_NUMBERED_REFERENCE:
15583 case PM_TOKEN_BACK_REFERENCE:
15584 case PM_CASE_KEYWORD:
15585 parser_lex(parser);
15588 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15593 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
15596 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15601 if (lex_mode->as.string.interpolation) {
15603 if (match1(parser, PM_TOKEN_STRING_END)) {
15604 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15605 parser_lex(parser);
15609 return UP(pm_symbol_node_create(parser, &opening, &content, &closing));
15613 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15617 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15618 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15619 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15621 return UP(pm_string_node_to_symbol_node(parser, (pm_string_node_t *) part, &opening, &parser->
previous));
15624 pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
15625 if (part) pm_interpolated_symbol_node_append(symbol, part);
15627 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15628 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15629 pm_interpolated_symbol_node_append(symbol, part);
15633 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15634 if (match1(parser, PM_TOKEN_EOF)) {
15635 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15637 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15640 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15647 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15650 parser_lex(parser);
15661 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15662 pm_interpolated_symbol_node_t *symbol = pm_interpolated_symbol_node_create(parser, &opening, NULL, &opening);
15665 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped));
15666 pm_interpolated_symbol_node_append(symbol, part);
15668 part = UP(pm_string_node_create_unescaped(parser, &bounds, &parser->
current, &bounds, &parser->
current_string));
15669 pm_interpolated_symbol_node_append(symbol, part);
15671 if (next_state != PM_LEX_STATE_NONE) {
15672 lex_state_set(parser, next_state);
15675 parser_lex(parser);
15676 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15678 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15683 pm_string_shared_init(&unescaped, content.
start, content.
end);
15686 if (next_state != PM_LEX_STATE_NONE) {
15687 lex_state_set(parser, next_state);
15690 if (match1(parser, PM_TOKEN_EOF)) {
15691 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15693 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15696 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
15703static inline pm_node_t *
15704parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
15706 case PM_CASE_OPERATOR: {
15707 const pm_token_t opening = not_provided(parser);
15708 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
15710 case PM_CASE_KEYWORD:
15711 case PM_TOKEN_CONSTANT:
15712 case PM_TOKEN_IDENTIFIER:
15713 case PM_TOKEN_METHOD_NAME: {
15714 parser_lex(parser);
15718 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
15721 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15725 case PM_TOKEN_SYMBOL_BEGIN: {
15727 parser_lex(parser);
15729 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15732 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
15743static inline pm_node_t *
15744parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
15746 case PM_CASE_OPERATOR: {
15747 const pm_token_t opening = not_provided(parser);
15748 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
15750 case PM_CASE_KEYWORD:
15751 case PM_TOKEN_CONSTANT:
15752 case PM_TOKEN_IDENTIFIER:
15753 case PM_TOKEN_METHOD_NAME: {
15754 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
15755 parser_lex(parser);
15759 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &parser->
previous, &closing);
15762 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15766 case PM_TOKEN_SYMBOL_BEGIN: {
15768 parser_lex(parser);
15770 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15772 case PM_TOKEN_BACK_REFERENCE:
15773 parser_lex(parser);
15774 return UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15775 case PM_TOKEN_NUMBERED_REFERENCE:
15776 parser_lex(parser);
15777 return UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15778 case PM_TOKEN_GLOBAL_VARIABLE:
15779 parser_lex(parser);
15780 return UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15782 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
15797 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
15798 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false));
15802 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
15803 if (is_numbered_param) {
15808 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
15809 for (uint8_t number = 1; number <= maximum; number++) {
15810 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
15813 if (!match1(parser, PM_TOKEN_EQUAL)) {
15817 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false));
15822 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->
previous));
15837 pm_node_flags_t flags = 0;
15839 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
15840 pm_node_t *node = parse_variable(parser);
15841 if (node != NULL)
return node;
15842 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
15845 pm_call_node_t *node = pm_call_node_variable_call_create(parser, &parser->
previous);
15846 pm_node_flag_set(UP(node), flags);
15857parse_method_definition_name(
pm_parser_t *parser) {
15859 case PM_CASE_KEYWORD:
15860 case PM_TOKEN_CONSTANT:
15861 case PM_TOKEN_METHOD_NAME:
15862 parser_lex(parser);
15864 case PM_TOKEN_IDENTIFIER:
15866 parser_lex(parser);
15868 case PM_CASE_OPERATOR:
15869 lex_state_set(parser, PM_LEX_STATE_ENDFN);
15870 parser_lex(parser);
15879parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
15882 pm_string_ensure_owned(
string);
15887 size_t dest_length = pm_string_length(
string);
15888 const uint8_t *source_cursor = (uint8_t *) string->
source;
15889 const uint8_t *source_end = source_cursor + dest_length;
15894 size_t trimmed_whitespace = 0;
15900 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
15901 if (*source_cursor ==
'\t') {
15902 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
15903 if (trimmed_whitespace > common_whitespace)
break;
15905 trimmed_whitespace++;
15912 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
15913 string->length = dest_length;
15920parse_heredoc_dedent(
pm_parser_t *parser, pm_node_list_t *nodes,
size_t common_whitespace) {
15923 bool dedent_next =
true;
15928 size_t write_index = 0;
15935 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
15936 nodes->
nodes[write_index++] = node;
15937 dedent_next =
false;
15941 pm_string_node_t *string_node = ((pm_string_node_t *) node);
15943 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
15947 pm_node_destroy(parser, node);
15949 nodes->
nodes[write_index++] = node;
15953 dedent_next =
true;
15956 nodes->
size = write_index;
15963parse_strings_empty_content(
const uint8_t *location) {
15964 return (
pm_token_t) { .type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
15970static inline pm_node_t *
15971parse_strings(
pm_parser_t *parser, pm_node_t *current,
bool accepts_label, uint16_t depth) {
15972 assert(parser->
current.
type == PM_TOKEN_STRING_BEGIN);
15973 bool concating =
false;
15975 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
15976 pm_node_t *node = NULL;
15981 assert(lex_mode->mode == PM_LEX_STRING);
15982 bool lex_interpolation = lex_mode->as.string.interpolation;
15983 bool label_allowed = lex_mode->as.string.label_allowed && accepts_label;
15986 parser_lex(parser);
15988 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15989 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
15994 pm_string_node_t *
string = pm_string_node_create(parser, &opening, &content, &parser->
previous);
15998 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16003 pm_symbol_node_t *symbol = pm_symbol_node_create(parser, &opening, &content, &parser->
previous);
16008 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16009 }
else if (!lex_interpolation) {
16015 if (match1(parser, PM_TOKEN_EOF)) {
16017 content = not_provided(parser);
16020 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16035 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16036 pm_node_list_t parts = { 0 };
16038 pm_token_t delimiters = not_provided(parser);
16039 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped));
16040 pm_node_list_append(&parts, part);
16043 part = UP(pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters));
16044 pm_node_list_append(&parts, part);
16045 parser_lex(parser);
16046 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16048 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16049 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16051 pm_node_list_free(&parts);
16052 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16053 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16054 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16055 }
else if (match1(parser, PM_TOKEN_EOF)) {
16056 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16057 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16058 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16059 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16064 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16066 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16073 parser_lex(parser);
16075 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16076 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16077 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16083 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16085 if (location > parser->
start && location[-1] ==
'\n') location--;
16086 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16091 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16092 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16093 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16097 pm_node_list_t parts = { 0 };
16098 pm_token_t string_opening = not_provided(parser);
16099 pm_token_t string_closing = not_provided(parser);
16101 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped));
16102 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16103 pm_node_list_append(&parts, part);
16105 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16106 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16107 pm_node_list_append(&parts, part);
16111 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16112 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16113 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16114 }
else if (match1(parser, PM_TOKEN_EOF)) {
16115 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16116 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16118 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16119 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16122 pm_node_list_free(&parts);
16128 pm_node_list_t parts = { 0 };
16131 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16132 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16133 pm_node_list_append(&parts, part);
16137 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16138 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16139 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16140 }
else if (match1(parser, PM_TOKEN_EOF)) {
16141 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16142 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16144 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16145 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16148 pm_node_list_free(&parts);
16151 if (current == NULL) {
16155 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16166 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16167 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16173 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16174 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16180 pm_interpolated_string_node_t *container = pm_interpolated_string_node_create(parser, &bounds, NULL, &bounds);
16181 pm_interpolated_string_node_append(container, current);
16182 current = UP(container);
16185 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, node);
16192#define PM_PARSE_PATTERN_SINGLE 0
16193#define PM_PARSE_PATTERN_TOP 1
16194#define PM_PARSE_PATTERN_MULTI 2
16207 if (peek_at(parser, location->
start) ==
'_')
return;
16209 if (pm_constant_id_list_includes(captures, capture)) {
16210 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16212 pm_constant_id_list_append(captures, capture);
16223 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16225 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16226 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
16232 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16238 pm_node_t *inner = NULL;
16240 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16242 accept1(parser, PM_TOKEN_NEWLINE);
16244 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16245 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16246 accept1(parser, PM_TOKEN_NEWLINE);
16247 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16252 parser_lex(parser);
16254 accept1(parser, PM_TOKEN_NEWLINE);
16256 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16257 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16258 accept1(parser, PM_TOKEN_NEWLINE);
16259 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16268 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16275 switch (PM_NODE_TYPE(inner)) {
16276 case PM_ARRAY_PATTERN_NODE: {
16277 pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
16284 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16285 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16287 return UP(pattern_node);
16292 case PM_FIND_PATTERN_NODE: {
16293 pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
16300 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16301 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16303 return UP(pattern_node);
16308 case PM_HASH_PATTERN_NODE: {
16309 pm_hash_pattern_node_t *pattern_node = (pm_hash_pattern_node_t *) inner;
16316 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16317 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16319 return UP(pattern_node);
16331 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16332 pm_array_pattern_node_requireds_append(pattern_node, inner);
16333 return UP(pattern_node);
16339static pm_splat_node_t *
16343 pm_node_t *name = NULL;
16348 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16350 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16353 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16354 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16357 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16358 name = UP(pm_local_variable_target_node_create(
16360 &PM_LOCATION_TOKEN_VALUE(&identifier),
16362 (uint32_t) (depth == -1 ? 0 : depth)
16367 return pm_splat_node_create(parser, &
operator, name);
16375 assert(parser->
current.
type == PM_TOKEN_USTAR_STAR);
16376 parser_lex(parser);
16379 pm_node_t *value = NULL;
16381 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16382 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
16385 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16389 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16393 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16394 value = UP(pm_local_variable_target_node_create(
16396 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16398 (uint32_t) (depth == -1 ? 0 : depth)
16402 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16410pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16411 ptrdiff_t length = end - start;
16412 if (length == 0)
return false;
16415 size_t width = char_is_identifier_start(parser, start, end - start);
16416 if (width == 0)
return false;
16422 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16427 const uint8_t *cursor = start + width;
16428 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16429 return cursor == end;
16438 const pm_location_t *value_loc = &((pm_symbol_node_t *) key)->value_loc;
16443 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
16444 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16448 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
16449 PM_PARSER_ERR_LOCATION_FORMAT(parser, value_loc, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE, (
int) (value_loc->
end - value_loc->
start), (
const char *) value_loc->
start);
16454 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
16457 parse_pattern_capture(parser, captures, constant_id, value_loc);
16458 pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
16462 (uint32_t) (depth == -1 ? 0 : depth)
16465 return UP(pm_implicit_node_create(parser, UP(target)));
16475 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16482static pm_hash_pattern_node_t *
16484 pm_node_list_t assocs = { 0 };
16486 pm_node_t *rest = NULL;
16488 switch (PM_NODE_TYPE(first_node)) {
16489 case PM_ASSOC_SPLAT_NODE:
16490 case PM_NO_KEYWORDS_PARAMETER_NODE:
16493 case PM_SYMBOL_NODE: {
16494 if (pm_symbol_node_label_p(first_node)) {
16495 parse_pattern_hash_key(parser, &keys, first_node);
16498 if (match8(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
16501 value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) first_node);
16505 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16509 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16511 pm_node_list_append(&assocs, assoc);
16520 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;
16521 pm_parser_err_node(parser, first_node, diag_id);
16525 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16527 pm_node_list_append(&assocs, assoc);
16533 while (accept1(parser, PM_TOKEN_COMMA)) {
16535 if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF)) {
16537 if (rest != NULL) {
16538 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16544 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16545 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16547 if (rest == NULL) {
16550 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16551 pm_node_list_append(&assocs, assoc);
16556 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16557 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16559 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16560 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16561 }
else if (!pm_symbol_node_label_p(key)) {
16562 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16565 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16566 key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16569 parse_pattern_hash_key(parser, &keys, key);
16570 pm_node_t *value = NULL;
16572 if (match7(parser, PM_TOKEN_COMMA, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
16573 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16574 value = parse_pattern_hash_implicit_value(parser, captures, (pm_symbol_node_t *) key);
16579 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16583 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, &
operator, value));
16585 if (rest != NULL) {
16586 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16589 pm_node_list_append(&assocs, assoc);
16593 pm_hash_pattern_node_t *node = pm_hash_pattern_node_node_list_create(parser, &assocs, rest);
16596 pm_static_literals_free(&keys);
16606 case PM_TOKEN_IDENTIFIER:
16607 case PM_TOKEN_METHOD_NAME: {
16608 parser_lex(parser);
16612 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16616 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16617 return UP(pm_local_variable_target_node_create(
16619 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16621 (uint32_t) (depth == -1 ? 0 : depth)
16624 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16626 parser_lex(parser);
16628 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16631 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous));
16636 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16638 accept1(parser, PM_TOKEN_NEWLINE);
16639 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16642 switch (PM_NODE_TYPE(inner)) {
16643 case PM_ARRAY_PATTERN_NODE: {
16644 pm_array_pattern_node_t *pattern_node = (pm_array_pattern_node_t *) inner;
16649 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16650 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16652 return UP(pattern_node);
16657 case PM_FIND_PATTERN_NODE: {
16658 pm_find_pattern_node_t *pattern_node = (pm_find_pattern_node_t *) inner;
16663 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16664 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16666 return UP(pattern_node);
16675 pm_array_pattern_node_t *node = pm_array_pattern_node_empty_create(parser, &opening, &closing);
16676 pm_array_pattern_node_requireds_append(node, inner);
16679 case PM_TOKEN_BRACE_LEFT: {
16683 pm_hash_pattern_node_t *node;
16685 parser_lex(parser);
16687 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16690 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
16692 pm_node_t *first_node;
16695 case PM_TOKEN_LABEL:
16696 parser_lex(parser);
16697 first_node = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16699 case PM_TOKEN_USTAR_STAR:
16700 first_node = parse_pattern_keyword_rest(parser, captures);
16702 case PM_TOKEN_STRING_BEGIN:
16703 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
16707 parser_lex(parser);
16714 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
16716 accept1(parser, PM_TOKEN_NEWLINE);
16717 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
16723 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16724 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16730 case PM_TOKEN_UDOT_DOT:
16731 case PM_TOKEN_UDOT_DOT_DOT: {
16733 parser_lex(parser);
16738 case PM_CASE_PRIMITIVE: {
16739 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16740 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16743 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
16744 pm_node_t *right = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16745 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16749 case PM_CASE_PRIMITIVE: {
16750 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
16753 if (pm_symbol_node_label_p(node))
return node;
16756 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
16757 pm_parser_err_node(parser, node, diag_id);
16760 pm_node_unreference(parser, node);
16761 pm_node_destroy(parser, node);
16762 return UP(missing_node);
16766 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
16773 case PM_CASE_PRIMITIVE: {
16774 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16775 return UP(pm_range_node_create(parser, node, &
operator, right));
16778 return UP(pm_range_node_create(parser, node, &
operator, NULL));
16784 case PM_TOKEN_CARET: {
16785 parser_lex(parser);
16791 case PM_TOKEN_IDENTIFIER: {
16792 parser_lex(parser);
16793 pm_node_t *variable = UP(parse_variable(parser));
16795 if (variable == NULL) {
16796 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
16797 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0));
16800 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16802 case PM_TOKEN_INSTANCE_VARIABLE: {
16803 parser_lex(parser);
16804 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
16806 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16808 case PM_TOKEN_CLASS_VARIABLE: {
16809 parser_lex(parser);
16810 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
16812 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16814 case PM_TOKEN_GLOBAL_VARIABLE: {
16815 parser_lex(parser);
16816 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
16818 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16820 case PM_TOKEN_NUMBERED_REFERENCE: {
16821 parser_lex(parser);
16822 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
16824 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16826 case PM_TOKEN_BACK_REFERENCE: {
16827 parser_lex(parser);
16828 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
16830 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16832 case PM_TOKEN_PARENTHESIS_LEFT: {
16837 parser_lex(parser);
16839 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
16842 accept1(parser, PM_TOKEN_NEWLINE);
16843 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
16844 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous));
16849 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
16850 pm_node_t *variable = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16851 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16855 case PM_TOKEN_UCOLON_COLON: {
16857 parser_lex(parser);
16859 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16860 pm_constant_path_node_t *node = pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous);
16862 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
16864 case PM_TOKEN_CONSTANT: {
16866 parser_lex(parser);
16868 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
16869 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
16872 pm_parser_err_current(parser, diag_id);
16878parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
16879 switch (PM_NODE_TYPE(node)) {
16880 case PM_LOCAL_VARIABLE_TARGET_NODE:
16893parse_pattern_alternation_error(
pm_parser_t *parser,
const pm_node_t *node) {
16894 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
16903 pm_node_t *node = first_node;
16904 bool alternation =
false;
16906 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
16907 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
16908 parse_pattern_alternation_error(parser, node);
16912 case PM_TOKEN_IDENTIFIER:
16913 case PM_TOKEN_BRACKET_LEFT_ARRAY:
16914 case PM_TOKEN_BRACE_LEFT:
16915 case PM_TOKEN_CARET:
16916 case PM_TOKEN_CONSTANT:
16917 case PM_TOKEN_UCOLON_COLON:
16918 case PM_TOKEN_UDOT_DOT:
16919 case PM_TOKEN_UDOT_DOT_DOT:
16920 case PM_CASE_PRIMITIVE: {
16921 if (!alternation) {
16922 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16925 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
16927 if (captures->
size) parse_pattern_alternation_error(parser, right);
16928 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16933 case PM_TOKEN_PARENTHESIS_LEFT:
16934 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
16937 parser_lex(parser);
16939 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16940 accept1(parser, PM_TOKEN_NEWLINE);
16941 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16942 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->
previous, 0));
16944 if (!alternation) {
16947 if (captures->
size) parse_pattern_alternation_error(parser, right);
16948 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16954 pm_parser_err_current(parser, diag_id);
16957 if (!alternation) {
16960 if (captures->
size) parse_pattern_alternation_error(parser, right);
16961 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->
previous));
16971 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
16973 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
16978 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16982 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16983 pm_local_variable_target_node_t *target = pm_local_variable_target_node_create(
16985 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16987 (uint32_t) (depth == -1 ? 0 : depth)
16990 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
17001 pm_node_t *node = NULL;
17003 bool leading_rest =
false;
17004 bool trailing_rest =
false;
17007 case PM_TOKEN_LABEL: {
17008 parser_lex(parser);
17009 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
17010 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
17012 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17013 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17018 case PM_TOKEN_USTAR_STAR: {
17019 node = parse_pattern_keyword_rest(parser, captures);
17020 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17022 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17023 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17028 case PM_TOKEN_STRING_BEGIN: {
17031 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17033 if (pm_symbol_node_label_p(node)) {
17034 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17036 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17037 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17043 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17046 case PM_TOKEN_USTAR: {
17047 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17048 parser_lex(parser);
17049 node = UP(parse_pattern_rest(parser, captures));
17050 leading_rest =
true;
17056 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17062 if (pm_symbol_node_label_p(node)) {
17063 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17066 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17070 pm_node_list_t nodes = { 0 };
17071 pm_node_list_append(&nodes, node);
17074 while (accept1(parser, PM_TOKEN_COMMA)) {
17076 if (match7(parser, PM_TOKEN_KEYWORD_THEN, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_AND, PM_TOKEN_KEYWORD_OR)) {
17077 node = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
17078 pm_node_list_append(&nodes, node);
17079 trailing_rest =
true;
17083 if (accept1(parser, PM_TOKEN_USTAR)) {
17084 node = UP(parse_pattern_rest(parser, captures));
17089 if (trailing_rest) {
17090 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17093 trailing_rest =
true;
17095 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17098 pm_node_list_append(&nodes, node);
17105 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17106 node = UP(pm_find_pattern_node_create(parser, &nodes));
17108 if (nodes.
size == 2) {
17109 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17112 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17114 if (leading_rest && trailing_rest) {
17115 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17120 }
else if (leading_rest) {
17123 node = UP(pm_array_pattern_node_rest_create(parser, node));
17135parse_negative_numeric(pm_node_t *node) {
17136 switch (PM_NODE_TYPE(node)) {
17137 case PM_INTEGER_NODE: {
17138 pm_integer_node_t *cast = (pm_integer_node_t *) node;
17143 case PM_FLOAT_NODE: {
17144 pm_float_node_t *cast = (pm_float_node_t *) node;
17149 case PM_RATIONAL_NODE: {
17150 pm_rational_node_t *cast = (pm_rational_node_t *) node;
17155 case PM_IMAGINARY_NODE:
17157 parse_negative_numeric(((pm_imaginary_node_t *) node)->numeric);
17160 assert(
false &&
"unreachable");
17173 case PM_ERR_HASH_KEY: {
17177 case PM_ERR_HASH_VALUE:
17178 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17182 case PM_ERR_UNARY_RECEIVER: {
17187 case PM_ERR_UNARY_DISALLOWED:
17188 case PM_ERR_EXPECT_ARGUMENT: {
17193 pm_parser_err_previous(parser, diag_id);
17202parse_retry(
pm_parser_t *parser,
const pm_node_t *node) {
17203#define CONTEXT_NONE 0
17204#define CONTEXT_THROUGH_ENSURE 1
17205#define CONTEXT_THROUGH_ELSE 2
17208 int context = CONTEXT_NONE;
17210 while (context_node != NULL) {
17211 switch (context_node->
context) {
17232 if (context == CONTEXT_NONE) {
17233 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17234 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17235 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17236 }
else if (context == CONTEXT_THROUGH_ELSE) {
17237 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17249 context = CONTEXT_THROUGH_ELSE;
17260 context = CONTEXT_THROUGH_ENSURE;
17264 assert(
false &&
"unreachable");
17295 context_node = context_node->
prev;
17299#undef CONTEXT_ENSURE
17307parse_yield(
pm_parser_t *parser,
const pm_node_t *node) {
17310 while (context_node != NULL) {
17311 switch (context_node->
context) {
17336 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17340 assert(
false &&
"unreachable");
17382 context_node = context_node->
prev;
17414parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17418 if (callback_data->
shared) {
17424 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
17431parse_regular_expression_errors(
pm_parser_t *parser, pm_regular_expression_node_t *node) {
17437 .shared = unescaped->type == PM_STRING_SHARED
17440 pm_regexp_parse(parser, pm_string_source(unescaped), pm_string_length(unescaped), PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED), NULL, NULL, parse_regular_expression_error, &error_data);
17446static inline pm_node_t *
17447parse_expression_prefix(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth) {
17449 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17450 parser_lex(parser);
17452 pm_array_node_t *array = pm_array_node_create(parser, &parser->
previous);
17453 pm_accepts_block_stack_push(parser,
true);
17454 bool parsed_bare_hash =
false;
17456 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
17457 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
17461 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17467 if (accept1(parser, PM_TOKEN_COMMA)) {
17470 if (accepted_newline) {
17471 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
17487 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
17489 pm_node_t *element;
17491 if (accept1(parser, PM_TOKEN_USTAR)) {
17493 pm_node_t *expression = NULL;
17495 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
17496 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
17498 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
17501 element = UP(pm_splat_node_create(parser, &
operator, expression));
17502 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
17503 if (parsed_bare_hash) {
17504 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
17507 element = UP(pm_keyword_hash_node_create(parser));
17510 if (!match8(parser, PM_TOKEN_EOF, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_EOF, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_KEYWORD_DO, PM_TOKEN_PARENTHESIS_RIGHT)) {
17511 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17514 pm_static_literals_free(&hash_keys);
17515 parsed_bare_hash =
true;
17517 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
17519 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17520 if (parsed_bare_hash) {
17521 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
17524 pm_keyword_hash_node_t *hash = pm_keyword_hash_node_create(parser);
17526 pm_hash_key_static_literals_add(parser, &hash_keys, element);
17529 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
17532 operator = not_provided(parser);
17535 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
17536 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, &
operator, value));
17537 pm_keyword_hash_node_elements_append(hash, assoc);
17539 element = UP(hash);
17540 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17541 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17544 pm_static_literals_free(&hash_keys);
17545 parsed_bare_hash =
true;
17549 pm_array_node_elements_append(array, element);
17550 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
17553 accept1(parser, PM_TOKEN_NEWLINE);
17555 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17561 pm_array_node_close_set(array, &parser->
previous);
17562 pm_accepts_block_stack_pop(parser);
17566 case PM_TOKEN_PARENTHESIS_LEFT:
17567 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17569 pm_node_flags_t flags = 0;
17571 pm_node_list_t current_block_exits = { 0 };
17572 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17574 parser_lex(parser);
17576 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17577 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17578 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17585 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
17586 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17588 pop_block_exits(parser, previous_block_exits);
17589 pm_node_list_free(¤t_block_exits);
17591 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags));
17596 pm_accepts_block_stack_push(parser,
true);
17598 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17599 context_pop(parser);
17604 bool terminator_found =
false;
17606 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17607 terminator_found =
true;
17608 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17609 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
17610 terminator_found =
true;
17613 if (terminator_found) {
17615 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17616 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17617 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17626 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17627 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
17628 lex_state_set(parser, PM_LEX_STATE_ENDARG);
17631 parser_lex(parser);
17632 pm_accepts_block_stack_pop(parser);
17634 pop_block_exits(parser, previous_block_exits);
17635 pm_node_list_free(¤t_block_exits);
17637 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17641 pm_multi_target_node_t *multi_target;
17643 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
17644 multi_target = (pm_multi_target_node_t *) statement;
17646 multi_target = pm_multi_target_node_create(parser);
17647 pm_multi_target_node_targets_append(parser, multi_target, statement);
17650 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17659 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
17660 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17661 accept1(parser, PM_TOKEN_NEWLINE);
17663 result = UP(multi_target);
17672 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
17675 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17676 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
17680 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17689 pm_statements_node_t *statements = pm_statements_node_create(parser);
17690 pm_statements_node_body_append(parser, statements, statement,
true);
17692 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17699 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17701 pm_statements_node_t *statements = pm_statements_node_create(parser);
17702 pm_statements_node_body_append(parser, statements, statement,
true);
17706 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
17712 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17713 pm_statements_node_body_append(parser, statements, node,
true);
17720 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
17726 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
17730 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17731 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17732 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
17733 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17735 }
else if (!match1(parser, PM_TOKEN_EOF)) {
17742 context_pop(parser);
17743 pm_accepts_block_stack_pop(parser);
17744 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17753 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17754 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
17755 pm_multi_target_node_targets_append(parser, multi_target, statement);
17757 statement = UP(multi_target);
17761 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
17763 pm_token_t operator = { .type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
17764 pm_node_t *value = UP(pm_missing_node_create(parser, offset, offset));
17766 statement = UP(pm_multi_write_node_create(parser, (pm_multi_target_node_t *) statement, &
operator, value));
17769 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
17773 pop_block_exits(parser, previous_block_exits);
17774 pm_node_list_free(¤t_block_exits);
17776 pm_void_statements_check(parser, statements,
true);
17777 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17779 case PM_TOKEN_BRACE_LEFT: {
17790 pm_accepts_block_stack_push(parser,
true);
17791 parser_lex(parser);
17794 pm_hash_node_t *node = pm_hash_node_create(parser, &opening);
17796 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
17797 if (current_hash_keys != NULL) {
17798 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
17801 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
17802 pm_static_literals_free(&hash_keys);
17805 accept1(parser, PM_TOKEN_NEWLINE);
17808 pm_accepts_block_stack_pop(parser);
17809 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
17810 pm_hash_node_closing_loc_set(node, &parser->
previous);
17814 case PM_TOKEN_CHARACTER_LITERAL: {
17816 pm_node_t *node = UP(pm_string_node_create_current_string(
17819 .type = PM_TOKEN_STRING_BEGIN,
17824 .type = PM_TOKEN_STRING_CONTENT,
17831 pm_node_flag_set(node, parse_unescaped_encoding(parser));
17835 parser_lex(parser);
17839 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17840 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
17845 case PM_TOKEN_CLASS_VARIABLE: {
17846 parser_lex(parser);
17847 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
17849 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17850 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17855 case PM_TOKEN_CONSTANT: {
17856 parser_lex(parser);
17862 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
17863 (accepts_command_call && (token_begins_expression_p(parser->
current.
type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17864 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17865 match1(parser, PM_TOKEN_BRACE_LEFT)
17868 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17869 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
17872 pm_node_t *node = UP(pm_constant_read_node_create(parser, &parser->
previous));
17874 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17877 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17882 case PM_TOKEN_UCOLON_COLON: {
17883 parser_lex(parser);
17886 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17887 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous));
17889 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17890 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17895 case PM_TOKEN_UDOT_DOT:
17896 case PM_TOKEN_UDOT_DOT_DOT: {
17898 parser_lex(parser);
17900 pm_node_t *right = parse_expression(parser, pm_binding_powers[
operator.
type].left,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
17906 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17907 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
17910 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17912 case PM_TOKEN_FLOAT:
17913 parser_lex(parser);
17914 return UP(pm_float_node_create(parser, &parser->
previous));
17915 case PM_TOKEN_FLOAT_IMAGINARY:
17916 parser_lex(parser);
17917 return UP(pm_float_node_imaginary_create(parser, &parser->
previous));
17918 case PM_TOKEN_FLOAT_RATIONAL:
17919 parser_lex(parser);
17920 return UP(pm_float_node_rational_create(parser, &parser->
previous));
17921 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
17922 parser_lex(parser);
17923 return UP(pm_float_node_rational_imaginary_create(parser, &parser->
previous));
17924 case PM_TOKEN_NUMBERED_REFERENCE: {
17925 parser_lex(parser);
17926 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
17928 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17929 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17934 case PM_TOKEN_GLOBAL_VARIABLE: {
17935 parser_lex(parser);
17936 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
17938 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17939 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17944 case PM_TOKEN_BACK_REFERENCE: {
17945 parser_lex(parser);
17946 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
17948 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17949 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17954 case PM_TOKEN_IDENTIFIER:
17955 case PM_TOKEN_METHOD_NAME: {
17956 parser_lex(parser);
17958 pm_node_t *node = parse_variable_call(parser);
17960 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17965 pm_call_node_t *call = (pm_call_node_t *) node;
17968 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
17971 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
17978 const uint8_t *end = pm_arguments_end(&arguments);
17989 (accepts_command_call && (token_begins_expression_p(parser->
current.
type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17990 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17991 match1(parser, PM_TOKEN_BRACE_LEFT)
17994 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17995 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
17997 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
18001 pm_node_unreference(parser, node);
18007 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
18009 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
18010 pm_node_unreference(parser, node);
18012 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
18013 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
18017 pm_node_destroy(parser, node);
18022 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
18023 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18028 case PM_TOKEN_HEREDOC_START: {
18031 assert(parser->lex_modes.
current->mode == PM_LEX_HEREDOC);
18034 size_t common_whitespace = (size_t) -1;
18035 parser->lex_modes.
current->as.heredoc.common_whitespace = &common_whitespace;
18037 parser_lex(parser);
18043 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18049 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18050 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY));
18056 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18064 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18069 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18070 pm_string_node_t *cast = (pm_string_node_t *) part;
18072 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18076 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18077 assert(
sizeof(pm_string_node_t) ==
sizeof(pm_x_string_node_t));
18078 cast->
base.
type = PM_X_STRING_NODE;
18081 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18082 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18091 pm_node_list_t parts = { 0 };
18092 pm_node_list_append(&parts, part);
18094 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18095 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18096 pm_node_list_append(&parts, part);
18102 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18103 pm_interpolated_x_string_node_t *cast = pm_interpolated_xstring_node_create(parser, &opening, &opening);
18104 cast->
parts = parts;
18107 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18112 pm_interpolated_string_node_t *cast = pm_interpolated_string_node_create(parser, &opening, &parts, &opening);
18113 pm_node_list_free(&parts);
18116 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18124 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18125 pm_node_list_t *nodes;
18126 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18127 nodes = &((pm_interpolated_x_string_node_t *) node)->parts;
18129 nodes = &((pm_interpolated_string_node_t *) node)->parts;
18132 parse_heredoc_dedent(parser, nodes, common_whitespace);
18136 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18137 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18142 case PM_TOKEN_INSTANCE_VARIABLE: {
18143 parser_lex(parser);
18144 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
18146 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18147 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18152 case PM_TOKEN_INTEGER: {
18154 parser_lex(parser);
18155 return UP(pm_integer_node_create(parser, base, &parser->
previous));
18157 case PM_TOKEN_INTEGER_IMAGINARY: {
18159 parser_lex(parser);
18160 return UP(pm_integer_node_imaginary_create(parser, base, &parser->
previous));
18162 case PM_TOKEN_INTEGER_RATIONAL: {
18164 parser_lex(parser);
18165 return UP(pm_integer_node_rational_create(parser, base, &parser->
previous));
18167 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18169 parser_lex(parser);
18170 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous));
18172 case PM_TOKEN_KEYWORD___ENCODING__:
18173 parser_lex(parser);
18174 return UP(pm_source_encoding_node_create(parser, &parser->
previous));
18175 case PM_TOKEN_KEYWORD___FILE__:
18176 parser_lex(parser);
18177 return UP(pm_source_file_node_create(parser, &parser->
previous));
18178 case PM_TOKEN_KEYWORD___LINE__:
18179 parser_lex(parser);
18180 return UP(pm_source_line_node_create(parser, &parser->
previous));
18181 case PM_TOKEN_KEYWORD_ALIAS: {
18182 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18183 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18186 parser_lex(parser);
18189 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18190 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18192 switch (PM_NODE_TYPE(new_name)) {
18193 case PM_BACK_REFERENCE_READ_NODE:
18194 case PM_NUMBERED_REFERENCE_READ_NODE:
18195 case PM_GLOBAL_VARIABLE_READ_NODE: {
18196 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)) {
18197 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18198 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18201 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18204 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
18206 case PM_SYMBOL_NODE:
18207 case PM_INTERPOLATED_SYMBOL_NODE: {
18208 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18209 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18214 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
18217 case PM_TOKEN_KEYWORD_CASE: {
18218 size_t opening_newline_index = token_newline_index(parser);
18219 parser_lex(parser);
18222 pm_node_t *predicate = NULL;
18224 pm_node_list_t current_block_exits = { 0 };
18225 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18227 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18228 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18230 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18232 }
else if (!token_begins_expression_p(parser->
current.
type)) {
18235 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18236 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18239 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18240 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18241 parser_lex(parser);
18243 pop_block_exits(parser, previous_block_exits);
18244 pm_node_list_free(¤t_block_exits);
18246 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18247 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous));
18252 pm_token_t end_keyword = not_provided(parser);
18255 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18256 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18262 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18263 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18264 parser_lex(parser);
18267 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18270 if (accept1(parser, PM_TOKEN_USTAR)) {
18272 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18274 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18275 pm_when_node_conditions_append(when_node, UP(splat_node));
18277 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18279 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18280 pm_when_node_conditions_append(when_node, condition);
18284 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18288 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18289 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18290 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18291 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18294 pm_when_clause_static_literals_add(parser, &literals, condition);
18296 }
while (accept1(parser, PM_TOKEN_COMMA));
18298 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18299 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18300 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18303 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18304 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18307 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18308 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_CASE_WHEN, (uint16_t) (depth + 1));
18309 if (statements != NULL) {
18310 pm_when_node_statements_set(when_node, statements);
18314 pm_case_node_condition_append(case_node, UP(when_node));
18320 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18323 pm_static_literals_free(&literals);
18324 node = UP(case_node);
18326 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18330 if (predicate == NULL) {
18331 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18337 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18338 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18343 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18345 parser_lex(parser);
18350 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));
18353 pm_constant_id_list_free(&captures);
18358 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18360 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18361 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18362 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18364 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18365 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18372 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18373 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18376 then_keyword = not_provided(parser);
18379 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18385 pm_statements_node_t *statements;
18386 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18394 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword));
18395 pm_case_match_node_condition_append(case_node, condition);
18401 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18404 node = UP(case_node);
18407 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18408 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18410 pm_else_node_t *else_node;
18412 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18413 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18415 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18418 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18419 pm_case_node_else_clause_set((pm_case_node_t *) node, else_node);
18421 pm_case_match_node_else_clause_set((pm_case_match_node_t *) node, else_node);
18425 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18426 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18428 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18429 pm_case_node_end_keyword_loc_set((pm_case_node_t *) node, &parser->
previous);
18431 pm_case_match_node_end_keyword_loc_set((pm_case_match_node_t *) node, &parser->
previous);
18434 pop_block_exits(parser, previous_block_exits);
18435 pm_node_list_free(¤t_block_exits);
18439 case PM_TOKEN_KEYWORD_BEGIN: {
18440 size_t opening_newline_index = token_newline_index(parser);
18441 parser_lex(parser);
18444 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18446 pm_node_list_t current_block_exits = { 0 };
18447 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18448 pm_statements_node_t *begin_statements = NULL;
18450 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18451 pm_accepts_block_stack_push(parser,
true);
18452 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18453 pm_accepts_block_stack_pop(parser);
18454 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18457 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18458 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18459 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
18462 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
18464 pop_block_exits(parser, previous_block_exits);
18465 pm_node_list_free(¤t_block_exits);
18467 return UP(begin_node);
18469 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
18470 pm_node_list_t current_block_exits = { 0 };
18471 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18473 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18474 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18477 parser_lex(parser);
18480 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
18482 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_PREEXE, (uint16_t) (depth + 1));
18484 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
18487 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
18490 flush_block_exits(parser, previous_block_exits);
18491 pm_node_list_free(¤t_block_exits);
18493 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
18495 case PM_TOKEN_KEYWORD_BREAK:
18496 case PM_TOKEN_KEYWORD_NEXT:
18497 case PM_TOKEN_KEYWORD_RETURN: {
18498 parser_lex(parser);
18504 token_begins_expression_p(parser->
current.
type) ||
18505 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
18507 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.
type].left;
18509 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
18511 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
18514 if (!accepts_command_call && arguments.
arguments != NULL) {
18520 switch (keyword.
type) {
18521 case PM_TOKEN_KEYWORD_BREAK: {
18522 pm_node_t *node = UP(pm_break_node_create(parser, &keyword, arguments.
arguments));
18526 case PM_TOKEN_KEYWORD_NEXT: {
18527 pm_node_t *node = UP(pm_next_node_create(parser, &keyword, arguments.
arguments));
18531 case PM_TOKEN_KEYWORD_RETURN: {
18532 pm_node_t *node = UP(pm_return_node_create(parser, &keyword, arguments.
arguments));
18533 parse_return(parser, node);
18537 assert(
false &&
"unreachable");
18541 case PM_TOKEN_KEYWORD_SUPER: {
18542 parser_lex(parser);
18546 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18551 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
18553 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
18556 return UP(pm_super_node_create(parser, &keyword, &arguments));
18558 case PM_TOKEN_KEYWORD_YIELD: {
18559 parser_lex(parser);
18563 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
18569 if (arguments.
block != NULL) {
18570 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
18571 pm_node_unreference(parser, arguments.
block);
18572 pm_node_destroy(parser, arguments.
block);
18573 arguments.
block = NULL;
18581 case PM_TOKEN_KEYWORD_CLASS: {
18582 size_t opening_newline_index = token_newline_index(parser);
18583 parser_lex(parser);
18586 pm_do_loop_stack_push(parser,
false);
18588 pm_node_list_t current_block_exits = { 0 };
18589 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18591 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18593 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_LESS_LESS, (uint16_t) (depth + 1));
18595 pm_parser_scope_push(parser,
true);
18596 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18600 pm_node_t *statements = NULL;
18601 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18602 pm_accepts_block_stack_push(parser,
true);
18603 statements = UP(parse_statements(parser,
PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18604 pm_accepts_block_stack_pop(parser);
18607 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18608 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18609 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)));
18611 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18614 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18619 pm_parser_scope_pop(parser);
18620 pm_do_loop_stack_pop(parser);
18622 flush_block_exits(parser, previous_block_exits);
18623 pm_node_list_free(¤t_block_exits);
18625 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous));
18628 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
18630 if (name.
type != PM_TOKEN_CONSTANT) {
18631 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18635 pm_node_t *superclass;
18637 if (match1(parser, PM_TOKEN_LESS)) {
18638 inheritance_operator = parser->
current;
18639 lex_state_set(parser, PM_LEX_STATE_BEG);
18642 parser_lex(parser);
18644 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
18646 inheritance_operator = not_provided(parser);
18650 pm_parser_scope_push(parser,
true);
18652 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
18653 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18655 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18657 pm_node_t *statements = NULL;
18659 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18660 pm_accepts_block_stack_push(parser,
true);
18661 statements = UP(parse_statements(parser,
PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18662 pm_accepts_block_stack_pop(parser);
18665 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18666 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18667 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)));
18669 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18672 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18674 if (context_def_p(parser)) {
18675 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18681 pm_parser_scope_pop(parser);
18682 pm_do_loop_stack_pop(parser);
18684 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18685 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18688 pop_block_exits(parser, previous_block_exits);
18689 pm_node_list_free(¤t_block_exits);
18691 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous));
18693 case PM_TOKEN_KEYWORD_DEF: {
18694 pm_node_list_t current_block_exits = { 0 };
18695 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18698 size_t opening_newline_index = token_newline_index(parser);
18700 pm_node_t *receiver = NULL;
18708 parser_lex(parser);
18712 bool valid_name =
true;
18715 case PM_CASE_OPERATOR:
18716 pm_parser_scope_push(parser,
true);
18717 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18718 parser_lex(parser);
18722 case PM_TOKEN_IDENTIFIER: {
18723 parser_lex(parser);
18725 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18726 receiver = parse_variable_call(parser);
18728 pm_parser_scope_push(parser,
true);
18729 lex_state_set(parser, PM_LEX_STATE_FNAME);
18730 parser_lex(parser);
18733 name = parse_method_definition_name(parser);
18736 pm_parser_scope_push(parser,
true);
18743 case PM_TOKEN_INSTANCE_VARIABLE:
18744 case PM_TOKEN_CLASS_VARIABLE:
18745 case PM_TOKEN_GLOBAL_VARIABLE:
18746 valid_name =
false;
18748 case PM_TOKEN_CONSTANT:
18749 case PM_TOKEN_KEYWORD_NIL:
18750 case PM_TOKEN_KEYWORD_SELF:
18751 case PM_TOKEN_KEYWORD_TRUE:
18752 case PM_TOKEN_KEYWORD_FALSE:
18753 case PM_TOKEN_KEYWORD___FILE__:
18754 case PM_TOKEN_KEYWORD___LINE__:
18755 case PM_TOKEN_KEYWORD___ENCODING__: {
18756 pm_parser_scope_push(parser,
true);
18757 parser_lex(parser);
18761 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18762 lex_state_set(parser, PM_LEX_STATE_FNAME);
18763 parser_lex(parser);
18766 switch (identifier.
type) {
18767 case PM_TOKEN_CONSTANT:
18768 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18770 case PM_TOKEN_INSTANCE_VARIABLE:
18771 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18773 case PM_TOKEN_CLASS_VARIABLE:
18774 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18776 case PM_TOKEN_GLOBAL_VARIABLE:
18777 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18779 case PM_TOKEN_KEYWORD_NIL:
18780 receiver = UP(pm_nil_node_create(parser, &identifier));
18782 case PM_TOKEN_KEYWORD_SELF:
18783 receiver = UP(pm_self_node_create(parser, &identifier));
18785 case PM_TOKEN_KEYWORD_TRUE:
18786 receiver = UP(pm_true_node_create(parser, &identifier));
18788 case PM_TOKEN_KEYWORD_FALSE:
18789 receiver = UP(pm_false_node_create(parser, &identifier));
18791 case PM_TOKEN_KEYWORD___FILE__:
18792 receiver = UP(pm_source_file_node_create(parser, &identifier));
18794 case PM_TOKEN_KEYWORD___LINE__:
18795 receiver = UP(pm_source_line_node_create(parser, &identifier));
18797 case PM_TOKEN_KEYWORD___ENCODING__:
18798 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18804 name = parse_method_definition_name(parser);
18814 case PM_TOKEN_PARENTHESIS_LEFT: {
18819 context_pop(parser);
18820 parser_lex(parser);
18823 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
18825 accept1(parser, PM_TOKEN_NEWLINE);
18826 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18829 lex_state_set(parser, PM_LEX_STATE_FNAME);
18830 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18833 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18837 pm_parser_scope_push(parser,
true);
18839 name = parse_method_definition_name(parser);
18843 pm_parser_scope_push(parser,
true);
18844 name = parse_method_definition_name(parser);
18850 pm_parameters_node_t *params;
18852 bool accept_endless_def =
true;
18854 case PM_TOKEN_PARENTHESIS_LEFT: {
18855 parser_lex(parser);
18858 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18861 params = parse_parameters(
18863 PM_BINDING_POWER_DEFINED,
18869 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18870 (uint16_t) (depth + 1)
18874 lex_state_set(parser, PM_LEX_STATE_BEG);
18877 context_pop(parser);
18878 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18887 case PM_CASE_PARAMETER: {
18891 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
18894 lparen = not_provided(parser);
18895 rparen = not_provided(parser);
18896 params = parse_parameters(
18898 PM_BINDING_POWER_DEFINED,
18904 PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES,
18905 (uint16_t) (depth + 1)
18910 accept_endless_def =
false;
18912 context_pop(parser);
18916 lparen = not_provided(parser);
18917 rparen = not_provided(parser);
18920 context_pop(parser);
18925 pm_node_t *statements = NULL;
18929 if (accept1(parser, PM_TOKEN_EQUAL)) {
18930 if (token_is_setter_name(&name)) {
18931 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18933 if (!accept_endless_def) {
18934 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18940 PM_PARSER_ERR_FORMAT(parser, def_keyword.
start, parser->
previous.
end, PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE,
"endless method definition");
18945 pm_do_loop_stack_push(parser,
false);
18946 statements = UP(pm_statements_node_create(parser));
18948 bool allow_command_call;
18950 allow_command_call = accepts_command_call;
18953 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
18956 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
18958 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18962 pm_node_t *value = parse_expression(parser, PM_BINDING_POWER_MATCH + 1,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
18963 context_pop(parser);
18965 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18968 pm_statements_node_body_append(parser, (pm_statements_node_t *) statements, statement,
false);
18969 pm_do_loop_stack_pop(parser);
18970 context_pop(parser);
18971 end_keyword = not_provided(parser);
18973 equal = not_provided(parser);
18975 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
18976 lex_state_set(parser, PM_LEX_STATE_BEG);
18978 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18980 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18983 pm_accepts_block_stack_push(parser,
true);
18984 pm_do_loop_stack_push(parser,
false);
18986 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18987 pm_accepts_block_stack_push(parser,
true);
18988 statements = UP(parse_statements(parser,
PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18989 pm_accepts_block_stack_pop(parser);
18992 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18993 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18994 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)));
18996 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18999 pm_accepts_block_stack_pop(parser);
19000 pm_do_loop_stack_pop(parser);
19002 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
19008 pm_parser_scope_pop(parser);
19015 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
19017 flush_block_exits(parser, previous_block_exits);
19018 pm_node_list_free(¤t_block_exits);
19020 return UP(pm_def_node_create(
19036 case PM_TOKEN_KEYWORD_DEFINED: {
19037 parser_lex(parser);
19042 pm_node_t *expression;
19045 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19047 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19050 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19051 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19052 lparen = not_provided(parser);
19053 rparen = not_provided(parser);
19055 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19058 rparen = not_provided(parser);
19060 accept1(parser, PM_TOKEN_NEWLINE);
19061 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19066 lparen = not_provided(parser);
19067 rparen = not_provided(parser);
19068 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19071 context_pop(parser);
19072 return UP(pm_defined_node_create(
19080 case PM_TOKEN_KEYWORD_END_UPCASE: {
19081 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19082 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19085 parser_lex(parser);
19088 if (context_def_p(parser)) {
19089 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19092 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19094 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_POSTEXE, (uint16_t) (depth + 1));
19096 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
19097 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
19099 case PM_TOKEN_KEYWORD_FALSE:
19100 parser_lex(parser);
19101 return UP(pm_false_node_create(parser, &parser->
previous));
19102 case PM_TOKEN_KEYWORD_FOR: {
19103 size_t opening_newline_index = token_newline_index(parser);
19104 parser_lex(parser);
19112 if (accept1(parser, PM_TOKEN_USTAR)) {
19114 pm_node_t *name = NULL;
19116 if (token_begins_expression_p(parser->
current.
type)) {
19117 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19120 index = UP(pm_splat_node_create(parser, &star_operator, name));
19121 }
else if (token_begins_expression_p(parser->
current.
type)) {
19122 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19124 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19125 index = UP(pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end));
19129 if (match1(parser, PM_TOKEN_COMMA)) {
19130 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19132 index = parse_target(parser, index,
false,
false);
19135 context_pop(parser);
19136 pm_do_loop_stack_push(parser,
true);
19138 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19141 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19142 pm_do_loop_stack_pop(parser);
19145 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19148 do_keyword = not_provided(parser);
19149 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19154 pm_statements_node_t *statements = NULL;
19155 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19156 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19159 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19160 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19162 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous));
19164 case PM_TOKEN_KEYWORD_IF:
19165 if (parser_end_of_line_p(parser)) {
19166 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19169 size_t opening_newline_index = token_newline_index(parser);
19170 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19171 parser_lex(parser);
19173 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19174 case PM_TOKEN_KEYWORD_UNDEF: {
19175 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19176 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19179 parser_lex(parser);
19180 pm_undef_node_t *undef = pm_undef_node_create(parser, &parser->
previous);
19181 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19183 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19184 pm_node_destroy(parser, name);
19186 pm_undef_node_append(undef, name);
19188 while (match1(parser, PM_TOKEN_COMMA)) {
19189 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19190 parser_lex(parser);
19191 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19193 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19194 pm_node_destroy(parser, name);
19198 pm_undef_node_append(undef, name);
19204 case PM_TOKEN_KEYWORD_NOT: {
19205 parser_lex(parser);
19209 pm_node_t *receiver = NULL;
19214 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19215 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19216 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19218 accept1(parser, PM_TOKEN_NEWLINE);
19219 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19225 accept1(parser, PM_TOKEN_NEWLINE);
19227 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19230 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19231 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19233 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19234 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19237 accept1(parser, PM_TOKEN_NEWLINE);
19238 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19243 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19246 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19248 case PM_TOKEN_KEYWORD_UNLESS: {
19249 size_t opening_newline_index = token_newline_index(parser);
19250 parser_lex(parser);
19252 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19254 case PM_TOKEN_KEYWORD_MODULE: {
19255 pm_node_list_t current_block_exits = { 0 };
19256 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19258 size_t opening_newline_index = token_newline_index(parser);
19259 parser_lex(parser);
19262 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19267 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19268 pop_block_exits(parser, previous_block_exits);
19269 pm_node_list_free(¤t_block_exits);
19272 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19275 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19278 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19279 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous));
19286 if (name.
type != PM_TOKEN_CONSTANT) {
19287 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19290 pm_parser_scope_push(parser,
true);
19291 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19292 pm_node_t *statements = NULL;
19294 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19295 pm_accepts_block_stack_push(parser,
true);
19296 statements = UP(parse_statements(parser,
PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19297 pm_accepts_block_stack_pop(parser);
19300 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19301 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19302 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)));
19304 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19310 pm_parser_scope_pop(parser);
19311 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
19313 if (context_def_p(parser)) {
19314 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19317 pop_block_exits(parser, previous_block_exits);
19318 pm_node_list_free(¤t_block_exits);
19320 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous));
19322 case PM_TOKEN_KEYWORD_NIL:
19323 parser_lex(parser);
19324 return UP(pm_nil_node_create(parser, &parser->
previous));
19325 case PM_TOKEN_KEYWORD_REDO: {
19326 parser_lex(parser);
19328 pm_node_t *node = UP(pm_redo_node_create(parser, &parser->
previous));
19333 case PM_TOKEN_KEYWORD_RETRY: {
19334 parser_lex(parser);
19336 pm_node_t *node = UP(pm_retry_node_create(parser, &parser->
previous));
19337 parse_retry(parser, node);
19341 case PM_TOKEN_KEYWORD_SELF:
19342 parser_lex(parser);
19343 return UP(pm_self_node_create(parser, &parser->
previous));
19344 case PM_TOKEN_KEYWORD_TRUE:
19345 parser_lex(parser);
19346 return UP(pm_true_node_create(parser, &parser->
previous));
19347 case PM_TOKEN_KEYWORD_UNTIL: {
19348 size_t opening_newline_index = token_newline_index(parser);
19351 pm_do_loop_stack_push(parser,
true);
19353 parser_lex(parser);
19355 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19357 pm_do_loop_stack_pop(parser);
19358 context_pop(parser);
19361 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19364 do_keyword = not_provided(parser);
19365 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19368 pm_statements_node_t *statements = NULL;
19369 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19370 pm_accepts_block_stack_push(parser,
true);
19371 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19372 pm_accepts_block_stack_pop(parser);
19373 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19376 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19377 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
19379 return UP(pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19381 case PM_TOKEN_KEYWORD_WHILE: {
19382 size_t opening_newline_index = token_newline_index(parser);
19385 pm_do_loop_stack_push(parser,
true);
19387 parser_lex(parser);
19389 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19391 pm_do_loop_stack_pop(parser);
19392 context_pop(parser);
19395 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19398 do_keyword = not_provided(parser);
19399 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19402 pm_statements_node_t *statements = NULL;
19403 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19404 pm_accepts_block_stack_push(parser,
true);
19405 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19406 pm_accepts_block_stack_pop(parser);
19407 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19410 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19411 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
19413 return UP(pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19415 case PM_TOKEN_PERCENT_LOWER_I: {
19416 parser_lex(parser);
19418 pm_array_node_t *array = pm_array_node_create(parser, &opening);
19419 pm_node_t *current = NULL;
19421 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19422 accept1(parser, PM_TOKEN_WORDS_SEP);
19423 if (match1(parser, PM_TOKEN_STRING_END))
break;
19427 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19432 if (current == NULL) {
19433 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19434 parser_lex(parser);
19435 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19436 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19437 parser_lex(parser);
19438 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current,
string);
19439 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19440 pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
19444 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19445 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19446 parser_lex(parser);
19448 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19449 pm_interpolated_symbol_node_append(interpolated, first_string);
19450 pm_interpolated_symbol_node_append(interpolated, second_string);
19453 current = UP(interpolated);
19455 assert(
false &&
"unreachable");
19460 pm_array_node_elements_append(array, current);
19463 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
19468 if (match1(parser, PM_TOKEN_EOF)) {
19469 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19472 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
19474 pm_array_node_close_set(array, &closing);
19478 case PM_TOKEN_PERCENT_UPPER_I: {
19479 parser_lex(parser);
19481 pm_array_node_t *array = pm_array_node_create(parser, &opening);
19485 pm_node_t *current = NULL;
19487 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19489 case PM_TOKEN_WORDS_SEP: {
19490 if (current == NULL) {
19496 pm_array_node_elements_append(array, current);
19500 parser_lex(parser);
19503 case PM_TOKEN_STRING_CONTENT: {
19507 if (current == NULL) {
19511 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19512 parser_lex(parser);
19513 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19517 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19518 parser_lex(parser);
19520 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current,
string);
19521 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19525 pm_symbol_node_t *cast = (pm_symbol_node_t *) current;
19529 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19530 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19531 parser_lex(parser);
19533 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19534 pm_interpolated_symbol_node_append(interpolated, first_string);
19535 pm_interpolated_symbol_node_append(interpolated, second_string);
19538 current = UP(interpolated);
19540 assert(
false &&
"unreachable");
19545 case PM_TOKEN_EMBVAR: {
19546 bool start_location_set =
false;
19547 if (current == NULL) {
19553 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19554 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19560 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19562 current = UP(pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current));
19563 pm_interpolated_symbol_node_append(interpolated, current);
19565 start_location_set =
true;
19566 current = UP(interpolated);
19572 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19573 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
19574 if (!start_location_set) {
19579 case PM_TOKEN_EMBEXPR_BEGIN: {
19580 bool start_location_set =
false;
19581 if (current == NULL) {
19587 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19588 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19595 pm_interpolated_symbol_node_t *interpolated = pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing);
19597 current = UP(pm_symbol_node_to_string_node(parser, (pm_symbol_node_t *) current));
19598 pm_interpolated_symbol_node_append(interpolated, current);
19600 start_location_set =
true;
19601 current = UP(interpolated);
19602 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19606 assert(
false &&
"unreachable");
19609 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19610 pm_interpolated_symbol_node_append((pm_interpolated_symbol_node_t *) current, part);
19611 if (!start_location_set) {
19617 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19618 parser_lex(parser);
19625 pm_array_node_elements_append(array, current);
19629 if (match1(parser, PM_TOKEN_EOF)) {
19630 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19633 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19635 pm_array_node_close_set(array, &closing);
19639 case PM_TOKEN_PERCENT_LOWER_W: {
19640 parser_lex(parser);
19642 pm_array_node_t *array = pm_array_node_create(parser, &opening);
19643 pm_node_t *current = NULL;
19645 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19646 accept1(parser, PM_TOKEN_WORDS_SEP);
19647 if (match1(parser, PM_TOKEN_STRING_END))
break;
19651 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19655 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19658 if (current == NULL) {
19660 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19661 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current,
string);
19662 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19663 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
19664 pm_interpolated_string_node_append(interpolated, current);
19665 pm_interpolated_string_node_append(interpolated,
string);
19666 current = UP(interpolated);
19668 assert(
false &&
"unreachable");
19670 parser_lex(parser);
19674 pm_array_node_elements_append(array, current);
19677 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
19682 if (match1(parser, PM_TOKEN_EOF)) {
19683 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
19686 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
19689 pm_array_node_close_set(array, &closing);
19692 case PM_TOKEN_PERCENT_UPPER_W: {
19693 parser_lex(parser);
19695 pm_array_node_t *array = pm_array_node_create(parser, &opening);
19699 pm_node_t *current = NULL;
19701 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19703 case PM_TOKEN_WORDS_SEP: {
19708 if (current == NULL) {
19715 pm_array_node_elements_append(array, current);
19719 parser_lex(parser);
19722 case PM_TOKEN_STRING_CONTENT: {
19726 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19727 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
19728 parser_lex(parser);
19730 if (current == NULL) {
19736 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19740 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current,
string);
19741 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19746 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
19747 pm_interpolated_string_node_append(interpolated, current);
19748 pm_interpolated_string_node_append(interpolated,
string);
19749 current = UP(interpolated);
19751 assert(
false &&
"unreachable");
19756 case PM_TOKEN_EMBVAR: {
19757 if (current == NULL) {
19764 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19765 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19772 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
19773 pm_interpolated_string_node_append(interpolated, current);
19774 current = UP(interpolated);
19781 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19782 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
19785 case PM_TOKEN_EMBEXPR_BEGIN: {
19786 if (current == NULL) {
19793 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19794 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19801 pm_interpolated_string_node_t *interpolated = pm_interpolated_string_node_create(parser, &opening, NULL, &closing);
19802 pm_interpolated_string_node_append(interpolated, current);
19803 current = UP(interpolated);
19804 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19809 assert(
false &&
"unreachable");
19812 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19813 pm_interpolated_string_node_append((pm_interpolated_string_node_t *) current, part);
19817 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19818 parser_lex(parser);
19825 pm_array_node_elements_append(array, current);
19829 if (match1(parser, PM_TOKEN_EOF)) {
19830 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19833 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19836 pm_array_node_close_set(array, &closing);
19839 case PM_TOKEN_REGEXP_BEGIN: {
19841 parser_lex(parser);
19843 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19848 .type = PM_TOKEN_STRING_CONTENT,
19853 parser_lex(parser);
19855 pm_node_t *node = UP(pm_regular_expression_node_create(parser, &opening, &content, &parser->
previous));
19856 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
19861 pm_interpolated_regular_expression_node_t *interpolated;
19863 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19871 parser_lex(parser);
19876 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19877 pm_regular_expression_node_t *node = (pm_regular_expression_node_t *) pm_regular_expression_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped);
19883 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19884 parse_regular_expression_errors(parser, node);
19887 pm_node_flag_set(UP(node), parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, FL(node)));
19893 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19897 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19903 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19906 pm_interpolated_regular_expression_node_append(interpolated, part);
19911 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19917 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19918 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19919 pm_interpolated_regular_expression_node_append(interpolated, part);
19924 if (match1(parser, PM_TOKEN_EOF)) {
19925 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19928 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19931 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19932 return UP(interpolated);
19934 case PM_TOKEN_BACKTICK:
19935 case PM_TOKEN_PERCENT_LOWER_X: {
19936 parser_lex(parser);
19943 if (match1(parser, PM_TOKEN_STRING_END)) {
19948 .type = PM_TOKEN_STRING_CONTENT,
19953 parser_lex(parser);
19954 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->
previous));
19957 pm_interpolated_x_string_node_t *node;
19959 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19966 parser_lex(parser);
19968 if (match1(parser, PM_TOKEN_STRING_END)) {
19969 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
19970 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19971 parser_lex(parser);
19977 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19982 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19983 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19985 pm_interpolated_xstring_node_append(node, part);
19990 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19994 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19995 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19996 pm_interpolated_xstring_node_append(node, part);
20001 if (match1(parser, PM_TOKEN_EOF)) {
20002 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
20005 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
20007 pm_interpolated_xstring_node_closing_set(node, &closing);
20011 case PM_TOKEN_USTAR: {
20012 parser_lex(parser);
20017 if (binding_power != PM_BINDING_POWER_STATEMENT) {
20018 pm_parser_err_prefix(parser, diag_id);
20023 pm_node_t *name = NULL;
20025 if (token_begins_expression_p(parser->
current.
type)) {
20026 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
20029 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
20031 if (match1(parser, PM_TOKEN_COMMA)) {
20032 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
20034 return parse_target_validate(parser, splat,
true);
20037 case PM_TOKEN_BANG: {
20038 if (binding_power > PM_BINDING_POWER_UNARY) {
20039 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20042 parser_lex(parser);
20045 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right, binding_power < PM_BINDING_POWER_MATCH,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20046 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20048 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20051 case PM_TOKEN_TILDE: {
20052 if (binding_power > PM_BINDING_POWER_UNARY) {
20053 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20055 parser_lex(parser);
20058 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20059 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20063 case PM_TOKEN_UMINUS: {
20064 if (binding_power > PM_BINDING_POWER_UNARY) {
20065 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20067 parser_lex(parser);
20070 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20071 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20075 case PM_TOKEN_UMINUS_NUM: {
20076 parser_lex(parser);
20079 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20081 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20083 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20084 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20085 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20087 switch (PM_NODE_TYPE(node)) {
20088 case PM_INTEGER_NODE:
20089 case PM_FLOAT_NODE:
20090 case PM_RATIONAL_NODE:
20091 case PM_IMAGINARY_NODE:
20092 parse_negative_numeric(node);
20095 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20102 case PM_TOKEN_MINUS_GREATER: {
20106 size_t opening_newline_index = token_newline_index(parser);
20107 pm_accepts_block_stack_push(parser,
true);
20108 parser_lex(parser);
20111 pm_parser_scope_push(parser,
false);
20113 pm_block_parameters_node_t *block_parameters;
20116 case PM_TOKEN_PARENTHESIS_LEFT: {
20118 parser_lex(parser);
20120 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20121 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20123 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20126 accept1(parser, PM_TOKEN_NEWLINE);
20127 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20129 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20132 case PM_CASE_PARAMETER: {
20133 pm_accepts_block_stack_push(parser,
false);
20135 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20136 pm_accepts_block_stack_pop(parser);
20140 block_parameters = NULL;
20146 pm_node_t *body = NULL;
20149 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20152 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20156 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20157 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20159 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20162 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20163 pm_accepts_block_stack_push(parser,
true);
20165 pm_accepts_block_stack_pop(parser);
20168 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20169 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20170 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)));
20172 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20175 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20179 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20180 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->
previous);
20182 pm_parser_scope_pop(parser);
20183 pm_accepts_block_stack_pop(parser);
20185 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body));
20187 case PM_TOKEN_UPLUS: {
20188 if (binding_power > PM_BINDING_POWER_UNARY) {
20189 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20191 parser_lex(parser);
20194 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20195 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20199 case PM_TOKEN_STRING_BEGIN:
20200 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20201 case PM_TOKEN_SYMBOL_BEGIN: {
20203 parser_lex(parser);
20205 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20216 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20217 pm_parser_err_prefix(parser, diag_id);
20224 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20230 pm_parser_err_prefix(parser, diag_id);
20248parse_assignment_value(
pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power,
bool accepts_command_call,
pm_diagnostic_id_t diag_id, uint16_t depth) {
20249 pm_node_t *value = parse_value_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MATCH,
false, diag_id, (uint16_t) (depth + 1));
20253 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20257 parser_lex(parser);
20259 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MATCH + 1,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20260 context_pop(parser);
20262 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20273parse_assignment_value_local(
pm_parser_t *parser,
const pm_node_t *node) {
20274 switch (PM_NODE_TYPE(node)) {
20275 case PM_BEGIN_NODE: {
20276 const pm_begin_node_t *cast = (
const pm_begin_node_t *) node;
20277 if (cast->
statements != NULL) parse_assignment_value_local(parser, (
const pm_node_t *) cast->
statements);
20280 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20281 const pm_local_variable_write_node_t *cast = (
const pm_local_variable_write_node_t *) node;
20282 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->locals, cast->
name);
20285 case PM_PARENTHESES_NODE: {
20286 const pm_parentheses_node_t *cast = (
const pm_parentheses_node_t *) node;
20287 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20290 case PM_STATEMENTS_NODE: {
20291 const pm_statements_node_t *cast = (
const pm_statements_node_t *) node;
20292 const pm_node_t *statement;
20295 parse_assignment_value_local(parser, statement);
20317parse_assignment_values(
pm_parser_t *parser, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power,
bool accepts_command_call,
pm_diagnostic_id_t diag_id, uint16_t depth) {
20318 bool permitted =
true;
20319 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20321 pm_node_t *value = parse_starred_expression(parser, binding_power, previous_binding_power == PM_BINDING_POWER_ASSIGNMENT ? accepts_command_call : previous_binding_power < PM_BINDING_POWER_MODIFIER, diag_id, (uint16_t) (depth + 1));
20322 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20324 parse_assignment_value_local(parser, value);
20325 bool single_value =
true;
20327 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20328 single_value =
false;
20331 pm_array_node_t *array = pm_array_node_create(parser, &opening);
20333 pm_array_node_elements_append(array, value);
20336 while (accept1(parser, PM_TOKEN_COMMA)) {
20337 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20339 pm_array_node_elements_append(array, element);
20340 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20342 parse_assignment_value_local(parser, element);
20348 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20352 parser_lex(parser);
20354 bool accepts_command_call_inner =
false;
20358 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20359 pm_call_node_t *call_node = (pm_call_node_t *) value;
20361 accepts_command_call_inner =
true;
20365 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MATCH + 1, accepts_command_call_inner,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20366 context_pop(parser);
20368 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20382parse_call_operator_write(
pm_parser_t *parser, pm_call_node_t *call_node,
const pm_token_t *
operator) {
20384 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20385 pm_node_unreference(parser, UP(call_node->
arguments));
20386 pm_node_destroy(parser, UP(call_node->
arguments));
20390 if (call_node->
block != NULL) {
20391 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20392 pm_node_unreference(parser, UP(call_node->
block));
20393 pm_node_destroy(parser, UP(call_node->
block));
20394 call_node->
block = NULL;
20423static inline const uint8_t *
20424pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20427 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20428 uint8_t value = escape_hexadecimal_digit(*cursor);
20431 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20432 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20436 pm_buffer_append_byte(unescaped, value);
20438 pm_buffer_append_string(unescaped,
"\\x", 2);
20444static inline const uint8_t *
20445pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20446 uint8_t value = (uint8_t) (*cursor -
'0');
20449 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20450 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20453 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20454 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20459 pm_buffer_append_byte(unescaped, value);
20463static inline const uint8_t *
20465 const uint8_t *start = cursor - 1;
20468 if (cursor >= end) {
20469 pm_buffer_append_string(unescaped,
"\\u", 2);
20473 if (*cursor !=
'{') {
20474 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20475 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20477 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20478 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20481 return cursor + length;
20486 while (cursor < end && *cursor ==
' ') cursor++;
20488 if (cursor >= end)
break;
20489 if (*cursor ==
'}') {
20494 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20498 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20500 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20508pm_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) {
20509 const uint8_t *end = source + length;
20510 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20513 if (++cursor >= end) {
20514 pm_buffer_append_byte(unescaped,
'\\');
20520 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20522 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20523 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20526 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
20529 pm_buffer_append_byte(unescaped,
'\\');
20533 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
20534 if (next_cursor == NULL)
break;
20536 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20537 cursor = next_cursor;
20540 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20548parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20552 pm_call_node_t *call = callback_data->
call;
20555 const uint8_t *source = pm_string_source(capture);
20556 size_t length = pm_string_length(capture);
20569 pm_named_capture_escape(parser, &unescaped, source, length, cursor, callback_data->
shared ? NULL : &call->
receiver->
location);
20570 source = (
const uint8_t *) pm_buffer_value(&unescaped);
20571 length = pm_buffer_length(&unescaped);
20579 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20580 pm_buffer_free(&unescaped);
20584 if (callback_data->
shared) {
20587 location = (
pm_location_t) { .start = source, .end = source + length };
20588 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20594 void *memory =
xmalloc(length);
20595 if (memory == NULL) abort();
20597 memcpy(memory, source, length);
20598 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20603 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20604 pm_constant_id_list_append(names, name);
20607 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20610 if (pm_local_is_keyword((
const char *) source, length)) {
20611 pm_buffer_free(&unescaped);
20617 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20622 if (callback_data->
match == NULL) {
20623 callback_data->
match = pm_match_write_node_create(parser, call);
20628 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth));
20629 pm_node_list_append(&callback_data->
match->
targets, target);
20632 pm_buffer_free(&unescaped);
20640parse_regular_expression_named_captures(
pm_parser_t *parser,
const pm_string_t *content, pm_call_node_t *call,
bool extended_mode) {
20645 .shared = content->type == PM_STRING_SHARED
20652 .shared = content->type == PM_STRING_SHARED
20655 pm_regexp_parse(parser, pm_string_source(content), pm_string_length(content), extended_mode, parse_regular_expression_named_capture, &callback_data, parse_regular_expression_error, &error_data);
20656 pm_constant_id_list_free(&callback_data.
names);
20658 if (callback_data.
match != NULL) {
20659 return UP(callback_data.
match);
20665static inline pm_node_t *
20666parse_expression_infix(
pm_parser_t *parser, pm_node_t *node, pm_binding_power_t previous_binding_power, pm_binding_power_t binding_power,
bool accepts_command_call, uint16_t depth) {
20669 switch (token.
type) {
20670 case PM_TOKEN_EQUAL: {
20671 switch (PM_NODE_TYPE(node)) {
20672 case PM_CALL_NODE: {
20677 pm_call_node_t *call_node = (pm_call_node_t *) node;
20678 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20683 case PM_CASE_WRITABLE: {
20687 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20691 parser_lex(parser);
20692 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, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20694 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
20695 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20698 return parse_write(parser, node, &token, value);
20700 case PM_SPLAT_NODE: {
20701 pm_multi_target_node_t *multi_target = pm_multi_target_node_create(parser);
20702 pm_multi_target_node_targets_append(parser, multi_target, node);
20704 parser_lex(parser);
20705 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_BINDING_POWER_MULTI_ASSIGNMENT + 1, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20706 return parse_write(parser, UP(multi_target), &token, value);
20708 case PM_SOURCE_ENCODING_NODE:
20709 case PM_FALSE_NODE:
20710 case PM_SOURCE_FILE_NODE:
20711 case PM_SOURCE_LINE_NODE:
20714 case PM_TRUE_NODE: {
20717 parser_lex(parser);
20718 pm_node_t *value = parse_assignment_values(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
20719 return parse_unwriteable_write(parser, node, &token, value);
20725 parser_lex(parser);
20726 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20730 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
20731 switch (PM_NODE_TYPE(node)) {
20732 case PM_BACK_REFERENCE_READ_NODE:
20733 case PM_NUMBERED_REFERENCE_READ_NODE:
20734 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20736 case PM_GLOBAL_VARIABLE_READ_NODE: {
20737 parser_lex(parser);
20739 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20740 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
20742 pm_node_destroy(parser, node);
20745 case PM_CLASS_VARIABLE_READ_NODE: {
20746 parser_lex(parser);
20748 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20749 pm_node_t *result = UP(pm_class_variable_and_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value));
20751 pm_node_destroy(parser, node);
20754 case PM_CONSTANT_PATH_NODE: {
20755 parser_lex(parser);
20757 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20758 pm_node_t *write = UP(pm_constant_path_and_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
20760 return parse_shareable_constant_write(parser, write);
20762 case PM_CONSTANT_READ_NODE: {
20763 parser_lex(parser);
20765 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20766 pm_node_t *write = UP(pm_constant_and_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
20768 pm_node_destroy(parser, node);
20769 return parse_shareable_constant_write(parser, write);
20771 case PM_INSTANCE_VARIABLE_READ_NODE: {
20772 parser_lex(parser);
20774 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20775 pm_node_t *result = UP(pm_instance_variable_and_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value));
20777 pm_node_destroy(parser, node);
20780 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20782 parser_lex(parser);
20784 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20785 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
20787 pm_node_unreference(parser, node);
20788 pm_node_destroy(parser, node);
20791 case PM_LOCAL_VARIABLE_READ_NODE: {
20794 pm_node_unreference(parser, node);
20797 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
20798 parser_lex(parser);
20800 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20801 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20803 pm_node_destroy(parser, node);
20806 case PM_CALL_NODE: {
20807 pm_call_node_t *cast = (pm_call_node_t *) node;
20812 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20814 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20817 parser_lex(parser);
20819 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20820 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20822 pm_node_destroy(parser, UP(cast));
20828 parser_lex(parser);
20833 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20834 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20835 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
20839 if (pm_call_node_writable_p(parser, cast)) {
20840 parse_write_name(parser, &cast->
name);
20842 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20845 parse_call_operator_write(parser, cast, &token);
20846 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ, (uint16_t) (depth + 1));
20847 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
20849 case PM_MULTI_WRITE_NODE: {
20850 parser_lex(parser);
20851 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
20855 parser_lex(parser);
20860 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
20864 case PM_TOKEN_PIPE_PIPE_EQUAL: {
20865 switch (PM_NODE_TYPE(node)) {
20866 case PM_BACK_REFERENCE_READ_NODE:
20867 case PM_NUMBERED_REFERENCE_READ_NODE:
20868 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20870 case PM_GLOBAL_VARIABLE_READ_NODE: {
20871 parser_lex(parser);
20873 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20874 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
20876 pm_node_destroy(parser, node);
20879 case PM_CLASS_VARIABLE_READ_NODE: {
20880 parser_lex(parser);
20882 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20883 pm_node_t *result = UP(pm_class_variable_or_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value));
20885 pm_node_destroy(parser, node);
20888 case PM_CONSTANT_PATH_NODE: {
20889 parser_lex(parser);
20891 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20892 pm_node_t *write = UP(pm_constant_path_or_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
20894 return parse_shareable_constant_write(parser, write);
20896 case PM_CONSTANT_READ_NODE: {
20897 parser_lex(parser);
20899 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20900 pm_node_t *write = UP(pm_constant_or_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
20902 pm_node_destroy(parser, node);
20903 return parse_shareable_constant_write(parser, write);
20905 case PM_INSTANCE_VARIABLE_READ_NODE: {
20906 parser_lex(parser);
20908 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20909 pm_node_t *result = UP(pm_instance_variable_or_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value));
20911 pm_node_destroy(parser, node);
20914 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20916 parser_lex(parser);
20918 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20919 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
20921 pm_node_unreference(parser, node);
20922 pm_node_destroy(parser, node);
20925 case PM_LOCAL_VARIABLE_READ_NODE: {
20928 pm_node_unreference(parser, node);
20931 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
20932 parser_lex(parser);
20934 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20935 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20937 pm_node_destroy(parser, node);
20940 case PM_CALL_NODE: {
20941 pm_call_node_t *cast = (pm_call_node_t *) node;
20946 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20948 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20951 parser_lex(parser);
20953 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20954 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20956 pm_node_destroy(parser, UP(cast));
20962 parser_lex(parser);
20967 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20968 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20969 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
20973 if (pm_call_node_writable_p(parser, cast)) {
20974 parse_write_name(parser, &cast->
name);
20976 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20979 parse_call_operator_write(parser, cast, &token);
20980 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ, (uint16_t) (depth + 1));
20981 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
20983 case PM_MULTI_WRITE_NODE: {
20984 parser_lex(parser);
20985 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
20989 parser_lex(parser);
20994 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
20998 case PM_TOKEN_AMPERSAND_EQUAL:
20999 case PM_TOKEN_CARET_EQUAL:
21000 case PM_TOKEN_GREATER_GREATER_EQUAL:
21001 case PM_TOKEN_LESS_LESS_EQUAL:
21002 case PM_TOKEN_MINUS_EQUAL:
21003 case PM_TOKEN_PERCENT_EQUAL:
21004 case PM_TOKEN_PIPE_EQUAL:
21005 case PM_TOKEN_PLUS_EQUAL:
21006 case PM_TOKEN_SLASH_EQUAL:
21007 case PM_TOKEN_STAR_EQUAL:
21008 case PM_TOKEN_STAR_STAR_EQUAL: {
21009 switch (PM_NODE_TYPE(node)) {
21010 case PM_BACK_REFERENCE_READ_NODE:
21011 case PM_NUMBERED_REFERENCE_READ_NODE:
21012 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
21014 case PM_GLOBAL_VARIABLE_READ_NODE: {
21015 parser_lex(parser);
21017 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21018 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
21020 pm_node_destroy(parser, node);
21023 case PM_CLASS_VARIABLE_READ_NODE: {
21024 parser_lex(parser);
21026 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21027 pm_node_t *result = UP(pm_class_variable_operator_write_node_create(parser, (pm_class_variable_read_node_t *) node, &token, value));
21029 pm_node_destroy(parser, node);
21032 case PM_CONSTANT_PATH_NODE: {
21033 parser_lex(parser);
21035 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21036 pm_node_t *write = UP(pm_constant_path_operator_write_node_create(parser, (pm_constant_path_node_t *) node, &token, value));
21038 return parse_shareable_constant_write(parser, write);
21040 case PM_CONSTANT_READ_NODE: {
21041 parser_lex(parser);
21043 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21044 pm_node_t *write = UP(pm_constant_operator_write_node_create(parser, (pm_constant_read_node_t *) node, &token, value));
21046 pm_node_destroy(parser, node);
21047 return parse_shareable_constant_write(parser, write);
21049 case PM_INSTANCE_VARIABLE_READ_NODE: {
21050 parser_lex(parser);
21052 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21053 pm_node_t *result = UP(pm_instance_variable_operator_write_node_create(parser, (pm_instance_variable_read_node_t *) node, &token, value));
21055 pm_node_destroy(parser, node);
21058 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21060 parser_lex(parser);
21062 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21063 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21065 pm_node_unreference(parser, node);
21066 pm_node_destroy(parser, node);
21069 case PM_LOCAL_VARIABLE_READ_NODE: {
21072 pm_node_unreference(parser, node);
21075 pm_local_variable_read_node_t *cast = (pm_local_variable_read_node_t *) node;
21076 parser_lex(parser);
21078 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21079 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21081 pm_node_destroy(parser, node);
21084 case PM_CALL_NODE: {
21085 parser_lex(parser);
21086 pm_call_node_t *cast = (pm_call_node_t *) node;
21091 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21093 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21096 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21097 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21099 pm_node_destroy(parser, UP(cast));
21106 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21107 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21108 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21112 if (pm_call_node_writable_p(parser, cast)) {
21113 parse_write_name(parser, &cast->
name);
21115 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21118 parse_call_operator_write(parser, cast, &token);
21119 pm_node_t *value = parse_assignment_value(parser, previous_binding_power, binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21120 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21122 case PM_MULTI_WRITE_NODE: {
21123 parser_lex(parser);
21124 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21128 parser_lex(parser);
21137 case PM_TOKEN_AMPERSAND_AMPERSAND:
21138 case PM_TOKEN_KEYWORD_AND: {
21139 parser_lex(parser);
21141 pm_node_t *right = parse_expression(parser, binding_power, parser->
previous.
type == PM_TOKEN_KEYWORD_AND,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21142 return UP(pm_and_node_create(parser, node, &token, right));
21144 case PM_TOKEN_KEYWORD_OR:
21145 case PM_TOKEN_PIPE_PIPE: {
21146 parser_lex(parser);
21148 pm_node_t *right = parse_expression(parser, binding_power, parser->
previous.
type == PM_TOKEN_KEYWORD_OR,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21149 return UP(pm_or_node_create(parser, node, &token, right));
21151 case PM_TOKEN_EQUAL_TILDE: {
21159 parser_lex(parser);
21160 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21163 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21164 pm_node_t *result = UP(call);
21169 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21174 pm_node_list_t *parts = &((pm_interpolated_regular_expression_node_t *) node)->parts;
21176 bool interpolated =
false;
21177 size_t total_length = 0;
21181 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21182 total_length += pm_string_length(&((pm_string_node_t *) part)->unescaped);
21184 interpolated =
true;
21189 if (!interpolated && total_length > 0) {
21190 void *memory =
xmalloc(total_length);
21191 if (!memory) abort();
21193 uint8_t *cursor = memory;
21195 pm_string_t *unescaped = &((pm_string_node_t *) part)->unescaped;
21196 size_t length = pm_string_length(unescaped);
21198 memcpy(cursor, pm_string_source(unescaped), length);
21203 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21205 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21206 pm_string_free(&owned);
21208 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21211 const pm_string_t *content = &((pm_regular_expression_node_t *) node)->unescaped;
21212 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21217 case PM_TOKEN_UAMPERSAND:
21218 case PM_TOKEN_USTAR:
21219 case PM_TOKEN_USTAR_STAR:
21222 case PM_TOKEN_BANG_EQUAL:
21223 case PM_TOKEN_BANG_TILDE:
21224 case PM_TOKEN_EQUAL_EQUAL:
21225 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21226 case PM_TOKEN_LESS_EQUAL_GREATER:
21227 case PM_TOKEN_CARET:
21228 case PM_TOKEN_PIPE:
21229 case PM_TOKEN_AMPERSAND:
21230 case PM_TOKEN_GREATER_GREATER:
21231 case PM_TOKEN_LESS_LESS:
21232 case PM_TOKEN_MINUS:
21233 case PM_TOKEN_PLUS:
21234 case PM_TOKEN_PERCENT:
21235 case PM_TOKEN_SLASH:
21236 case PM_TOKEN_STAR:
21237 case PM_TOKEN_STAR_STAR: {
21238 parser_lex(parser);
21240 switch (PM_NODE_TYPE(node)) {
21241 case PM_RESCUE_MODIFIER_NODE: {
21242 pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
21244 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21248 case PM_AND_NODE: {
21249 pm_and_node_t *cast = (pm_and_node_t *) node;
21250 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21251 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21256 pm_or_node_t *cast = (pm_or_node_t *) node;
21257 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21258 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21266 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21267 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21269 case PM_TOKEN_GREATER:
21270 case PM_TOKEN_GREATER_EQUAL:
21271 case PM_TOKEN_LESS:
21272 case PM_TOKEN_LESS_EQUAL: {
21273 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21274 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21277 parser_lex(parser);
21278 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21279 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21281 case PM_TOKEN_AMPERSAND_DOT:
21282 case PM_TOKEN_DOT: {
21283 parser_lex(parser);
21288 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21289 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21290 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21293 switch (PM_NODE_TYPE(node)) {
21294 case PM_RESCUE_MODIFIER_NODE: {
21295 pm_rescue_modifier_node_t *cast = (pm_rescue_modifier_node_t *) node;
21297 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21301 case PM_AND_NODE: {
21302 pm_and_node_t *cast = (pm_and_node_t *) node;
21303 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21304 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21309 pm_or_node_t *cast = (pm_or_node_t *) node;
21310 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21311 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21322 case PM_CASE_OPERATOR:
21323 case PM_CASE_KEYWORD:
21324 case PM_TOKEN_CONSTANT:
21325 case PM_TOKEN_IDENTIFIER:
21326 case PM_TOKEN_METHOD_NAME: {
21327 parser_lex(parser);
21337 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21338 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21341 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21344 match1(parser, PM_TOKEN_COMMA)
21346 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21351 case PM_TOKEN_DOT_DOT:
21352 case PM_TOKEN_DOT_DOT_DOT: {
21353 parser_lex(parser);
21355 pm_node_t *right = NULL;
21356 if (token_begins_expression_p(parser->
current.
type)) {
21357 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21360 return UP(pm_range_node_create(parser, node, &token, right));
21362 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21364 parser_lex(parser);
21366 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21367 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21369 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21371 parser_lex(parser);
21373 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21374 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21376 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21377 parser_lex(parser);
21378 pm_statements_node_t *statements = pm_statements_node_create(parser);
21379 pm_statements_node_body_append(parser, statements, node,
true);
21381 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21382 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));
21384 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21385 parser_lex(parser);
21386 pm_statements_node_t *statements = pm_statements_node_create(parser);
21387 pm_statements_node_body_append(parser, statements, node,
true);
21389 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21390 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));
21392 case PM_TOKEN_QUESTION_MARK: {
21394 pm_node_list_t current_block_exits = { 0 };
21395 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21398 parser_lex(parser);
21400 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21410 pm_node_t *false_expression = UP(pm_missing_node_create(parser, colon.
start, colon.
end));
21412 context_pop(parser);
21413 pop_block_exits(parser, previous_block_exits);
21414 pm_node_list_free(¤t_block_exits);
21416 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21419 accept1(parser, PM_TOKEN_NEWLINE);
21420 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21423 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21425 context_pop(parser);
21426 pop_block_exits(parser, previous_block_exits);
21427 pm_node_list_free(¤t_block_exits);
21429 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21431 case PM_TOKEN_COLON_COLON: {
21432 parser_lex(parser);
21436 case PM_TOKEN_CONSTANT: {
21437 parser_lex(parser);
21441 (parser->
current.
type == PM_TOKEN_PARENTHESIS_LEFT) ||
21442 (accepts_command_call && (token_begins_expression_p(parser->
current.
type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21453 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21454 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21457 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21461 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21462 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21467 case PM_CASE_OPERATOR:
21468 case PM_CASE_KEYWORD:
21469 case PM_TOKEN_IDENTIFIER:
21470 case PM_TOKEN_METHOD_NAME: {
21471 parser_lex(parser);
21477 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21478 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21481 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21482 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21487 case PM_TOKEN_PARENTHESIS_LEFT: {
21491 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21493 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21496 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21497 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21501 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21503 parser_lex(parser);
21504 accept1(parser, PM_TOKEN_NEWLINE);
21506 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21507 context_pop(parser);
21509 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21511 case PM_TOKEN_BRACKET_LEFT: {
21512 parser_lex(parser);
21517 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21518 pm_accepts_block_stack_push(parser,
true);
21519 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
21520 pm_accepts_block_stack_pop(parser);
21521 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21528 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21529 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21530 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21536 pm_block_node_t *block = NULL;
21537 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21538 block = parse_block(parser, (uint16_t) (depth + 1));
21539 pm_arguments_validate_block(parser, &arguments, block);
21540 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21541 block = parse_block(parser, (uint16_t) (depth + 1));
21544 if (block != NULL) {
21545 if (arguments.
block != NULL) {
21546 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21548 arguments.
arguments = pm_arguments_node_create(parser);
21550 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21553 arguments.
block = UP(block);
21556 return UP(pm_call_node_aref_create(parser, node, &arguments));
21558 case PM_TOKEN_KEYWORD_IN: {
21564 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21565 parser_lex(parser);
21568 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));
21571 pm_constant_id_list_free(&captures);
21573 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21575 case PM_TOKEN_EQUAL_GREATER: {
21581 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21582 parser_lex(parser);
21585 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));
21588 pm_constant_id_list_free(&captures);
21590 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21593 assert(
false &&
"unreachable");
21598#undef PM_PARSE_PATTERN_SINGLE
21599#undef PM_PARSE_PATTERN_TOP
21600#undef PM_PARSE_PATTERN_MULTI
21607pm_call_node_command_p(
const pm_call_node_t *node) {
21610 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
21624parse_expression(
pm_parser_t *parser, pm_binding_power_t binding_power,
bool accepts_command_call,
bool accepts_label,
pm_diagnostic_id_t diag_id, uint16_t depth) {
21626 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21630 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21632 switch (PM_NODE_TYPE(node)) {
21633 case PM_MISSING_NODE:
21637 case PM_PRE_EXECUTION_NODE:
21638 case PM_POST_EXECUTION_NODE:
21639 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
21640 case PM_ALIAS_METHOD_NODE:
21641 case PM_MULTI_WRITE_NODE:
21642 case PM_UNDEF_NODE:
21645 if (pm_binding_powers[parser->
current.
type].left > PM_BINDING_POWER_MODIFIER) {
21655 if ((pm_binding_powers[parser->
current.
type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((pm_call_node_t *) node)) {
21659 case PM_SYMBOL_NODE:
21663 if (pm_symbol_node_label_p(node)) {
21674 pm_token_type_t current_token_type;
21678 current_binding_powers = pm_binding_powers[current_token_type],
21679 binding_power <= current_binding_powers.
left &&
21680 current_binding_powers.
binary
21682 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21684 switch (PM_NODE_TYPE(node)) {
21685 case PM_MULTI_WRITE_NODE:
21688 if (pm_binding_powers[parser->
current.
type].left > PM_BINDING_POWER_MODIFIER) {
21692 case PM_CLASS_VARIABLE_WRITE_NODE:
21693 case PM_CONSTANT_PATH_WRITE_NODE:
21694 case PM_CONSTANT_WRITE_NODE:
21695 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21696 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21697 case PM_LOCAL_VARIABLE_WRITE_NODE:
21700 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.
type].left > PM_BINDING_POWER_MODIFIER) {
21708 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.
type].left > PM_BINDING_POWER_MODIFIER) {
21718 if (current_binding_powers.
nonassoc) {
21721 if (match1(parser, current_token_type)) {
21733 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((pm_range_node_t *) node)->right == NULL) {
21734 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
21739 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.
type].left) {
21742 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.
type].left) {
21747 if (accepts_command_call) {
21756 switch (node->
type) {
21757 case PM_CALL_NODE: {
21758 pm_call_node_t *cast = (pm_call_node_t *)node;
21771 cast->
block == NULL &&
21781 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
21784 accepts_command_call =
false;
21789 case PM_CONSTANT_PATH_NODE:
21792 accepts_command_call =
false;
21800 !next_binding_powers.
binary ||
21801 binding_power > next_binding_powers.
left ||
21802 (PM_NODE_TYPE_P(node, PM_CALL_NODE) && pm_call_node_command_p((pm_call_node_t *) node))
21816static pm_statements_node_t *
21817wrap_statements(
pm_parser_t *parser, pm_statements_node_t *statements) {
21818 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21819 if (statements == NULL) {
21820 statements = pm_statements_node_create(parser);
21823 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
21824 pm_arguments_node_arguments_append(
21826 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
21829 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
21832 pm_parser_constant_id_constant(parser,
"print", 5)
21836 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21837 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21838 if (statements == NULL) {
21839 statements = pm_statements_node_create(parser);
21842 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
21843 pm_arguments_node_arguments_append(
21845 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
21848 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21849 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
21851 pm_global_variable_write_node_t *write = pm_global_variable_write_node_synthesized_create(
21853 pm_parser_constant_id_constant(parser,
"$F", 2),
21857 pm_statements_node_body_prepend(statements, UP(write));
21860 pm_arguments_node_t *arguments = pm_arguments_node_create(parser);
21861 pm_arguments_node_arguments_append(
21863 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
21866 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21867 pm_keyword_hash_node_t *keywords = pm_keyword_hash_node_create(parser);
21868 pm_keyword_hash_node_elements_append(keywords, UP(pm_assoc_node_create(
21870 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
21871 &(
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start },
21872 UP(pm_true_node_synthesized_create(parser))
21875 pm_arguments_node_arguments_append(arguments, UP(keywords));
21876 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
21879 pm_statements_node_t *wrapped_statements = pm_statements_node_create(parser);
21880 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
21882 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
21886 statements = wrapped_statements;
21901 pm_parser_scope_push(parser,
true);
21904 pm_node_list_t current_block_exits = { 0 };
21905 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21907 parser_lex(parser);
21908 pm_statements_node_t *statements = parse_statements(parser,
PM_CONTEXT_MAIN, 0);
21914 assert(statements->
body.
size > 0);
21915 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
21920 pm_parser_scope_pop(parser);
21924 if (parser->
command_line & (PM_OPTIONS_COMMAND_LINE_P | PM_OPTIONS_COMMAND_LINE_N)) {
21925 statements = wrap_statements(parser, statements);
21927 flush_block_exits(parser, previous_block_exits);
21930 pm_node_list_free(¤t_block_exits);
21935 if (statements == NULL) {
21936 statements = pm_statements_node_create(parser);
21937 pm_statements_node_location_set(statements, parser->
start, parser->
start);
21940 return UP(pm_program_node_create(parser, &locals, statements));
21957pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
21958 size_t little_length = strlen(little);
21960 for (
const char *max = big + big_length - little_length; big <= max; big++) {
21961 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
21968#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
21976pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
21977 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
21978 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
21989 const char *switches = pm_strnstr(engine,
" -", length);
21990 if (switches == NULL)
return;
21995 (
const uint8_t *) (switches + 1),
21996 length - ((
size_t) (switches - engine)) - 1,
22000 size_t encoding_length;
22001 if ((encoding_length = pm_string_length(&next_options.
encoding)) > 0) {
22002 const uint8_t *encoding_source = pm_string_source(&next_options.
encoding);
22003 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22015 assert(source != NULL);
22019 .lex_state = PM_LEX_STATE_BEG,
22020 .enclosure_nesting = 0,
22021 .lambda_enclosure_nesting = -1,
22022 .brace_nesting = 0,
22023 .do_loop_stack = 0,
22024 .accepts_block_stack = 0,
22027 .stack = {{ .mode = PM_LEX_DEFAULT }},
22028 .current = &parser->lex_modes.stack[0],
22031 .end = source + size,
22032 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22033 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
22034 .next_start = NULL,
22035 .heredoc_end = NULL,
22036 .data_loc = { .start = NULL, .end = NULL },
22037 .comment_list = { 0 },
22038 .magic_comment_list = { 0 },
22039 .warning_list = { 0 },
22040 .error_list = { 0 },
22041 .current_scope = NULL,
22042 .current_context = NULL,
22044 .encoding_changed_callback = NULL,
22045 .encoding_comment_start = source,
22046 .lex_callback = NULL,
22048 .constant_pool = { 0 },
22049 .newline_list = { 0 },
22053 .explicit_encoding = NULL,
22055 .parsing_eval =
false,
22056 .partial_script =
false,
22057 .command_start =
true,
22058 .recovering =
false,
22059 .encoding_locked =
false,
22060 .encoding_changed =
false,
22061 .pattern_matching_newlines =
false,
22062 .in_keyword_arg =
false,
22063 .current_block_exits = NULL,
22064 .semantic_token_seen =
false,
22066 .current_regular_expression_ascii_only =
false,
22067 .warn_mismatched_indentation =
true
22084 uint32_t constant_size = ((uint32_t) size) / 95;
22085 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22090 size_t newline_size = size / 22;
22091 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22094 if (options != NULL) {
22102 size_t encoding_length = pm_string_length(&options->
encoding);
22103 if (encoding_length > 0) {
22104 const uint8_t *encoding_source = pm_string_source(&options->
encoding);
22105 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22127 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22129 pm_parser_scope_push(parser, scope_index == 0);
22135 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22136 const pm_string_t *local = pm_options_scope_local_get(scope, local_index);
22138 const uint8_t *source = pm_string_source(local);
22139 size_t length = pm_string_length(local);
22141 void *allocated =
xmalloc(length);
22142 if (allocated == NULL)
continue;
22144 memcpy(allocated, source, length);
22145 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22156 pm_accepts_block_stack_push(parser,
true);
22159 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22172 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22190 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
current.
end);
22193 const char *engine;
22195 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22196 if (newline != NULL) {
22200 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22205 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22208 search_shebang =
false;
22210 search_shebang =
true;
22216 if (search_shebang) {
22219 bool found_shebang =
false;
22223 const uint8_t *cursor = parser->
start;
22227 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22229 while (newline != NULL) {
22230 pm_newline_list_append(&parser->
newline_list, newline);
22232 cursor = newline + 1;
22233 newline = next_newline(cursor, parser->
end - cursor);
22235 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22236 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22237 const char *engine;
22238 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22239 found_shebang =
true;
22241 if (newline != NULL) {
22242 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22247 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22255 if (found_shebang) {
22256 parser->
previous = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22257 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22259 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22286 for (node = list->
head; node != NULL; node = next) {
22298pm_magic_comment_list_free(
pm_list_t *list) {
22301 for (node = list->
head; node != NULL; node = next) {
22314 pm_string_free(&parser->
filepath);
22315 pm_diagnostic_list_free(&parser->
error_list);
22327 pm_parser_scope_pop(parser);
22331 lex_mode_pop(parser);
22340 return parse_program(parser);
22350#define LINE_SIZE 4096
22351 char line[LINE_SIZE];
22353 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22354 size_t length = LINE_SIZE;
22355 while (length > 0 && line[length - 1] ==
'\n') length--;
22357 if (length == LINE_SIZE) {
22362 pm_buffer_append_string(buffer, line, length);
22368 pm_buffer_append_string(buffer, line, length);
22376 if (strncmp(line,
"__END__", 7) == 0)
return false;
22379 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22382 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22388 if (stream_feof(stream)) {
22407pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22410 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22411 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22427 pm_buffer_init(buffer);
22429 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22431 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22432 pm_node_t *node =
pm_parse(parser);
22434 while (!eof && parser->
error_list.
size > 0 && (parser->lex_modes.index > 0 || pm_parse_stream_unterminated_heredoc_p(parser))) {
22435 pm_node_destroy(parser, node);
22436 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22439 pm_parser_init(parser, (
const uint8_t *) pm_buffer_value(buffer), pm_buffer_length(buffer), options);
22450pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22452 pm_options_read(&options, data);
22455 pm_parser_init(&parser, source, size, &options);
22457 pm_node_t *node = pm_parse(&parser);
22458 pm_node_destroy(&parser, node);
22461 pm_parser_free(&parser);
22462 pm_options_free(&options);
22467#undef PM_CASE_KEYWORD
22468#undef PM_CASE_OPERATOR
22469#undef PM_CASE_WRITABLE
22470#undef PM_STRING_EMPTY
22475#ifndef PRISM_EXCLUDE_SERIALIZATION
22479 pm_buffer_append_string(buffer,
"PRISM", 5);
22483 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22491 pm_serialize_header(buffer);
22493 pm_buffer_append_byte(buffer,
'\0');
22501pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22503 pm_options_read(&options, data);
22506 pm_parser_init(&parser, source, size, &options);
22508 pm_node_t *node = pm_parse(&parser);
22510 pm_serialize_header(buffer);
22512 pm_buffer_append_byte(buffer,
'\0');
22514 pm_node_destroy(&parser, node);
22515 pm_parser_free(&parser);
22516 pm_options_free(&options);
22527 pm_options_read(&options, data);
22530 pm_node_t *node = pm_parse_stream(&parser, &parser_buffer, stream, stream_fgets, stream_feof, &options);
22531 pm_serialize_header(buffer);
22533 pm_buffer_append_byte(buffer,
'\0');
22535 pm_node_destroy(&parser, node);
22536 pm_buffer_free(&parser_buffer);
22537 pm_parser_free(&parser);
22538 pm_options_free(&options);
22545pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22547 pm_options_read(&options, data);
22550 pm_parser_init(&parser, source, size, &options);
22552 pm_node_t *node = pm_parse(&parser);
22553 pm_serialize_header(buffer);
22555 pm_buffer_append_varsint(buffer, parser.
start_line);
22558 pm_node_destroy(&parser, node);
22559 pm_parser_free(&parser);
22560 pm_options_free(&options);
22572 PM_SLICE_TYPE_ERROR = -1,
22575 PM_SLICE_TYPE_NONE,
22578 PM_SLICE_TYPE_LOCAL,
22581 PM_SLICE_TYPE_CONSTANT,
22584 PM_SLICE_TYPE_METHOD_NAME
22591pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22593 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22594 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22597 if (length == 0)
return PM_SLICE_TYPE_NONE;
22600 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22602 }
else if (*source ==
'_') {
22605 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22609 return PM_SLICE_TYPE_NONE;
22613 const uint8_t *end = source + length;
22614 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22620 while (source < end) {
22621 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22624 }
else if (*source ==
'_') {
22627 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22637 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22639 result = PM_SLICE_TYPE_METHOD_NAME;
22643 return source == end ? result : PM_SLICE_TYPE_NONE;
22650pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22651 switch (pm_slice_type(source, length, encoding_name)) {
22652 case PM_SLICE_TYPE_ERROR:
22654 case PM_SLICE_TYPE_NONE:
22655 case PM_SLICE_TYPE_CONSTANT:
22656 case PM_SLICE_TYPE_METHOD_NAME:
22658 case PM_SLICE_TYPE_LOCAL:
22662 assert(
false &&
"unreachable");
22670pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22671 switch (pm_slice_type(source, length, encoding_name)) {
22672 case PM_SLICE_TYPE_ERROR:
22674 case PM_SLICE_TYPE_NONE:
22675 case PM_SLICE_TYPE_LOCAL:
22676 case PM_SLICE_TYPE_METHOD_NAME:
22678 case PM_SLICE_TYPE_CONSTANT:
22682 assert(
false &&
"unreachable");
22690pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22691#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22692#define C1(c) (*source == c)
22693#define C2(s) (memcmp(source, s, 2) == 0)
22694#define C3(s) (memcmp(source, s, 3) == 0)
22696 switch (pm_slice_type(source, length, encoding_name)) {
22697 case PM_SLICE_TYPE_ERROR:
22699 case PM_SLICE_TYPE_NONE:
22701 case PM_SLICE_TYPE_LOCAL:
22703 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22704 case PM_SLICE_TYPE_CONSTANT:
22706 case PM_SLICE_TYPE_METHOD_NAME:
22713 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22715 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22717 return B(C3(
"===") || C3(
"<=>") || C3(
"[]="));
pm_diagnostic_id_t
The diagnostic IDs of all of the diagnostics, used to communicate the types of errors between the par...
#define xfree
Old name of ruby_xfree.
#define xmalloc
Old name of ruby_xmalloc.
#define xcalloc
Old name of ruby_xcalloc.
VALUE type(ANYARGS)
ANYARGS-ed function type.
struct pm_options_scope pm_options_scope_t
A scope of locals surrounding the code that is being parsed.
struct pm_options pm_options_t
The options that can be passed to the parser.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should be made frozen.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED
String literals should be made mutable.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_UNSET
String literals may be frozen or mutable depending on the implementation default.
@ PM_OPTIONS_VERSION_CRUBY_3_3
The vendored version of prism in CRuby 3.3.x.
@ PM_OPTIONS_VERSION_LATEST
The current version of prism.
@ PM_OPTIONS_VERSION_UNSET
If an explicit version is not provided, the current version of prism will be used.
@ PM_OPTIONS_VERSION_CRUBY_3_4
The vendored version of prism in CRuby 3.4.x.
@ PM_OPTIONS_VERSION_CRUBY_4_0
The vendored version of prism in CRuby 4.0.x.
struct pm_locals pm_locals_t
This is a set of local variables in a certain lexical context (method, class, module,...
pm_heredoc_indent_t
The type of indentation that a heredoc uses.
struct pm_context_node pm_context_node_t
This is a node in a linked list of contexts.
#define PM_LEX_STACK_SIZE
We pre-allocate a certain number of lex states in order to avoid having to call malloc too many times...
struct pm_parser pm_parser_t
The parser used to parse Ruby source.
struct pm_lex_mode pm_lex_mode_t
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
struct pm_comment pm_comment_t
This is a node in the linked list of comments that we've found while parsing.
void(*) pm_encoding_changed_callback_t(pm_parser_t *parser)
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
pm_lex_state_t
This enum combines the various bits from the above enum into individual values that represent the var...
struct pm_scope pm_scope_t
This struct represents a node in a linked list of scopes.
pm_heredoc_quote_t
The type of quote that a heredoc uses.
pm_context_t
While parsing, we keep track of a stack of contexts.
@ PM_CONTEXT_CLASS_RESCUE
a rescue statement within a class statement
@ PM_CONTEXT_ELSIF
an elsif clause
@ PM_CONTEXT_DEF_RESCUE
a rescue statement within a method definition
@ PM_CONTEXT_ELSE
an else clause
@ PM_CONTEXT_FOR_INDEX
a for loop's index
@ PM_CONTEXT_CASE_WHEN
a case when statements
@ PM_CONTEXT_BLOCK_RESCUE
a rescue statement within a do..end block
@ PM_CONTEXT_MODULE
a module declaration
@ PM_CONTEXT_DEF_PARAMS
a method definition's parameters
@ PM_CONTEXT_CASE_IN
a case in statements
@ PM_CONTEXT_BLOCK_ELSE
a rescue else statement within a do..end block
@ PM_CONTEXT_LOOP_PREDICATE
the predicate clause of a loop statement
@ PM_CONTEXT_SCLASS
a singleton class definition
@ PM_CONTEXT_UNLESS
an unless statement
@ PM_CONTEXT_POSTEXE
an END block
@ PM_CONTEXT_IF
an if statement
@ PM_CONTEXT_MULTI_TARGET
a multiple target expression
@ PM_CONTEXT_LAMBDA_RESCUE
a rescue statement within a lambda expression
@ PM_CONTEXT_BEGIN_ELSE
a rescue else statement with an explicit begin
@ PM_CONTEXT_NONE
a null context, used for returning a value from a function
@ PM_CONTEXT_CLASS_ELSE
a rescue else statement within a class statement
@ PM_CONTEXT_LAMBDA_ENSURE
an ensure statement within a lambda expression
@ PM_CONTEXT_BLOCK_ENSURE
an ensure statement within a do..end block
@ PM_CONTEXT_CLASS_ENSURE
an ensure statement within a class statement
@ PM_CONTEXT_LAMBDA_BRACES
a lambda expression with braces
@ PM_CONTEXT_MODULE_ELSE
a rescue else statement within a module statement
@ PM_CONTEXT_PARENS
a parenthesized expression
@ PM_CONTEXT_BLOCK_BRACES
expressions in block arguments using braces
@ PM_CONTEXT_BLOCK_PARAMETERS
expressions in block parameters foo do |...| end
@ PM_CONTEXT_DEF_ENSURE
an ensure statement within a method definition
@ PM_CONTEXT_SCLASS_RESCUE
a rescue statement with a singleton class
@ PM_CONTEXT_PREEXE
a BEGIN block
@ PM_CONTEXT_DEFINED
a defined?
@ PM_CONTEXT_MODULE_ENSURE
an ensure statement within a module statement
@ PM_CONTEXT_BEGIN_RESCUE
a rescue statement with an explicit begin
@ PM_CONTEXT_UNTIL
an until statement
@ PM_CONTEXT_DEF_ELSE
a rescue else statement within a method definition
@ PM_CONTEXT_FOR
a for loop
@ PM_CONTEXT_PREDICATE
a predicate inside an if/elsif/unless statement
@ PM_CONTEXT_BEGIN_ENSURE
an ensure statement with an explicit begin
@ PM_CONTEXT_SCLASS_ENSURE
an ensure statement with a singleton class
@ PM_CONTEXT_DEFAULT_PARAMS
a method definition's default parameter
@ PM_CONTEXT_LAMBDA_ELSE
a rescue else statement within a lambda expression
@ PM_CONTEXT_CLASS
a class declaration
@ PM_CONTEXT_MAIN
the top level context
@ PM_CONTEXT_LAMBDA_DO_END
a lambda expression with do..end
@ PM_CONTEXT_BEGIN
a begin statement
@ PM_CONTEXT_RESCUE_MODIFIER
a modifier rescue clause
@ PM_CONTEXT_EMBEXPR
an interpolated expression
@ PM_CONTEXT_TERNARY
a ternary expression
@ PM_CONTEXT_DEF
a method definition
@ PM_CONTEXT_SCLASS_ELSE
a rescue else statement with a singleton class
@ PM_CONTEXT_MODULE_RESCUE
a rescue statement within a module statement
@ PM_CONTEXT_BLOCK_KEYWORDS
expressions in block arguments using do..end
@ PM_CONTEXT_WHILE
a while statement
uint8_t pm_scope_parameters_t
The flags about scope parameters that can be set.
uint8_t pm_shareable_constant_value_t
The type of shareable constant value that can be set.
pm_comment_type_t
This is the type of a comment that we've found while parsing.
#define PM_CONSTANT_ID_UNSET
When we allocate constants into the pool, we reserve 0 to mean that the slot is not yet filled.
uint32_t pm_constant_id_t
A constant id is a unique identifier for a constant in the constant pool.
struct pm_list_node pm_list_node_t
This struct represents an abstract linked list that provides common functionality.
#define PM_STRING_EMPTY
Defines an empty string.
#define PRISM_FALLTHROUGH
We use -Wimplicit-fallthrough to guard potentially unintended fall-through between cases of a switch.
#define PRISM_UNLIKELY(x)
The compiler should predicate that this branch will not be taken.
#define PRISM_ATTRIBUTE_UNUSED
GCC will warn if you specify a function or parameter that is unused at runtime.
#define PRISM_DEPTH_MAXIMUM
When we are parsing using recursive descent, we want to protect against malicious payloads that could...
#define PM_STATIC_ASSERT(line, condition, message)
We want to be able to use static assertions, but they weren't standardized until C11.
#define PRISM_EXPORTED_FUNCTION
By default, we compile with -fvisibility=hidden.
#define PM_ENCODING_US_ASCII_ENTRY
This is the US-ASCII encoding.
#define PM_ENCODING_UTF_8_ENTRY
This is the default UTF-8 encoding.
#define PRISM_ENCODING_ALPHABETIC_BIT
All of the lookup tables use the first bit of each embedded byte to indicate whether the codepoint is...
#define PRISM_ENCODING_ALPHANUMERIC_BIT
All of the lookup tables use the second bit of each embedded byte to indicate whether the codepoint i...
#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.
#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 main header file for the prism parser.
pm_string_query_t
Represents the results of a slice query.
@ PM_STRING_QUERY_TRUE
Returned if the result of the slice query is true.
@ PM_STRING_QUERY_ERROR
Returned if the encoding given to a slice query was invalid.
@ PM_STRING_QUERY_FALSE
Returned if the result of the slice query is false.
void pm_serialize_content(pm_parser_t *parser, pm_node_t *node, pm_buffer_t *buffer)
Serialize the encoding, metadata, nodes, and constant pool.
int pm_parse_stream_feof_t(void *stream)
This function is used in pm_parse_stream to check whether a stream is EOF.
void pm_serialize_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
char * pm_parse_stream_fgets_t(char *string, int size, void *stream)
This function is used in pm_parse_stream() to retrieve a line of input from a stream.
void pm_serialize_comment_list(pm_parser_t *parser, pm_list_t *list, pm_buffer_t *buffer)
Serialize the given list of comments to the given buffer.
const char * pm_token_type_human(pm_token_type_t token_type)
Returns the human name of the given token type.
This struct is used to pass information between the regular expression parser and the error callback.
pm_parser_t * parser
The parser that we are parsing the regular expression for.
const uint8_t * start
The start of the regular expression.
bool shared
Whether or not the source of the regular expression is shared.
const uint8_t * end
The end of the regular expression.
This struct is used to pass information between the regular expression parser and the named capture c...
pm_constant_id_list_t names
The list of names that have been parsed.
pm_parser_t * parser
The parser that is parsing the regular expression.
pm_match_write_node_t * match
The match write node that is being created.
pm_call_node_t * call
The call node wrapping the regular expression node.
bool shared
Whether the content of the regular expression is shared.
struct pm_node * left
AndNode::left.
struct pm_node * right
AndNode::right.
pm_node_t base
The embedded base node.
struct pm_node_list arguments
ArgumentsNode::arguments.
This is a special out parameter to the parse_arguments_list function that includes opening and closin...
pm_node_t * block
The optional block attached to the call.
bool has_forwarding
The flag indicating whether this arguments list has forwarding argument.
pm_location_t opening_loc
The optional location of the opening parenthesis or bracket.
pm_arguments_node_t * arguments
The lazily-allocated optional arguments node.
pm_location_t closing_loc
The optional location of the closing parenthesis or bracket.
struct pm_node_list elements
ArrayNode::elements.
struct pm_node * constant
ArrayPatternNode::constant.
pm_location_t opening_loc
ArrayPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
ArrayPatternNode::closing_loc.
struct pm_node * value
AssocNode::value.
struct pm_node * key
AssocNode::key.
struct pm_ensure_node * ensure_clause
BeginNode::ensure_clause.
struct pm_rescue_node * rescue_clause
BeginNode::rescue_clause.
struct pm_statements_node * statements
BeginNode::statements.
pm_node_t base
The embedded base node.
struct pm_else_node * else_clause
BeginNode::else_clause.
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.
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
size_t length
The length of the buffer in bytes.
char * value
A pointer to the start of the buffer.
pm_location_t opening_loc
CallNode::opening_loc.
pm_location_t closing_loc
CallNode::closing_loc.
struct pm_node * receiver
CallNode::receiver.
pm_constant_id_t name
CallNode::name.
pm_node_t base
The embedded base node.
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.
struct pm_arguments_node * arguments
CallNode::arguments.
struct pm_node * block
CallNode::block.
struct pm_node_list conditions
CaseMatchNode::conditions.
struct pm_node_list conditions
CaseNode::conditions.
size_t size
The number of constant ids in the list.
A constant in the pool which effectively stores a string.
size_t length
The length of the string.
const uint8_t * start
A pointer to the start of the string.
pm_context_t context
The context that this node represents.
struct pm_context_node * prev
A pointer to the previous context in the linked list.
This struct represents a diagnostic generated during parsing.
struct pm_statements_node * statements
ElseNode::statements.
This struct defines the functions necessary to implement the encoding interface so we can determine h...
size_t(*) alpha_char(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphab...
size_t(*) char_width(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding.
bool(*) isupper_char(const uint8_t *b, ptrdiff_t n)
Return true if the next character is valid in the encoding and is an uppercase character.
size_t(*) alnum_char(const uint8_t *b, ptrdiff_t n)
Return the number of bytes that the next character takes if it is valid in the encoding and is alphan...
const char * name
The name of the encoding.
struct pm_statements_node * statements
EnsureNode::statements.
struct pm_node * constant
FindPatternNode::constant.
pm_location_t opening_loc
FindPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
FindPatternNode::closing_loc.
double value
FloatNode::value.
pm_node_t base
The embedded base node.
struct pm_node_list elements
HashNode::elements.
pm_location_t opening_loc
HashPatternNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t closing_loc
HashPatternNode::closing_loc.
struct pm_node * constant
HashPatternNode::constant.
All of the information necessary to store to lexing a heredoc.
size_t ident_length
The length of the heredoc identifier.
pm_heredoc_quote_t quote
The type of quote that the heredoc uses.
pm_heredoc_indent_t indent
The type of indentation that the heredoc uses.
const uint8_t * ident_start
A pointer to the start of the heredoc identifier.
struct pm_statements_node * statements
IfNode::statements.
struct pm_node * subsequent
IfNode::subsequent.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedXStringNode::opening_loc.
pm_node_t base
The embedded base node.
struct pm_node_list parts
InterpolatedXStringNode::parts.
void(*) callback(void *data, pm_parser_t *parser, pm_token_t *token)
This is the callback that is called when a token is lexed.
void * data
This opaque pointer is used to provide whatever information the user deemed necessary to the callback...
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
struct pm_list_node * next
A pointer to the next node in the list.
This represents the overall linked list.
pm_list_node_t * head
A pointer to the head of the list.
size_t size
The size of the list.
This tracks an individual local variable in a certain lexical context, as well as the number of times...
pm_constant_id_t name
The name of the local variable.
pm_location_t location
The location of the local variable in the source.
uint32_t hash
The hash of the local variable.
uint32_t index
The index of the local variable in the local table.
uint32_t reads
The number of times the local variable is read.
uint32_t depth
LocalVariableReadNode::depth.
pm_constant_id_t name
LocalVariableReadNode::name.
uint32_t depth
LocalVariableWriteNode::depth.
pm_constant_id_t name
LocalVariableWriteNode::name.
pm_local_t * locals
The nullable allocated memory for the local variables in the set.
uint32_t capacity
The capacity of the local variables set.
uint32_t size
The number of local variables in the set.
This represents a range of bytes in the source string to which a node or token corresponds.
const uint8_t * start
A pointer to the start location of the range in the source.
const uint8_t * end
A pointer to the end location of the range in the source.
struct pm_node_list targets
MatchWriteNode::targets.
pm_node_t base
The embedded base node.
pm_location_t lparen_loc
MultiTargetNode::lparen_loc.
struct pm_node_list lefts
MultiTargetNode::lefts.
pm_location_t rparen_loc
MultiTargetNode::rparen_loc.
size_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
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.
size_t locals_count
The number of locals in the scope.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
uint8_t command_line
A bitset of the various options that were set on the command line.
void * shebang_callback_data
Any additional data that should be passed along to the shebang callback if one was set.
bool encoding_locked
Whether or not the encoding magic comments should be respected.
bool main_script
When the file being parsed is the main script, the shebang will be considered for command-line flags ...
pm_string_t encoding
The name of the encoding that the source file is in.
int32_t line
The line within the file that the parse starts on.
pm_options_shebang_callback_t shebang_callback
The callback to call when additional switches are found in a shebang comment.
int8_t frozen_string_literal
Whether or not the frozen string literal option has been set.
bool partial_script
When the file being parsed is considered a "partial" script, jumps will not be marked as errors if th...
size_t scopes_count
The number of scopes surrounding the code that is being parsed.
pm_string_t filepath
The name of the file that is currently being parsed.
pm_options_version_t version
The version of prism that we should be parsing with.
struct pm_node * left
OrNode::left.
struct pm_node * right
OrNode::right.
struct pm_node * rest
ParametersNode::rest.
struct pm_block_parameter_node * block
ParametersNode::block.
pm_node_t base
The embedded base node.
struct pm_node * keyword_rest
ParametersNode::keyword_rest.
struct pm_node * body
ParenthesesNode::body.
const pm_encoding_t * explicit_encoding
When a string-like expression is being lexed, any byte or escape sequence that resolves to a value wh...
pm_lex_state_t lex_state
The current state of the lexer.
uint8_t command_line
The command line flags given from the options.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser)
Initiate the parser with the given parser.
const pm_encoding_t * encoding
The encoding functions for the current file is attached to the parser as it's parsing so that it can ...
bool partial_script
Whether or not we are parsing a "partial" script, which is a script that will be evaluated in the con...
PRISM_EXPORTED_FUNCTION void pm_parser_register_encoding_changed_callback(pm_parser_t *parser, pm_encoding_changed_callback_t callback)
Register a callback that will be called whenever prism changes the encoding it is using to parse base...
bool pattern_matching_newlines
This flag indicates that we are currently parsing a pattern matching expression and impacts that calc...
const uint8_t * end
The pointer to the end of the source.
bool recovering
Whether or not we're currently recovering from a syntax error.
pm_node_flags_t integer_base
We want to add a flag to integer nodes that indicates their base.
bool warn_mismatched_indentation
By default, Ruby always warns about mismatched indentation.
pm_constant_pool_t constant_pool
This constant pool keeps all of the constants defined throughout the file so that we can reference th...
bool in_keyword_arg
This flag indicates that we are currently parsing a keyword argument.
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser)
Free any memory associated with the given parser.
const uint8_t * next_start
This is a special field set on the parser when we need the parser to jump to a specific location when...
pm_static_literals_t * current_hash_keys
The hash keys for the hash that is currently being parsed.
pm_list_t magic_comment_list
The list of magic comments that have been found while parsing.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse_stream(pm_parser_t *parser, pm_buffer_t *buffer, void *stream, pm_parse_stream_fgets_t *stream_fgets, pm_parse_stream_feof_t *stream_feof, const pm_options_t *options)
Parse a stream of Ruby source and return the tree.
int lambda_enclosure_nesting
Used to temporarily track the nesting of enclosures to determine if a { is the beginning of a lambda ...
pm_lex_callback_t * lex_callback
This is an optional callback that can be attached to the parser that will be called whenever a new to...
pm_options_version_t version
The version of prism that we should use to parse.
pm_token_t previous
The previous token we were considering.
pm_string_t current_string
This string is used to pass information from the lexer to the parser.
bool parsing_eval
Whether or not we are parsing an eval string.
bool current_regular_expression_ascii_only
True if the current regular expression being lexed contains only ASCII characters.
bool encoding_changed
Whether or not the encoding has been changed by a magic comment.
pm_location_t data_loc
An optional location that represents the location of the END marker and the rest of the content of th...
pm_context_node_t * current_context
The current parsing context.
const uint8_t * start
The pointer to the start of the source.
int enclosure_nesting
Tracks the current nesting of (), [], and {}.
pm_list_t error_list
The list of errors that have been found while parsing.
int8_t frozen_string_literal
Whether or not we have found a frozen_string_literal magic comment with a true or false value.
pm_node_list_t * current_block_exits
When parsing block exits (e.g., break, next, redo), we need to validate that they are in correct cont...
const uint8_t * encoding_comment_start
This pointer indicates where a comment must start if it is to be considered an encoding comment.
pm_token_t current
The current token we're considering.
pm_list_t warning_list
The list of warnings that have been found while parsing.
const uint8_t * heredoc_end
This field indicates the end of a heredoc whose identifier was found on the current line.
PRISM_EXPORTED_FUNCTION void pm_parser_init(pm_parser_t *parser, const uint8_t *source, size_t size, const pm_options_t *options)
Initialize a parser with the given start and end pointers.
int brace_nesting
Used to track the nesting of braces to ensure we get the correct value when we are interpolating bloc...
pm_encoding_changed_callback_t encoding_changed_callback
When the encoding that is being used to parse the source is changed by prism, we provide the ability ...
int32_t start_line
The line number at the start of the parse.
bool encoding_locked
This is very specialized behavior for when you want to parse in a context that does not respect encod...
pm_list_t comment_list
The list of comments that have been found while parsing.
pm_string_t filepath
This is the path of the file being parsed.
pm_scope_t * current_scope
The current local scope.
bool command_start
Whether or not we're at the beginning of a command.
pm_newline_list_t newline_list
This is the list of newline offsets in the source file.
bool semantic_token_seen
Whether or not the parser has seen a token that has semantic meaning (i.e., a token that is not a com...
struct pm_node * right
RangeNode::right.
struct pm_node * left
RangeNode::left.
pm_node_t base
The embedded base node.
pm_integer_t numerator
RationalNode::numerator.
In order to properly set a regular expression's encoding and to validate the byte sequence for the un...
pm_buffer_t regexp_buffer
The buffer holding the regexp source.
pm_token_buffer_t base
The embedded base buffer.
pm_node_t base
The embedded base node.
pm_string_t unescaped
RegularExpressionNode::unescaped.
struct pm_node * rescue_expression
RescueModifierNode::rescue_expression.
struct pm_rescue_node * subsequent
RescueNode::subsequent.
pm_location_t then_keyword_loc
RescueNode::then_keyword_loc.
pm_node_t base
The embedded base node.
struct pm_scope * previous
A pointer to the previous scope in the linked list.
pm_node_list_t implicit_parameters
This is a list of the implicit parameters contained within the block.
pm_shareable_constant_value_t shareable_constant
The current state of constant shareability for this scope.
pm_locals_t locals
The IDs of the locals in the given scope.
pm_scope_parameters_t parameters
This is a bitfield that indicates the parameters that are being used in this scope.
bool closed
A boolean indicating whether or not this scope can see into its parent.
struct pm_node * expression
SplatNode::expression.
struct pm_node_list body
StatementsNode::body.
Certain sets of nodes (hash keys and when clauses) check for duplicate nodes to alert the user of pot...
pm_node_t base
The embedded base node.
pm_string_t unescaped
StringNode::unescaped.
pm_location_t closing_loc
StringNode::closing_loc.
pm_location_t opening_loc
StringNode::opening_loc.
A generic string type that can have various ownership semantics.
const uint8_t * source
A pointer to the start of the string.
size_t length
The length of the string in bytes of memory.
pm_location_t value_loc
SymbolNode::value_loc.
pm_string_t unescaped
SymbolNode::unescaped.
pm_node_t base
The embedded base node.
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.
struct pm_statements_node * statements
UnlessNode::statements.
struct pm_else_node * else_clause
UnlessNode::else_clause.