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) {
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
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
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
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');
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__)
441 pm_parser_err(parser, parser->
current.start, parser->
current.end, diag_id);
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);
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: {
1071 if (vn != NULL)
return vn;
1076 if (vn != NULL)
return vn;
1084 if (vn == NULL)
return NULL;
1085 if (void_node == NULL) void_node = vn;
1088 pm_node_t *vn = pm_check_value_expression(parser, UP(rescue_clause->statements));
1093 if (void_node == NULL) {
1109 case PM_ENSURE_NODE: {
1114 case PM_PARENTHESES_NODE: {
1116 node = UP(cast->
body);
1119 case PM_STATEMENTS_NODE: {
1133 if (void_node == NULL) {
1139 case PM_UNLESS_NODE: {
1148 if (void_node == NULL) {
1154 case PM_ELSE_NODE: {
1169 case PM_LOCAL_VARIABLE_WRITE_NODE: {
1173 for (uint32_t depth = 0; depth < cast->
depth; depth++) scope = scope->
previous;
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);
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: {
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: {
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);
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;
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;
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;
1394 for (
size_t index = 0; index < cast->
elements.
size; index++) {
1396 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE))
return false;
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:
1429 if (pm_conditional_predicate_warn_write_literal_p(node)) {
1448 switch (PM_NODE_TYPE(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);
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: {
1464 if ((cast->
body != NULL) && PM_NODE_TYPE_P(cast->
body, PM_STATEMENTS_NODE)) {
1466 if (statements->body.size == 1) pm_conditional_predicate(parser, statements->body.nodes[0],
type);
1471 case PM_BEGIN_NODE: {
1479 case PM_RANGE_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);
1491 node->
type = PM_FLIP_FLOP_NODE;
1495 case PM_REGULAR_EXPRESSION_NODE:
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:
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:
1547 case PM_CONSTANT_WRITE_NODE:
1550 case PM_GLOBAL_VARIABLE_WRITE_NODE:
1553 case PM_INSTANCE_VARIABLE_WRITE_NODE:
1556 case PM_LOCAL_VARIABLE_WRITE_NODE:
1559 case PM_MULTI_WRITE_NODE:
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);
3966 if (end - point > 1) memset(digits + 1, '0', (size_t) (end - point - 1));
3967 pm_integer_parse(&node->denominator, PM_INTEGER_BASE_DEFAULT, digits, digits + (end - point));
3970 pm_integers_reduce(&node->numerator, &node->denominator);
3978static pm_imaginary_node_t *
3979pm_float_node_rational_imaginary_create(pm_parser_t *parser, const pm_token_t *token) {
3980 assert(token->type == PM_TOKEN_FLOAT_RATIONAL_IMAGINARY);
3982 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
3983 *node = (pm_imaginary_node_t) {
3984 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
3985 .numeric = UP(pm_float_node_rational_create(parser, &((pm_token_t) {
3986 .type = PM_TOKEN_FLOAT_RATIONAL,
3987 .start = token->start,
3988 .end = token->end - 1
3998static pm_for_node_t *
4000 pm_parser_t *parser,
4002 pm_node_t *collection,
4003 pm_statements_node_t *statements,
4004 const pm_token_t *for_keyword,
4005 const pm_token_t *in_keyword,
4006 const pm_token_t *do_keyword,
4007 const pm_token_t *end_keyword
4009 pm_for_node_t *node = PM_NODE_ALLOC(parser, pm_for_node_t);
4011 *node = (pm_for_node_t) {
4012 .base = PM_NODE_INIT_TOKENS(parser, PM_FOR_NODE, 0, for_keyword, end_keyword),
4014 .collection = collection,
4015 .statements = statements,
4016 .for_keyword_loc = PM_LOCATION_TOKEN_VALUE(for_keyword),
4017 .in_keyword_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4018 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
4019 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
4028static pm_forwarding_arguments_node_t *
4029pm_forwarding_arguments_node_create(pm_parser_t *parser, const pm_token_t *token) {
4030 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4031 pm_forwarding_arguments_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_arguments_node_t);
4033 *node = (pm_forwarding_arguments_node_t) {
4034 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_ARGUMENTS_NODE, 0, token)
4043static pm_forwarding_parameter_node_t *
4044pm_forwarding_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
4045 assert(token->type == PM_TOKEN_UDOT_DOT_DOT);
4046 pm_forwarding_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_parameter_node_t);
4048 *node = (pm_forwarding_parameter_node_t) {
4049 .base = PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_PARAMETER_NODE, 0, token)
4058static pm_forwarding_super_node_t *
4059pm_forwarding_super_node_create(pm_parser_t *parser, const pm_token_t *token, pm_arguments_t *arguments) {
4060 assert(arguments->block == NULL || PM_NODE_TYPE_P(arguments->block, PM_BLOCK_NODE));
4061 assert(token->type == PM_TOKEN_KEYWORD_SUPER);
4062 pm_forwarding_super_node_t *node = PM_NODE_ALLOC(parser, pm_forwarding_super_node_t);
4064 pm_block_node_t *block = NULL;
4065 if (arguments->block != NULL) {
4066 block = (pm_block_node_t *) arguments->block;
4069 *node = (pm_forwarding_super_node_t) {
4072 ? PM_NODE_INIT_TOKEN(parser, PM_FORWARDING_SUPER_NODE, 0, token)
4073 : PM_NODE_INIT_TOKEN_NODE(parser, PM_FORWARDING_SUPER_NODE, 0, token, block)
4085static pm_hash_pattern_node_t *
4086pm_hash_pattern_node_empty_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4087 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4089 *node = (pm_hash_pattern_node_t) {
4090 .base = PM_NODE_INIT_TOKENS(parser, PM_HASH_PATTERN_NODE, 0, opening, closing),
4092 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4093 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
4104static pm_hash_pattern_node_t *
4105pm_hash_pattern_node_node_list_create(pm_parser_t *parser, pm_node_list_t *elements, pm_node_t *rest) {
4106 pm_hash_pattern_node_t *node = PM_NODE_ALLOC(parser, pm_hash_pattern_node_t);
4108 const uint8_t *start;
4111 if (elements->size > 0) {
4113 start = MIN(rest->location.start, elements->nodes[0]->location.start);
4114 end = MAX(rest->location.end, elements->nodes[elements->size - 1]->location.end);
4116 start = elements->nodes[0]->location.start;
4117 end = elements->nodes[elements->size - 1]->location.end;
4120 assert(rest != NULL);
4121 start = rest->location.start;
4122 end = rest->location.end;
4125 *node = (pm_hash_pattern_node_t) {
4126 .base = PM_NODE_INIT(parser, PM_HASH_PATTERN_NODE, 0, start, end),
4130 .opening_loc = { 0 },
4131 .closing_loc = { 0 }
4134 pm_node_list_concat(&node->elements, elements);
4141static pm_constant_id_t
4142pm_global_variable_write_name(pm_parser_t *parser, const pm_node_t *target) {
4143 switch (PM_NODE_TYPE(target)) {
4144 case PM_GLOBAL_VARIABLE_READ_NODE:
4145 return ((pm_global_variable_read_node_t *) target)->name;
4146 case PM_BACK_REFERENCE_READ_NODE:
4147 return ((pm_back_reference_read_node_t *) target)->name;
4148 case PM_NUMBERED_REFERENCE_READ_NODE:
4149 // This will only ever happen in the event of a syntax error, but we
4150 // still need to provide something for the node.
4151 return pm_parser_constant_id_location(parser, target->location.start, target->location.end);
4153 assert(false && "unreachable");
4154 return (pm_constant_id_t) -1;
4161static pm_global_variable_and_write_node_t *
4162pm_global_variable_and_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4163 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4164 pm_global_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_and_write_node_t);
4166 *node = (pm_global_variable_and_write_node_t) {
4167 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
4168 .name = pm_global_variable_write_name(parser, target),
4169 .name_loc = target->location,
4170 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4180static pm_global_variable_operator_write_node_t *
4181pm_global_variable_operator_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4182 pm_global_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_operator_write_node_t);
4184 *node = (pm_global_variable_operator_write_node_t) {
4185 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4186 .name = pm_global_variable_write_name(parser, target),
4187 .name_loc = target->location,
4188 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4190 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4199static pm_global_variable_or_write_node_t *
4200pm_global_variable_or_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4201 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4202 pm_global_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_or_write_node_t);
4204 *node = (pm_global_variable_or_write_node_t) {
4205 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
4206 .name = pm_global_variable_write_name(parser, target),
4207 .name_loc = target->location,
4208 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4218static pm_global_variable_read_node_t *
4219pm_global_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4220 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4222 *node = (pm_global_variable_read_node_t) {
4223 .base = PM_NODE_INIT_TOKEN(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0, name),
4224 .name = pm_parser_constant_id_token(parser, name)
4233static pm_global_variable_read_node_t *
4234pm_global_variable_read_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name) {
4235 pm_global_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_read_node_t);
4237 *node = (pm_global_variable_read_node_t) {
4238 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_READ_NODE, 0),
4248static pm_global_variable_write_node_t *
4249pm_global_variable_write_node_create(pm_parser_t *parser, pm_node_t *target, const pm_token_t *operator, pm_node_t *value) {
4250 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4251 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4253 *node = (pm_global_variable_write_node_t) {
4254 .base = PM_NODE_INIT_NODES(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, flags, target, value),
4255 .name = pm_global_variable_write_name(parser, target),
4256 .name_loc = PM_LOCATION_NODE_VALUE(target),
4257 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4267static pm_global_variable_write_node_t *
4268pm_global_variable_write_node_synthesized_create(pm_parser_t *parser, pm_constant_id_t name, pm_node_t *value) {
4269 pm_global_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_global_variable_write_node_t);
4271 *node = (pm_global_variable_write_node_t) {
4272 .base = PM_NODE_INIT_BASE(parser, PM_GLOBAL_VARIABLE_WRITE_NODE, 0),
4274 .name_loc = PM_LOCATION_NULL_VALUE(parser),
4275 .operator_loc = PM_LOCATION_NULL_VALUE(parser),
4285static pm_hash_node_t *
4286pm_hash_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4287 assert(opening != NULL);
4288 pm_hash_node_t *node = PM_NODE_ALLOC(parser, pm_hash_node_t);
4290 *node = (pm_hash_node_t) {
4291 .base = PM_NODE_INIT_TOKEN(parser, PM_HASH_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4292 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4293 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
4304pm_hash_node_elements_append(pm_hash_node_t *hash, pm_node_t *element) {
4305 pm_node_list_append(&hash->elements, element);
4307 bool static_literal = PM_NODE_TYPE_P(element, PM_ASSOC_NODE);
4308 if (static_literal) {
4309 pm_assoc_node_t *assoc = (pm_assoc_node_t *) element;
4310 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);
4311 static_literal = static_literal && PM_NODE_FLAG_P(assoc->key, PM_NODE_FLAG_STATIC_LITERAL);
4312 static_literal = static_literal && PM_NODE_FLAG_P(assoc, PM_NODE_FLAG_STATIC_LITERAL);
4315 if (!static_literal) {
4316 pm_node_flag_unset(UP(hash), PM_NODE_FLAG_STATIC_LITERAL);
4321pm_hash_node_closing_loc_set(pm_hash_node_t *hash, pm_token_t *token) {
4322 hash->base.location.end = token->end;
4323 hash->closing_loc = PM_LOCATION_TOKEN_VALUE(token);
4329static pm_if_node_t *
4330pm_if_node_create(pm_parser_t *parser,
4331 const pm_token_t *if_keyword,
4332 pm_node_t *predicate,
4333 const pm_token_t *then_keyword,
4334 pm_statements_node_t *statements,
4335 pm_node_t *subsequent,
4336 const pm_token_t *end_keyword
4338 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4339 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4342 if (end_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4343 end = end_keyword->end;
4344 } else if (subsequent != NULL) {
4345 end = subsequent->location.end;
4346 } else if (pm_statements_node_body_length(statements) != 0) {
4347 end = statements->base.location.end;
4349 end = predicate->location.end;
4352 *node = (pm_if_node_t) {
4353 .base = PM_NODE_INIT(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, if_keyword->start, end),
4354 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4355 .predicate = predicate,
4356 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
4357 .statements = statements,
4358 .subsequent = subsequent,
4359 .end_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(end_keyword)
4368static pm_if_node_t *
4369pm_if_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *if_keyword, pm_node_t *predicate) {
4370 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4371 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4373 pm_statements_node_t *statements = pm_statements_node_create(parser);
4374 pm_statements_node_body_append(parser, statements, statement, true);
4376 *node = (pm_if_node_t) {
4377 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
4378 .if_keyword_loc = PM_LOCATION_TOKEN_VALUE(if_keyword),
4379 .predicate = predicate,
4380 .then_keyword_loc = { 0 },
4381 .statements = statements,
4383 .end_keyword_loc = { 0 }
4392static pm_if_node_t *
4393pm_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) {
4394 pm_assert_value_expression(parser, predicate);
4395 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
4397 pm_statements_node_t *if_statements = pm_statements_node_create(parser);
4398 pm_statements_node_body_append(parser, if_statements, true_expression, true);
4400 pm_statements_node_t *else_statements = pm_statements_node_create(parser);
4401 pm_statements_node_body_append(parser, else_statements, false_expression, true);
4403 pm_token_t end_keyword = not_provided(parser);
4404 pm_else_node_t *else_node = pm_else_node_create(parser, colon, else_statements, &end_keyword);
4406 pm_if_node_t *node = PM_NODE_ALLOC(parser, pm_if_node_t);
4408 *node = (pm_if_node_t) {
4409 .base = PM_NODE_INIT_NODES(parser, PM_IF_NODE, PM_NODE_FLAG_NEWLINE, predicate, false_expression),
4410 .if_keyword_loc = { 0 },
4411 .predicate = predicate,
4412 .then_keyword_loc = PM_LOCATION_TOKEN_VALUE(qmark),
4413 .statements = if_statements,
4414 .subsequent = UP(else_node),
4415 .end_keyword_loc = { 0 }
4423pm_if_node_end_keyword_loc_set(pm_if_node_t *node, const pm_token_t *keyword) {
4424 node->base.location.end = keyword->end;
4425 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4429pm_else_node_end_keyword_loc_set(pm_else_node_t *node, const pm_token_t *keyword) {
4430 node->base.location.end = keyword->end;
4431 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword);
4437static pm_implicit_node_t *
4438pm_implicit_node_create(pm_parser_t *parser, pm_node_t *value) {
4439 pm_implicit_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_node_t);
4441 *node = (pm_implicit_node_t) {
4442 .base = PM_NODE_INIT_NODE(parser, PM_IMPLICIT_NODE, 0, value),
4452static pm_implicit_rest_node_t *
4453pm_implicit_rest_node_create(pm_parser_t *parser, const pm_token_t *token) {
4454 assert(token->type == PM_TOKEN_COMMA);
4456 pm_implicit_rest_node_t *node = PM_NODE_ALLOC(parser, pm_implicit_rest_node_t);
4458 *node = (pm_implicit_rest_node_t) {
4459 .base = PM_NODE_INIT_TOKEN(parser, PM_IMPLICIT_REST_NODE, 0, token)
4468static pm_integer_node_t *
4469pm_integer_node_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4470 assert(token->type == PM_TOKEN_INTEGER);
4471 pm_integer_node_t *node = PM_NODE_ALLOC(parser, pm_integer_node_t);
4473 *node = (pm_integer_node_t) {
4474 .base = PM_NODE_INIT_TOKEN(parser, PM_INTEGER_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4478 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4480 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4481 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4482 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4483 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4484 default: assert(false && "unreachable"); break;
4487 pm_integer_parse(&node->value, integer_base, token->start, token->end);
4495static pm_imaginary_node_t *
4496pm_integer_node_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4497 assert(token->type == PM_TOKEN_INTEGER_IMAGINARY);
4499 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4500 *node = (pm_imaginary_node_t) {
4501 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4502 .numeric = UP(pm_integer_node_create(parser, base, &((pm_token_t) {
4503 .type = PM_TOKEN_INTEGER,
4504 .start = token->start,
4505 .end = token->end - 1
4516static pm_rational_node_t *
4517pm_integer_node_rational_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4518 assert(token->type == PM_TOKEN_INTEGER_RATIONAL);
4520 pm_rational_node_t *node = PM_NODE_ALLOC(parser, pm_rational_node_t);
4521 *node = (pm_rational_node_t) {
4522 .base = PM_NODE_INIT_TOKEN(parser, PM_RATIONAL_NODE, base | PM_NODE_FLAG_STATIC_LITERAL, token),
4524 .denominator = { .value = 1, 0 }
4527 pm_integer_base_t integer_base = PM_INTEGER_BASE_DECIMAL;
4529 case PM_INTEGER_BASE_FLAGS_BINARY: integer_base = PM_INTEGER_BASE_BINARY; break;
4530 case PM_INTEGER_BASE_FLAGS_OCTAL: integer_base = PM_INTEGER_BASE_OCTAL; break;
4531 case PM_INTEGER_BASE_FLAGS_DECIMAL: break;
4532 case PM_INTEGER_BASE_FLAGS_HEXADECIMAL: integer_base = PM_INTEGER_BASE_HEXADECIMAL; break;
4533 default: assert(false && "unreachable"); break;
4536 pm_integer_parse(&node->numerator, integer_base, token->start, token->end - 1);
4545static pm_imaginary_node_t *
4546pm_integer_node_rational_imaginary_create(pm_parser_t *parser, pm_node_flags_t base, const pm_token_t *token) {
4547 assert(token->type == PM_TOKEN_INTEGER_RATIONAL_IMAGINARY);
4549 pm_imaginary_node_t *node = PM_NODE_ALLOC(parser, pm_imaginary_node_t);
4550 *node = (pm_imaginary_node_t) {
4551 .base = PM_NODE_INIT_TOKEN(parser, PM_IMAGINARY_NODE, PM_NODE_FLAG_STATIC_LITERAL, token),
4552 .numeric = UP(pm_integer_node_rational_create(parser, base, &((pm_token_t) {
4553 .type = PM_TOKEN_INTEGER_RATIONAL,
4554 .start = token->start,
4555 .end = token->end - 1
4565static pm_in_node_t *
4566pm_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) {
4567 pm_in_node_t *node = PM_NODE_ALLOC(parser, pm_in_node_t);
4570 if (statements != NULL) {
4571 end = statements->base.location.end;
4572 } else if (then_keyword->type != PM_TOKEN_NOT_PROVIDED) {
4573 end = then_keyword->end;
4575 end = pattern->location.end;
4578 *node = (pm_in_node_t) {
4579 .base = PM_NODE_INIT(parser, PM_IN_NODE, 0, in_keyword->start, end),
4581 .statements = statements,
4582 .in_loc = PM_LOCATION_TOKEN_VALUE(in_keyword),
4583 .then_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword)
4592static pm_instance_variable_and_write_node_t *
4593pm_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) {
4594 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
4595 pm_instance_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_and_write_node_t);
4597 *node = (pm_instance_variable_and_write_node_t) {
4598 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_AND_WRITE_NODE, 0, target, value),
4599 .name = target->name,
4600 .name_loc = target->base.location,
4601 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4611static pm_instance_variable_operator_write_node_t *
4612pm_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) {
4613 pm_instance_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_operator_write_node_t);
4615 *node = (pm_instance_variable_operator_write_node_t) {
4616 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
4617 .name = target->name,
4618 .name_loc = target->base.location,
4619 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4621 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1)
4630static pm_instance_variable_or_write_node_t *
4631pm_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) {
4632 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
4633 pm_instance_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_or_write_node_t);
4635 *node = (pm_instance_variable_or_write_node_t) {
4636 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_OR_WRITE_NODE, 0, target, value),
4637 .name = target->name,
4638 .name_loc = target->base.location,
4639 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
4649static pm_instance_variable_read_node_t *
4650pm_instance_variable_read_node_create(pm_parser_t *parser, const pm_token_t *token) {
4651 assert(token->type == PM_TOKEN_INSTANCE_VARIABLE);
4652 pm_instance_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_read_node_t);
4654 *node = (pm_instance_variable_read_node_t) {
4655 .base = PM_NODE_INIT_TOKEN(parser, PM_INSTANCE_VARIABLE_READ_NODE, 0, token),
4656 .name = pm_parser_constant_id_token(parser, token)
4666static pm_instance_variable_write_node_t *
4667pm_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) {
4668 pm_instance_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_instance_variable_write_node_t);
4669 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
4671 *node = (pm_instance_variable_write_node_t) {
4672 .base = PM_NODE_INIT_NODES(parser, PM_INSTANCE_VARIABLE_WRITE_NODE, flags, read_node, value),
4673 .name = read_node->name,
4674 .name_loc = PM_LOCATION_NODE_VALUE(read_node),
4675 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator),
4688pm_interpolated_node_append(pm_node_t *node, pm_node_list_t *parts, pm_node_t *part) {
4689 switch (PM_NODE_TYPE(part)) {
4690 case PM_STRING_NODE:
4691 pm_node_flag_set(part, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4693 case PM_EMBEDDED_STATEMENTS_NODE: {
4694 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4695 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4697 if (embedded == NULL) {
4698 // If there are no statements or more than one statement, then
4699 // we lose the static literal flag.
4700 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4701 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4702 // If the embedded statement is a string, then we can keep the
4703 // static literal flag and mark the string as frozen.
4704 pm_node_flag_set(embedded, PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN);
4705 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4706 // If the embedded statement is an interpolated string and it's
4707 // a static literal, then we can keep the static literal flag.
4709 // Otherwise we lose the static literal flag.
4710 pm_node_flag_unset(node, PM_NODE_FLAG_STATIC_LITERAL);
4715 case PM_EMBEDDED_VARIABLE_NODE:
4716 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4719 assert(false && "unexpected node type");
4723 pm_node_list_append(parts, part);
4729static pm_interpolated_regular_expression_node_t *
4730pm_interpolated_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening) {
4731 pm_interpolated_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_regular_expression_node_t);
4733 *node = (pm_interpolated_regular_expression_node_t) {
4734 .base = PM_NODE_INIT_TOKEN(parser, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening),
4735 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
4736 .closing_loc = PM_LOCATION_TOKEN_VALUE(opening),
4744pm_interpolated_regular_expression_node_append(pm_interpolated_regular_expression_node_t *node, pm_node_t *part) {
4745 if (node->base.location.start > part->location.start) {
4746 node->base.location.start = part->location.start;
4748 if (node->base.location.end < part->location.end) {
4749 node->base.location.end = part->location.end;
4752 pm_interpolated_node_append(UP(node), &node->parts, part);
4756pm_interpolated_regular_expression_node_closing_set(pm_parser_t *parser, pm_interpolated_regular_expression_node_t *node, const pm_token_t *closing) {
4757 node->closing_loc = PM_LOCATION_TOKEN_VALUE(closing);
4758 node->base.location.end = closing->end;
4759 pm_node_flag_set(UP(node), pm_regular_expression_flags_create(parser, closing));
4786pm_interpolated_string_node_append(pm_interpolated_string_node_t *node, pm_node_t *part) {
4787#define CLEAR_FLAGS(node) \
4788 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))
4790#define MUTABLE_FLAGS(node) \
4791 node->base.flags = (pm_node_flags_t) ((FL(node) | PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE) & ~PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN);
4793 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4794 node->base.location.start = part->location.start;
4797 node->base.location.end = MAX(node->base.location.end, part->location.end);
4799 switch (PM_NODE_TYPE(part)) {
4800 case PM_STRING_NODE:
4801 // If inner string is not frozen, it stops being a static literal. We should *not* clear other flags,
4802 // because concatenating two frozen strings (`'foo' 'bar'`) is still frozen. This holds true for
4803 // as long as this interpolation only consists of other string literals.
4804 if (!PM_NODE_FLAG_P(part, PM_STRING_FLAGS_FROZEN)) {
4805 pm_node_flag_unset(UP(node), PM_NODE_FLAG_STATIC_LITERAL);
4807 part->flags = (pm_node_flags_t) ((part->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4809 case PM_INTERPOLATED_STRING_NODE:
4810 if (PM_NODE_FLAG_P(part, PM_NODE_FLAG_STATIC_LITERAL)) {
4811 // If the string that we're concatenating is a static literal,
4812 // then we can keep the static literal flag for this string.
4814 // Otherwise, we lose the static literal flag here and we should
4815 // also clear the mutability flags.
4819 case PM_EMBEDDED_STATEMENTS_NODE: {
4820 pm_embedded_statements_node_t *cast = (pm_embedded_statements_node_t *) part;
4821 pm_node_t *embedded = (cast->statements != NULL && cast->statements->body.size == 1) ? cast->statements->body.nodes[0] : NULL;
4823 if (embedded == NULL) {
4824 // If we're embedding multiple statements or no statements, then
4825 // the string is not longer a static literal.
4827 } else if (PM_NODE_TYPE_P(embedded, PM_STRING_NODE)) {
4828 // If the embedded statement is a string, then we can make that
4829 // string as frozen and static literal, and not touch the static
4830 // literal status of this string.
4831 embedded->flags = (pm_node_flags_t) ((embedded->flags | PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN) & ~PM_STRING_FLAGS_MUTABLE);
4833 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4834 MUTABLE_FLAGS(node);
4836 } else if (PM_NODE_TYPE_P(embedded, PM_INTERPOLATED_STRING_NODE) && PM_NODE_FLAG_P(embedded, PM_NODE_FLAG_STATIC_LITERAL)) {
4837 // If the embedded statement is an interpolated string, but that
4838 // string is marked as static literal, then we can keep our
4839 // static literal status for this string.
4840 if (PM_NODE_FLAG_P(node, PM_NODE_FLAG_STATIC_LITERAL)) {
4841 MUTABLE_FLAGS(node);
4844 // In all other cases, we lose the static literal flag here and
4851 case PM_EMBEDDED_VARIABLE_NODE:
4852 // Embedded variables clear static literal, which means we also
4853 // should clear the mutability flags.
4856 case PM_X_STRING_NODE:
4857 case PM_INTERPOLATED_X_STRING_NODE:
4858 case PM_SYMBOL_NODE:
4859 case PM_INTERPOLATED_SYMBOL_NODE:
4860 // These will only happen in error cases. But we want to handle it
4861 // here so that we don't fail the assertion.
4865 assert(false && "unexpected node type");
4869 pm_node_list_append(&node->parts, part);
4878static pm_interpolated_string_node_t *
4879pm_interpolated_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4880 pm_interpolated_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_string_node_t);
4881 pm_node_flags_t flags = PM_NODE_FLAG_STATIC_LITERAL;
4883 switch (parser->frozen_string_literal) {
4884 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
4885 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_MUTABLE;
4887 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
4888 flags |= PM_INTERPOLATED_STRING_NODE_FLAGS_FROZEN;
4892 *node = (pm_interpolated_string_node_t) {
4893 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_STRING_NODE, flags, opening, closing),
4894 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4895 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4899 if (parts != NULL) {
4901 PM_NODE_LIST_FOREACH(parts, index, part) {
4902 pm_interpolated_string_node_append(node, part);
4913pm_interpolated_string_node_closing_set(pm_interpolated_string_node_t *node, const pm_token_t *closing) {
4914 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4915 node->base.location.end = closing->end;
4919pm_interpolated_symbol_node_append(pm_interpolated_symbol_node_t *node, pm_node_t *part) {
4920 if (node->parts.size == 0 && node->opening_loc.start == NULL) {
4921 node->base.location.start = part->location.start;
4924 pm_interpolated_node_append(UP(node), &node->parts, part);
4925 node->base.location.end = MAX(node->base.location.end, part->location.end);
4929pm_interpolated_symbol_node_closing_loc_set(pm_interpolated_symbol_node_t *node, const pm_token_t *closing) {
4930 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4931 node->base.location.end = closing->end;
4937static pm_interpolated_symbol_node_t *
4938pm_interpolated_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_node_list_t *parts, const pm_token_t *closing) {
4939 pm_interpolated_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_symbol_node_t);
4941 *node = (pm_interpolated_symbol_node_t) {
4942 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
4943 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4944 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4948 if (parts != NULL) {
4950 PM_NODE_LIST_FOREACH(parts, index, part) {
4951 pm_interpolated_symbol_node_append(node, part);
4961static pm_interpolated_x_string_node_t *
4962pm_interpolated_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
4963 pm_interpolated_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_interpolated_x_string_node_t);
4965 *node = (pm_interpolated_x_string_node_t) {
4966 .base = PM_NODE_INIT_TOKENS(parser, PM_INTERPOLATED_X_STRING_NODE, 0, opening, closing),
4967 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
4968 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
4976pm_interpolated_xstring_node_append(pm_interpolated_x_string_node_t *node, pm_node_t *part) {
4977 pm_interpolated_node_append(UP(node), &node->parts, part);
4978 node->base.location.end = part->location.end;
4982pm_interpolated_xstring_node_closing_set(pm_interpolated_x_string_node_t *node, const pm_token_t *closing) {
4983 node->closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing);
4984 node->base.location.end = closing->end;
4990static pm_it_local_variable_read_node_t *
4991pm_it_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
4992 pm_it_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_it_local_variable_read_node_t);
4994 *node = (pm_it_local_variable_read_node_t) {
4995 .base = PM_NODE_INIT_TOKEN(parser, PM_IT_LOCAL_VARIABLE_READ_NODE, 0, name),
5004static pm_it_parameters_node_t *
5005pm_it_parameters_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *closing) {
5006 pm_it_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_it_parameters_node_t);
5008 *node = (pm_it_parameters_node_t) {
5009 .base = PM_NODE_INIT_TOKENS(parser, PM_IT_PARAMETERS_NODE, 0, opening, closing),
5018static pm_keyword_hash_node_t *
5019pm_keyword_hash_node_create(pm_parser_t *parser) {
5020 pm_keyword_hash_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_hash_node_t);
5022 *node = (pm_keyword_hash_node_t) {
5023 .base = PM_NODE_INIT_UNSET(parser, PM_KEYWORD_HASH_NODE, PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS),
5034pm_keyword_hash_node_elements_append(pm_keyword_hash_node_t *hash, pm_node_t *element) {
5035 // If the element being added is not an AssocNode or does not have a symbol
5036 // key, then we want to turn the SYMBOL_KEYS flag off.
5037 if (!PM_NODE_TYPE_P(element, PM_ASSOC_NODE) || !PM_NODE_TYPE_P(((pm_assoc_node_t *) element)->key, PM_SYMBOL_NODE)) {
5038 pm_node_flag_unset(UP(hash), PM_KEYWORD_HASH_NODE_FLAGS_SYMBOL_KEYS);
5041 pm_node_list_append(&hash->elements, element);
5042 if (hash->base.location.start == NULL) {
5043 hash->base.location.start = element->location.start;
5045 hash->base.location.end = element->location.end;
5051static pm_required_keyword_parameter_node_t *
5052pm_required_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name) {
5053 pm_required_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_keyword_parameter_node_t);
5055 *node = (pm_required_keyword_parameter_node_t) {
5056 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_KEYWORD_PARAMETER_NODE, 0, name),
5057 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5058 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5067static pm_optional_keyword_parameter_node_t *
5068pm_optional_keyword_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, pm_node_t *value) {
5069 pm_optional_keyword_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_keyword_parameter_node_t);
5071 *node = (pm_optional_keyword_parameter_node_t) {
5072 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_KEYWORD_PARAMETER_NODE, 0, name, value),
5073 .name = pm_parser_constant_id_location(parser, name->start, name->end - 1),
5074 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5084static pm_keyword_rest_parameter_node_t *
5085pm_keyword_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
5086 pm_keyword_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_keyword_rest_parameter_node_t);
5088 *node = (pm_keyword_rest_parameter_node_t) {
5090 (name->type == PM_TOKEN_NOT_PROVIDED)
5091 ? PM_NODE_INIT_TOKEN(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator)
5092 : PM_NODE_INIT_TOKENS(parser, PM_KEYWORD_REST_PARAMETER_NODE, 0, operator, name)
5094 .name = pm_parser_optional_constant_id_token(parser, name),
5095 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
5096 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5105static pm_lambda_node_t *
5106pm_lambda_node_create(
5107 pm_parser_t *parser,
5108 pm_constant_id_list_t *locals,
5109 const pm_token_t *operator,
5110 const pm_token_t *opening,
5111 const pm_token_t *closing,
5112 pm_node_t *parameters,
5115 pm_lambda_node_t *node = PM_NODE_ALLOC(parser, pm_lambda_node_t);
5117 *node = (pm_lambda_node_t) {
5118 .base = PM_NODE_INIT_TOKENS(parser, PM_LAMBDA_NODE, 0, operator, closing),
5120 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5121 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5122 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5123 .parameters = parameters,
5133static pm_local_variable_and_write_node_t *
5134pm_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) {
5135 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));
5136 assert(operator->type == PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
5137 pm_local_variable_and_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_and_write_node_t);
5139 *node = (pm_local_variable_and_write_node_t) {
5140 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_AND_WRITE_NODE, 0, target, value),
5141 .name_loc = target->location,
5142 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5154static pm_local_variable_operator_write_node_t *
5155pm_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) {
5156 pm_local_variable_operator_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_operator_write_node_t);
5158 *node = (pm_local_variable_operator_write_node_t) {
5159 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OPERATOR_WRITE_NODE, 0, target, value),
5160 .name_loc = target->location,
5161 .binary_operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5164 .binary_operator = pm_parser_constant_id_location(parser, operator->start, operator->end - 1),
5174static pm_local_variable_or_write_node_t *
5175pm_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) {
5176 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));
5177 assert(operator->type == PM_TOKEN_PIPE_PIPE_EQUAL);
5178 pm_local_variable_or_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_or_write_node_t);
5180 *node = (pm_local_variable_or_write_node_t) {
5181 .base = PM_NODE_INIT_NODES(parser, PM_LOCAL_VARIABLE_OR_WRITE_NODE, 0, target, value),
5182 .name_loc = target->location,
5183 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5195static pm_local_variable_read_node_t *
5196pm_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) {
5197 if (!missing) pm_locals_read(&pm_parser_scope_find(parser, depth)->locals, name_id);
5199 pm_local_variable_read_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_read_node_t);
5201 *node = (pm_local_variable_read_node_t) {
5202 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_READ_NODE, 0, name),
5213static pm_local_variable_read_node_t *
5214pm_local_variable_read_node_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5215 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5216 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, false);
5223static pm_local_variable_read_node_t *
5224pm_local_variable_read_node_missing_create(pm_parser_t *parser, const pm_token_t *name, uint32_t depth) {
5225 pm_constant_id_t name_id = pm_parser_constant_id_token(parser, name);
5226 return pm_local_variable_read_node_create_constant_id(parser, name, name_id, depth, true);
5232static pm_local_variable_write_node_t *
5233pm_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) {
5234 pm_local_variable_write_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_write_node_t);
5235 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5237 *node = (pm_local_variable_write_node_t) {
5238 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_LOCAL_VARIABLE_WRITE_NODE, flags, name_loc, value),
5242 .name_loc = *name_loc,
5243 .operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator)
5253pm_token_is_it(const uint8_t *start, const uint8_t *end) {
5254 return (end - start == 2) && (start[0] == 'i') && (start[1] == 't');
5262pm_token_is_numbered_parameter(const uint8_t *start, const uint8_t *end) {
5263 return (end - start == 2) && (start[0] == '_') && (start[1] != '0') && (pm_char_is_decimal_digit(start[1]));
5271pm_refute_numbered_parameter(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
5272 if (pm_token_is_numbered_parameter(start, end)) {
5273 PM_PARSER_ERR_FORMAT(parser, start, end, PM_ERR_PARAMETER_NUMBERED_RESERVED, start);
5281static pm_local_variable_target_node_t *
5282pm_local_variable_target_node_create(pm_parser_t *parser, const pm_location_t *location, pm_constant_id_t name, uint32_t depth) {
5283 pm_refute_numbered_parameter(parser, location->start, location->end);
5284 pm_local_variable_target_node_t *node = PM_NODE_ALLOC(parser, pm_local_variable_target_node_t);
5286 *node = (pm_local_variable_target_node_t) {
5287 .base = PM_NODE_INIT_TOKEN(parser, PM_LOCAL_VARIABLE_TARGET_NODE, 0, location),
5298static pm_match_predicate_node_t *
5299pm_match_predicate_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5300 pm_assert_value_expression(parser, value);
5302 pm_match_predicate_node_t *node = PM_NODE_ALLOC(parser, pm_match_predicate_node_t);
5304 *node = (pm_match_predicate_node_t) {
5305 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_PREDICATE_NODE, 0, value, pattern),
5308 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5317static pm_match_required_node_t *
5318pm_match_required_node_create(pm_parser_t *parser, pm_node_t *value, pm_node_t *pattern, const pm_token_t *operator) {
5319 pm_assert_value_expression(parser, value);
5321 pm_match_required_node_t *node = PM_NODE_ALLOC(parser, pm_match_required_node_t);
5323 *node = (pm_match_required_node_t) {
5324 .base = PM_NODE_INIT_NODES(parser, PM_MATCH_REQUIRED_NODE, 0, value, pattern),
5327 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5336static pm_match_write_node_t *
5337pm_match_write_node_create(pm_parser_t *parser, pm_call_node_t *call) {
5338 pm_match_write_node_t *node = PM_NODE_ALLOC(parser, pm_match_write_node_t);
5340 *node = (pm_match_write_node_t) {
5341 .base = PM_NODE_INIT_NODE(parser, PM_MATCH_WRITE_NODE, 0, call),
5352static pm_module_node_t *
5353pm_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) {
5354 pm_module_node_t *node = PM_NODE_ALLOC(parser, pm_module_node_t);
5356 *node = (pm_module_node_t) {
5357 .base = PM_NODE_INIT_TOKENS(parser, PM_MODULE_NODE, 0, module_keyword, end_keyword),
5358 .locals = (locals == NULL ? ((pm_constant_id_list_t) { .ids = NULL, .size = 0, .capacity = 0 }) : *locals),
5359 .module_keyword_loc = PM_LOCATION_TOKEN_VALUE(module_keyword),
5360 .constant_path = constant_path,
5362 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword),
5363 .name = pm_parser_constant_id_token(parser, name)
5372static pm_multi_target_node_t *
5373pm_multi_target_node_create(pm_parser_t *parser) {
5374 pm_multi_target_node_t *node = PM_NODE_ALLOC(parser, pm_multi_target_node_t);
5376 *node = (pm_multi_target_node_t) {
5377 .base = PM_NODE_INIT_UNSET(parser, PM_MULTI_TARGET_NODE, 0),
5381 .lparen_loc = { 0 },
5392pm_multi_target_node_targets_append(pm_parser_t *parser, pm_multi_target_node_t *node, pm_node_t *target) {
5393 if (PM_NODE_TYPE_P(target, PM_SPLAT_NODE)) {
5394 if (node->rest == NULL) {
5395 node->rest = target;
5397 pm_parser_err_node(parser, target, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
5398 pm_node_list_append(&node->rights, target);
5400 } else if (PM_NODE_TYPE_P(target, PM_IMPLICIT_REST_NODE)) {
5401 if (node->rest == NULL) {
5402 node->rest = target;
5404 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->current, PM_ERR_MULTI_ASSIGN_UNEXPECTED_REST);
5405 pm_node_list_append(&node->rights, target);
5407 } else if (node->rest == NULL) {
5408 pm_node_list_append(&node->lefts, target);
5410 pm_node_list_append(&node->rights, target);
5413 if (node->base.location.start == NULL || (node->base.location.start > target->location.start)) {
5414 node->base.location.start = target->location.start;
5417 if (node->base.location.end == NULL || (node->base.location.end < target->location.end)) {
5418 node->base.location.end = target->location.end;
5426pm_multi_target_node_opening_set(pm_multi_target_node_t *node, const pm_token_t *lparen) {
5427 node->base.location.start = lparen->start;
5428 node->lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen);
5435pm_multi_target_node_closing_set(pm_multi_target_node_t *node, const pm_token_t *rparen) {
5436 node->base.location.end = rparen->end;
5437 node->rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen);
5443static pm_multi_write_node_t *
5444pm_multi_write_node_create(pm_parser_t *parser, pm_multi_target_node_t *target, const pm_token_t *operator, pm_node_t *value) {
5445 pm_multi_write_node_t *node = PM_NODE_ALLOC(parser, pm_multi_write_node_t);
5446 pm_node_flags_t flags = pm_implicit_array_write_flags(value, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY);
5448 *node = (pm_multi_write_node_t) {
5449 .base = PM_NODE_INIT_NODES(parser, PM_MULTI_WRITE_NODE, flags, target, value),
5450 .lefts = target->lefts,
5451 .rest = target->rest,
5452 .rights = target->rights,
5453 .lparen_loc = target->lparen_loc,
5454 .rparen_loc = target->rparen_loc,
5455 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5459 // Explicitly do not call pm_node_destroy here because we want to keep
5460 // around all of the information within the MultiWriteNode node.
5469static pm_next_node_t *
5470pm_next_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
5471 assert(keyword->type == PM_TOKEN_KEYWORD_NEXT);
5472 pm_next_node_t *node = PM_NODE_ALLOC(parser, pm_next_node_t);
5474 *node = (pm_next_node_t) {
5477 ? PM_NODE_INIT_TOKEN(parser, PM_NEXT_NODE, 0, keyword)
5478 : PM_NODE_INIT_TOKEN_NODE(parser, PM_NEXT_NODE, 0, keyword, arguments)
5480 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5481 .arguments = arguments
5490static pm_nil_node_t *
5491pm_nil_node_create(pm_parser_t *parser, const pm_token_t *token) {
5492 assert(token->type == PM_TOKEN_KEYWORD_NIL);
5493 pm_nil_node_t *node = PM_NODE_ALLOC(parser, pm_nil_node_t);
5495 *node = (pm_nil_node_t) {
5496 .base = PM_NODE_INIT_TOKEN(parser, PM_NIL_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
5505static pm_no_keywords_parameter_node_t *
5506pm_no_keywords_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *keyword) {
5507 assert(operator->type == PM_TOKEN_USTAR_STAR || operator->type == PM_TOKEN_STAR_STAR);
5508 assert(keyword->type == PM_TOKEN_KEYWORD_NIL);
5509 pm_no_keywords_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_no_keywords_parameter_node_t);
5511 *node = (pm_no_keywords_parameter_node_t) {
5512 .base = PM_NODE_INIT_TOKENS(parser, PM_NO_KEYWORDS_PARAMETER_NODE, 0, operator, keyword),
5513 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5514 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword)
5523static pm_numbered_parameters_node_t *
5524pm_numbered_parameters_node_create(pm_parser_t *parser, const pm_location_t *location, uint8_t maximum) {
5525 pm_numbered_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_parameters_node_t);
5527 *node = (pm_numbered_parameters_node_t) {
5528 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_PARAMETERS_NODE, 0, location),
5539#define NTH_REF_MAX ((uint32_t) (INT_MAX >> 1))
5548pm_numbered_reference_read_node_number(pm_parser_t *parser, const pm_token_t *token) {
5549 const uint8_t *start = token->start + 1;
5550 const uint8_t *end = token->end;
5552 ptrdiff_t diff = end - start;
5554#if PTRDIFF_MAX > SIZE_MAX
5555 assert(diff < (ptrdiff_t) SIZE_MAX);
5557 size_t length = (size_t) diff;
5559 char *digits = xcalloc(length + 1, sizeof(char));
5560 memcpy(digits, start, length);
5561 digits[length] = '\0';
5565 unsigned long value = strtoul(digits, &endptr, 10);
5567 if ((digits == endptr) || (*endptr != '\0')) {
5568 pm_parser_err(parser, start, end, PM_ERR_INVALID_NUMBER_DECIMAL);
5574 if ((errno == ERANGE) || (value > NTH_REF_MAX)) {
5575 PM_PARSER_WARN_FORMAT(parser, start, end, PM_WARN_INVALID_NUMBERED_REFERENCE, (int) (length + 1), (const char *) token->start);
5579 return (uint32_t) value;
5587static pm_numbered_reference_read_node_t *
5588pm_numbered_reference_read_node_create(pm_parser_t *parser, const pm_token_t *name) {
5589 assert(name->type == PM_TOKEN_NUMBERED_REFERENCE);
5590 pm_numbered_reference_read_node_t *node = PM_NODE_ALLOC(parser, pm_numbered_reference_read_node_t);
5592 *node = (pm_numbered_reference_read_node_t) {
5593 .base = PM_NODE_INIT_TOKEN(parser, PM_NUMBERED_REFERENCE_READ_NODE, 0, name),
5594 .number = pm_numbered_reference_read_node_number(parser, name)
5603static pm_optional_parameter_node_t *
5604pm_optional_parameter_node_create(pm_parser_t *parser, const pm_token_t *name, const pm_token_t *operator, pm_node_t *value) {
5605 pm_optional_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_optional_parameter_node_t);
5607 *node = (pm_optional_parameter_node_t) {
5608 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_OPTIONAL_PARAMETER_NODE, 0, name, value),
5609 .name = pm_parser_constant_id_token(parser, name),
5610 .name_loc = PM_LOCATION_TOKEN_VALUE(name),
5611 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5621static pm_or_node_t *
5622pm_or_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5623 pm_assert_value_expression(parser, left);
5625 pm_or_node_t *node = PM_NODE_ALLOC(parser, pm_or_node_t);
5627 *node = (pm_or_node_t) {
5628 .base = PM_NODE_INIT_NODES(parser, PM_OR_NODE, 0, left, right),
5631 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5640static pm_parameters_node_t *
5641pm_parameters_node_create(pm_parser_t *parser) {
5642 pm_parameters_node_t *node = PM_NODE_ALLOC(parser, pm_parameters_node_t);
5644 *node = (pm_parameters_node_t) {
5645 .base = PM_NODE_INIT_UNSET(parser, PM_PARAMETERS_NODE, 0),
5647 .keyword_rest = NULL,
5662pm_parameters_node_location_set(pm_parameters_node_t *params, pm_node_t *param) {
5663 if (params->base.location.start == NULL) {
5664 params->base.location.start = param->location.start;
5666 params->base.location.start = params->base.location.start < param->location.start ? params->base.location.start : param->location.start;
5669 if (params->base.location.end == NULL) {
5670 params->base.location.end = param->location.end;
5672 params->base.location.end = params->base.location.end > param->location.end ? params->base.location.end : param->location.end;
5680pm_parameters_node_requireds_append(pm_parameters_node_t *params, pm_node_t *param) {
5681 pm_parameters_node_location_set(params, param);
5682 pm_node_list_append(¶ms->requireds, param);
5689pm_parameters_node_optionals_append(pm_parameters_node_t *params, pm_optional_parameter_node_t *param) {
5690 pm_parameters_node_location_set(params, UP(param));
5691 pm_node_list_append(¶ms->optionals, UP(param));
5698pm_parameters_node_posts_append(pm_parameters_node_t *params, pm_node_t *param) {
5699 pm_parameters_node_location_set(params, param);
5700 pm_node_list_append(¶ms->posts, param);
5707pm_parameters_node_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5708 pm_parameters_node_location_set(params, param);
5709 params->rest = param;
5716pm_parameters_node_keywords_append(pm_parameters_node_t *params, pm_node_t *param) {
5717 pm_parameters_node_location_set(params, param);
5718 pm_node_list_append(¶ms->keywords, param);
5725pm_parameters_node_keyword_rest_set(pm_parameters_node_t *params, pm_node_t *param) {
5726 assert(params->keyword_rest == NULL);
5727 pm_parameters_node_location_set(params, param);
5728 params->keyword_rest = param;
5735pm_parameters_node_block_set(pm_parameters_node_t *params, pm_block_parameter_node_t *param) {
5736 assert(params->block == NULL);
5737 pm_parameters_node_location_set(params, UP(param));
5738 params->block = param;
5744static pm_program_node_t *
5745pm_program_node_create(pm_parser_t *parser, pm_constant_id_list_t *locals, pm_statements_node_t *statements) {
5746 pm_program_node_t *node = PM_NODE_ALLOC(parser, pm_program_node_t);
5748 *node = (pm_program_node_t) {
5749 .base = PM_NODE_INIT_NODE(parser, PM_PROGRAM_NODE, 0, statements),
5751 .statements = statements
5760static pm_parentheses_node_t *
5761pm_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) {
5762 pm_parentheses_node_t *node = PM_NODE_ALLOC(parser, pm_parentheses_node_t);
5764 *node = (pm_parentheses_node_t) {
5765 .base = PM_NODE_INIT_TOKENS(parser, PM_PARENTHESES_NODE, flags, opening, closing),
5767 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5768 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5777static pm_pinned_expression_node_t *
5778pm_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) {
5779 pm_pinned_expression_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_expression_node_t);
5781 *node = (pm_pinned_expression_node_t) {
5782 .base = PM_NODE_INIT_TOKENS(parser, PM_PINNED_EXPRESSION_NODE, 0, operator, rparen),
5783 .expression = expression,
5784 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
5785 .lparen_loc = PM_LOCATION_TOKEN_VALUE(lparen),
5786 .rparen_loc = PM_LOCATION_TOKEN_VALUE(rparen)
5795static pm_pinned_variable_node_t *
5796pm_pinned_variable_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *variable) {
5797 pm_pinned_variable_node_t *node = PM_NODE_ALLOC(parser, pm_pinned_variable_node_t);
5799 *node = (pm_pinned_variable_node_t) {
5800 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_PINNED_VARIABLE_NODE, 0, operator, variable),
5801 .variable = variable,
5802 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5811static pm_post_execution_node_t *
5812pm_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) {
5813 pm_post_execution_node_t *node = PM_NODE_ALLOC(parser, pm_post_execution_node_t);
5815 *node = (pm_post_execution_node_t) {
5816 .base = PM_NODE_INIT_TOKENS(parser, PM_POST_EXECUTION_NODE, 0, keyword, closing),
5817 .statements = statements,
5818 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5819 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5820 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5829static pm_pre_execution_node_t *
5830pm_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) {
5831 pm_pre_execution_node_t *node = PM_NODE_ALLOC(parser, pm_pre_execution_node_t);
5833 *node = (pm_pre_execution_node_t) {
5834 .base = PM_NODE_INIT_TOKENS(parser, PM_PRE_EXECUTION_NODE, 0, keyword, closing),
5835 .statements = statements,
5836 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5837 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5838 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing)
5847static pm_range_node_t *
5848pm_range_node_create(pm_parser_t *parser, pm_node_t *left, const pm_token_t *operator, pm_node_t *right) {
5849 pm_assert_value_expression(parser, left);
5850 pm_assert_value_expression(parser, right);
5852 pm_range_node_t *node = PM_NODE_ALLOC(parser, pm_range_node_t);
5853 pm_node_flags_t flags = 0;
5855 // Indicate that this node is an exclusive range if the operator is `...`.
5856 if (operator->type == PM_TOKEN_DOT_DOT_DOT || operator->type == PM_TOKEN_UDOT_DOT_DOT) {
5857 flags |= PM_RANGE_FLAGS_EXCLUDE_END;
5860 // Indicate that this node is a static literal (i.e., can be compiled with
5861 // a putobject in CRuby) if the left and right are implicit nil, explicit
5862 // nil, or integers.
5864 (left == NULL || PM_NODE_TYPE_P(left, PM_NIL_NODE) || PM_NODE_TYPE_P(left, PM_INTEGER_NODE)) &&
5865 (right == NULL || PM_NODE_TYPE_P(right, PM_NIL_NODE) || PM_NODE_TYPE_P(right, PM_INTEGER_NODE))
5867 flags |= PM_NODE_FLAG_STATIC_LITERAL;
5870 *node = (pm_range_node_t) {
5871 .base = PM_NODE_INIT(parser, PM_RANGE_NODE, flags, (left == NULL ? operator->start : left->location.start), (right == NULL ? operator->end : right->location.end)),
5874 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
5883static pm_redo_node_t *
5884pm_redo_node_create(pm_parser_t *parser, const pm_token_t *token) {
5885 assert(token->type == PM_TOKEN_KEYWORD_REDO);
5886 pm_redo_node_t *node = PM_NODE_ALLOC(parser, pm_redo_node_t);
5888 *node = (pm_redo_node_t) {
5889 .base = PM_NODE_INIT_TOKEN(parser, PM_REDO_NODE, 0, token)
5899static pm_regular_expression_node_t *
5900pm_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) {
5901 pm_regular_expression_node_t *node = PM_NODE_ALLOC(parser, pm_regular_expression_node_t);
5902 pm_node_flags_t flags = pm_regular_expression_flags_create(parser, closing) | PM_NODE_FLAG_STATIC_LITERAL;
5904 *node = (pm_regular_expression_node_t) {
5905 .base = PM_NODE_INIT_TOKENS(parser, PM_REGULAR_EXPRESSION_NODE, flags, opening, closing),
5906 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
5907 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
5908 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
5909 .unescaped = *unescaped
5918static inline pm_regular_expression_node_t *
5919pm_regular_expression_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
5920 return pm_regular_expression_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
5926static pm_required_parameter_node_t *
5927pm_required_parameter_node_create(pm_parser_t *parser, const pm_token_t *token) {
5928 pm_required_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_required_parameter_node_t);
5930 *node = (pm_required_parameter_node_t) {
5931 .base = PM_NODE_INIT_TOKEN(parser, PM_REQUIRED_PARAMETER_NODE, 0, token),
5932 .name = pm_parser_constant_id_token(parser, token)
5941static pm_rescue_modifier_node_t *
5942pm_rescue_modifier_node_create(pm_parser_t *parser, pm_node_t *expression, const pm_token_t *keyword, pm_node_t *rescue_expression) {
5943 pm_rescue_modifier_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_modifier_node_t);
5945 *node = (pm_rescue_modifier_node_t) {
5946 .base = PM_NODE_INIT_NODES(parser, PM_RESCUE_MODIFIER_NODE, 0, expression, rescue_expression),
5947 .expression = expression,
5948 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5949 .rescue_expression = rescue_expression
5958static pm_rescue_node_t *
5959pm_rescue_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
5960 pm_rescue_node_t *node = PM_NODE_ALLOC(parser, pm_rescue_node_t);
5962 *node = (pm_rescue_node_t) {
5963 .base = PM_NODE_INIT_TOKEN(parser, PM_RESCUE_NODE, 0, keyword),
5964 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
5965 .operator_loc = { 0 },
5966 .then_keyword_loc = { 0 },
5977pm_rescue_node_operator_set(pm_rescue_node_t *node, const pm_token_t *operator) {
5978 node->operator_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(operator);
5985pm_rescue_node_reference_set(pm_rescue_node_t *node, pm_node_t *reference) {
5986 node->reference = reference;
5987 node->base.location.end = reference->location.end;
5994pm_rescue_node_statements_set(pm_rescue_node_t *node, pm_statements_node_t *statements) {
5995 node->statements = statements;
5996 if (pm_statements_node_body_length(statements) > 0) {
5997 node->base.location.end = statements->base.location.end;
6005pm_rescue_node_subsequent_set(pm_rescue_node_t *node, pm_rescue_node_t *subsequent) {
6006 node->subsequent = subsequent;
6007 node->base.location.end = subsequent->base.location.end;
6014pm_rescue_node_exceptions_append(pm_rescue_node_t *node, pm_node_t *exception) {
6015 pm_node_list_append(&node->exceptions, exception);
6016 node->base.location.end = exception->location.end;
6022static pm_rest_parameter_node_t *
6023pm_rest_parameter_node_create(pm_parser_t *parser, const pm_token_t *operator, const pm_token_t *name) {
6024 pm_rest_parameter_node_t *node = PM_NODE_ALLOC(parser, pm_rest_parameter_node_t);
6026 *node = (pm_rest_parameter_node_t) {
6028 (name->type == PM_TOKEN_NOT_PROVIDED)
6029 ? PM_NODE_INIT_TOKEN(parser, PM_REST_PARAMETER_NODE, 0, operator)
6030 : PM_NODE_INIT_TOKENS(parser, PM_REST_PARAMETER_NODE, 0, operator, name)
6032 .name = pm_parser_optional_constant_id_token(parser, name),
6033 .name_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(name),
6034 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator)
6043static pm_retry_node_t *
6044pm_retry_node_create(pm_parser_t *parser, const pm_token_t *token) {
6045 assert(token->type == PM_TOKEN_KEYWORD_RETRY);
6046 pm_retry_node_t *node = PM_NODE_ALLOC(parser, pm_retry_node_t);
6048 *node = (pm_retry_node_t) {
6049 .base = PM_NODE_INIT_TOKEN(parser, PM_RETRY_NODE, 0, token)
6058static pm_return_node_t *
6059pm_return_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_node_t *arguments) {
6060 pm_return_node_t *node = PM_NODE_ALLOC(parser, pm_return_node_t);
6062 *node = (pm_return_node_t) {
6065 ? PM_NODE_INIT_TOKEN(parser, PM_RETURN_NODE, 0, keyword)
6066 : PM_NODE_INIT_TOKEN_NODE(parser, PM_RETURN_NODE, 0, keyword, arguments)
6068 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6069 .arguments = arguments
6078static pm_self_node_t *
6079pm_self_node_create(pm_parser_t *parser, const pm_token_t *token) {
6080 assert(token->type == PM_TOKEN_KEYWORD_SELF);
6081 pm_self_node_t *node = PM_NODE_ALLOC(parser, pm_self_node_t);
6083 *node = (pm_self_node_t) {
6084 .base = PM_NODE_INIT_TOKEN(parser, PM_SELF_NODE, 0, token)
6093static pm_shareable_constant_node_t *
6094pm_shareable_constant_node_create(pm_parser_t *parser, pm_node_t *write, pm_shareable_constant_value_t value) {
6095 pm_shareable_constant_node_t *node = PM_NODE_ALLOC(parser, pm_shareable_constant_node_t);
6097 *node = (pm_shareable_constant_node_t) {
6098 .base = PM_NODE_INIT_NODE(parser, PM_SHAREABLE_CONSTANT_NODE, (pm_node_flags_t) value, write),
6108static pm_singleton_class_node_t *
6109pm_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) {
6110 pm_singleton_class_node_t *node = PM_NODE_ALLOC(parser, pm_singleton_class_node_t);
6112 *node = (pm_singleton_class_node_t) {
6113 .base = PM_NODE_INIT_TOKENS(parser, PM_SINGLETON_CLASS_NODE, 0, class_keyword, end_keyword),
6115 .class_keyword_loc = PM_LOCATION_TOKEN_VALUE(class_keyword),
6116 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6117 .expression = expression,
6119 .end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword)
6128static pm_source_encoding_node_t *
6129pm_source_encoding_node_create(pm_parser_t *parser, const pm_token_t *token) {
6130 assert(token->type == PM_TOKEN_KEYWORD___ENCODING__);
6131 pm_source_encoding_node_t *node = PM_NODE_ALLOC(parser, pm_source_encoding_node_t);
6133 *node = (pm_source_encoding_node_t) {
6134 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_ENCODING_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6143static pm_source_file_node_t*
6144pm_source_file_node_create(pm_parser_t *parser, const pm_token_t *file_keyword) {
6145 pm_source_file_node_t *node = PM_NODE_ALLOC(parser, pm_source_file_node_t);
6146 assert(file_keyword->type == PM_TOKEN_KEYWORD___FILE__);
6148 pm_node_flags_t flags = 0;
6150 switch (parser->frozen_string_literal) {
6151 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6152 flags |= PM_STRING_FLAGS_MUTABLE;
6154 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6155 flags |= PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6159 *node = (pm_source_file_node_t) {
6160 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_FILE_NODE, flags, file_keyword),
6161 .filepath = parser->filepath
6170static pm_source_line_node_t *
6171pm_source_line_node_create(pm_parser_t *parser, const pm_token_t *token) {
6172 assert(token->type == PM_TOKEN_KEYWORD___LINE__);
6173 pm_source_line_node_t *node = PM_NODE_ALLOC(parser, pm_source_line_node_t);
6175 *node = (pm_source_line_node_t) {
6176 .base = PM_NODE_INIT_TOKEN(parser, PM_SOURCE_LINE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6185static pm_splat_node_t *
6186pm_splat_node_create(pm_parser_t *parser, const pm_token_t *operator, pm_node_t *expression) {
6187 pm_splat_node_t *node = PM_NODE_ALLOC(parser, pm_splat_node_t);
6189 *node = (pm_splat_node_t) {
6191 (expression == NULL)
6192 ? PM_NODE_INIT_TOKEN(parser, PM_SPLAT_NODE, 0, operator)
6193 : PM_NODE_INIT_TOKEN_NODE(parser, PM_SPLAT_NODE, 0, operator, expression)
6195 .operator_loc = PM_LOCATION_TOKEN_VALUE(operator),
6196 .expression = expression
6205static pm_statements_node_t *
6206pm_statements_node_create(pm_parser_t *parser) {
6207 pm_statements_node_t *node = PM_NODE_ALLOC(parser, pm_statements_node_t);
6209 *node = (pm_statements_node_t) {
6210 .base = PM_NODE_INIT_BASE(parser, PM_STATEMENTS_NODE, 0),
6221pm_statements_node_body_length(pm_statements_node_t *node) {
6222 return node && node->body.size;
6229pm_statements_node_location_set(pm_statements_node_t *node, const uint8_t *start, const uint8_t *end) {
6230 node->base.location = (pm_location_t) { .start = start, .end = end };
6238pm_statements_node_body_update(pm_statements_node_t *node, pm_node_t *statement) {
6239 if (pm_statements_node_body_length(node) == 0 || statement->location.start < node->base.location.start) {
6240 node->base.location.start = statement->location.start;
6243 if (statement->location.end > node->base.location.end) {
6244 node->base.location.end = statement->location.end;
6252pm_statements_node_body_append(pm_parser_t *parser, pm_statements_node_t *node, pm_node_t *statement, bool newline) {
6253 pm_statements_node_body_update(node, statement);
6255 if (node->body.size > 0) {
6256 const pm_node_t *previous = node->body.nodes[node->body.size - 1];
6258 switch (PM_NODE_TYPE(previous)) {
6263 case PM_RETURN_NODE:
6264 pm_parser_warn_node(parser, statement, PM_WARN_UNREACHABLE_STATEMENT);
6271 pm_node_list_append(&node->body, statement);
6272 if (newline) pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6279pm_statements_node_body_prepend(pm_statements_node_t *node, pm_node_t *statement) {
6280 pm_statements_node_body_update(node, statement);
6281 pm_node_list_prepend(&node->body, statement);
6282 pm_node_flag_set(statement, PM_NODE_FLAG_NEWLINE);
6288static inline pm_string_node_t *
6289pm_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) {
6290 pm_string_node_t *node = PM_NODE_ALLOC(parser, pm_string_node_t);
6291 pm_node_flags_t flags = 0;
6293 switch (parser->frozen_string_literal) {
6294 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6295 flags = PM_STRING_FLAGS_MUTABLE;
6297 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6298 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6302 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? content->start : opening->start);
6303 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? content->end : closing->end);
6305 *node = (pm_string_node_t) {
6306 .base = PM_NODE_INIT(parser, PM_STRING_NODE, flags, start, end),
6307 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6308 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
6309 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6310 .unescaped = *string
6319static pm_string_node_t *
6320pm_string_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6321 return pm_string_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
6328static pm_string_node_t *
6329pm_string_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
6330 pm_string_node_t *node = pm_string_node_create_unescaped(parser, opening, content, closing, &parser->current_string);
6331 parser->current_string = PM_STRING_EMPTY;
6338static pm_super_node_t *
6339pm_super_node_create(pm_parser_t *parser, const pm_token_t *keyword, pm_arguments_t *arguments) {
6340 assert(keyword->type == PM_TOKEN_KEYWORD_SUPER);
6341 pm_super_node_t *node = PM_NODE_ALLOC(parser, pm_super_node_t);
6343 const uint8_t *end = pm_arguments_end(arguments);
6345 assert(false && "unreachable");
6348 *node = (pm_super_node_t) {
6349 .base = PM_NODE_INIT(parser, PM_SUPER_NODE, 0, keyword->start, end),
6350 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6351 .lparen_loc = arguments->opening_loc,
6352 .arguments = arguments->arguments,
6353 .rparen_loc = arguments->closing_loc,
6354 .block = arguments->block
6365pm_ascii_only_p(const pm_string_t *contents) {
6366 const size_t length = pm_string_length(contents);
6367 const uint8_t *source = pm_string_source(contents);
6369 for (size_t index = 0; index < length; index++) {
6370 if (source[index] & 0x80) return false;
6380parse_symbol_encoding_validate_utf8(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6381 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6382 size_t width = pm_encoding_utf_8_char_width(cursor, end - cursor);
6385 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6398parse_symbol_encoding_validate_other(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents) {
6399 const pm_encoding_t *encoding = parser->encoding;
6401 for (const uint8_t *cursor = pm_string_source(contents), *end = cursor + pm_string_length(contents); cursor < end;) {
6402 size_t width = encoding->char_width(cursor, end - cursor);
6405 pm_parser_err(parser, location->start, location->end, PM_ERR_INVALID_SYMBOL);
6422static inline pm_node_flags_t
6423parse_symbol_encoding(pm_parser_t *parser, const pm_token_t *location, const pm_string_t *contents, bool validate) {
6424 if (parser->explicit_encoding != NULL) {
6425 // A Symbol may optionally have its encoding explicitly set. This will
6426 // happen if an escape sequence results in a non-ASCII code point.
6427 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6428 if (validate) parse_symbol_encoding_validate_utf8(parser, location, contents);
6429 return PM_SYMBOL_FLAGS_FORCED_UTF8_ENCODING;
6430 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6431 return PM_SYMBOL_FLAGS_FORCED_BINARY_ENCODING;
6432 } else if (validate) {
6433 parse_symbol_encoding_validate_other(parser, location, contents);
6435 } else if (pm_ascii_only_p(contents)) {
6436 // Ruby stipulates that all source files must use an ASCII-compatible
6437 // encoding. Thus, all symbols appearing in source are eligible for
6438 // "downgrading" to US-ASCII.
6439 return PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING;
6440 } else if (validate) {
6441 parse_symbol_encoding_validate_other(parser, location, contents);
6447static pm_node_flags_t
6448parse_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) {
6449 assert ((modifier == 'n' && modifier_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) ||
6450 (modifier == 'u' && modifier_encoding == PM_ENCODING_UTF_8_ENTRY) ||
6451 (modifier == 'e' && modifier_encoding == PM_ENCODING_EUC_JP_ENTRY) ||
6452 (modifier == 's' && modifier_encoding == PM_ENCODING_WINDOWS_31J_ENTRY));
6454 // There's special validation logic used if a string does not contain any character escape sequences.
6455 if (parser->explicit_encoding == NULL) {
6456 // If an ASCII-only string without character escapes is used with an encoding modifier, then resulting Regexp
6457 // has the modifier encoding, unless the ASCII-8BIT modifier is used, in which case the Regexp "downgrades" to
6458 // the US-ASCII encoding.
6460 return modifier == 'n' ? PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING : flags;
6463 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6465 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6467 } else if (parser->encoding != modifier_encoding) {
6468 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_REGEXP_ENCODING_OPTION_MISMATCH, modifier, parser->encoding->name);
6470 if (modifier == 'n' && !ascii_only) {
6471 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));
6478 // 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.
6479 bool mixed_encoding = false;
6481 if (mixed_encoding) {
6482 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6483 } else if (modifier != 'n' && parser->explicit_encoding == PM_ENCODING_ASCII_8BIT_ENTRY) {
6484 // 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.
6485 bool valid_string_in_modifier_encoding = true;
6487 if (!valid_string_in_modifier_encoding) {
6488 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_ESCAPE, (int) pm_string_length(source), (const char *) pm_string_source(source));
6490 } else if (modifier != 'u' && parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6491 // 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.
6492 if (parser->encoding != PM_ENCODING_UTF_8_ENTRY) {
6493 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));
6497 // We've determined the encoding would naturally be EUC-JP and there is no need to force the encoding to anything else.
6507static pm_node_flags_t
6508parse_and_validate_regular_expression_encoding(pm_parser_t *parser, const pm_string_t *source, bool ascii_only, pm_node_flags_t flags) {
6509 // 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.
6510 bool valid_unicode_range = true;
6511 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY && !valid_unicode_range) {
6512 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));
6516 // US-ASCII strings do not admit multi-byte character literals. However, character escape sequences corresponding
6517 // to multi-byte characters are allowed.
6518 if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY && parser->explicit_encoding == NULL && !ascii_only) {
6519 // CRuby will continue processing even though a SyntaxError has already been detected. It may result in the
6520 // following error message appearing twice. We do the same for compatibility.
6521 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->current, PM_ERR_INVALID_MULTIBYTE_CHAR, parser->encoding->name);
6532 if (flags & PM_REGULAR_EXPRESSION_FLAGS_ASCII_8BIT) {
6533 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'n', PM_ENCODING_ASCII_8BIT_ENTRY);
6536 if (flags & PM_REGULAR_EXPRESSION_FLAGS_UTF_8) {
6537 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'u', PM_ENCODING_UTF_8_ENTRY);
6540 if (flags & PM_REGULAR_EXPRESSION_FLAGS_EUC_JP) {
6541 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 'e', PM_ENCODING_EUC_JP_ENTRY);
6544 if (flags & PM_REGULAR_EXPRESSION_FLAGS_WINDOWS_31J) {
6545 return parse_and_validate_regular_expression_encoding_modifier(parser, source, ascii_only, flags, 's', PM_ENCODING_WINDOWS_31J_ENTRY);
6548 // At this point no encoding modifiers will be present on the regular expression as they would have already
6549 // been processed. Ruby stipulates that all source files must use an ASCII-compatible encoding. Thus, all
6550 // regular expressions without an encoding modifier appearing in source are eligible for "downgrading" to US-ASCII.
6552 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING;
6555 // A Regexp may optionally have its encoding explicitly set via a character escape sequence in the source string
6556 // or by specifying a modifier.
6558 // NB: an explicitly set encoding is ignored by Ruby if the Regexp consists of only US ASCII code points.
6559 if (parser->explicit_encoding != NULL) {
6560 if (parser->explicit_encoding == PM_ENCODING_UTF_8_ENTRY) {
6561 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_UTF8_ENCODING;
6562 } else if (parser->encoding == PM_ENCODING_US_ASCII_ENTRY) {
6563 return PM_REGULAR_EXPRESSION_FLAGS_FORCED_BINARY_ENCODING;
6574static pm_symbol_node_t *
6575pm_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) {
6576 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6578 const uint8_t *start = (opening->type == PM_TOKEN_NOT_PROVIDED ? value->start : opening->start);
6579 const uint8_t *end = (closing->type == PM_TOKEN_NOT_PROVIDED ? value->end : closing->end);
6581 *node = (pm_symbol_node_t) {
6582 .base = PM_NODE_INIT(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | flags, start, end),
6583 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6584 .value_loc = PM_LOCATION_TOKEN_VALUE(value),
6585 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6586 .unescaped = *unescaped
6595static inline pm_symbol_node_t *
6596pm_symbol_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6597 return pm_symbol_node_create_unescaped(parser, opening, value, closing, &PM_STRING_EMPTY, 0);
6603static pm_symbol_node_t *
6604pm_symbol_node_create_current_string(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *value, const pm_token_t *closing) {
6605 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));
6606 parser->current_string = PM_STRING_EMPTY;
6613static pm_symbol_node_t *
6614pm_symbol_node_label_create(pm_parser_t *parser, const pm_token_t *token) {
6615 pm_symbol_node_t *node;
6617 switch (token->type) {
6618 case PM_TOKEN_LABEL: {
6619 pm_token_t opening = not_provided(parser);
6620 pm_token_t closing = { .type = PM_TOKEN_LABEL_END, .start = token->end - 1, .end = token->end };
6622 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end - 1 };
6623 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6625 assert((label.end - label.start) >= 0);
6626 pm_string_shared_init(&node->unescaped, label.start, label.end);
6627 pm_node_flag_set(UP(node), parse_symbol_encoding(parser, &label, &node->unescaped, false));
6631 case PM_TOKEN_MISSING: {
6632 pm_token_t opening = not_provided(parser);
6633 pm_token_t closing = not_provided(parser);
6635 pm_token_t label = { .type = PM_TOKEN_LABEL, .start = token->start, .end = token->end };
6636 node = pm_symbol_node_create(parser, &opening, &label, &closing);
6640 assert(false && "unreachable");
6651static pm_symbol_node_t *
6652pm_symbol_node_synthesized_create(pm_parser_t *parser, const char *content) {
6653 pm_symbol_node_t *node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6655 *node = (pm_symbol_node_t) {
6656 .base = PM_NODE_INIT_BASE(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL | PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING),
6657 .value_loc = PM_LOCATION_NULL_VALUE(parser),
6661 pm_string_constant_init(&node->unescaped, content, strlen(content));
6669pm_symbol_node_label_p(pm_node_t *node) {
6670 const uint8_t *end = NULL;
6672 switch (PM_NODE_TYPE(node)) {
6673 case PM_SYMBOL_NODE:
6674 end = ((pm_symbol_node_t *) node)->closing_loc.end;
6676 case PM_INTERPOLATED_SYMBOL_NODE:
6677 end = ((pm_interpolated_symbol_node_t *) node)->closing_loc.end;
6683 return (end != NULL) && (end[-1] == ':');
6689static pm_symbol_node_t *
6690pm_string_node_to_symbol_node(pm_parser_t *parser, pm_string_node_t *node, const pm_token_t *opening, const pm_token_t *closing) {
6691 pm_symbol_node_t *new_node = PM_NODE_ALLOC(parser, pm_symbol_node_t);
6693 *new_node = (pm_symbol_node_t) {
6694 .base = PM_NODE_INIT_TOKENS(parser, PM_SYMBOL_NODE, PM_NODE_FLAG_STATIC_LITERAL, opening, closing),
6695 .opening_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(opening),
6696 .value_loc = node->content_loc,
6697 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6698 .unescaped = node->unescaped
6701 pm_token_t content = { .type = PM_TOKEN_IDENTIFIER, .start = node->content_loc.start, .end = node->content_loc.end };
6702 pm_node_flag_set(UP(new_node), parse_symbol_encoding(parser, &content, &node->unescaped, true));
6704 // We are explicitly _not_ using pm_node_destroy here because we don't want
6705 // to trash the unescaped string. We could instead copy the string if we
6706 // know that it is owned, but we're taking the fast path for now.
6715static pm_string_node_t *
6716pm_symbol_node_to_string_node(pm_parser_t *parser, pm_symbol_node_t *node) {
6717 pm_string_node_t *new_node = PM_NODE_ALLOC(parser, pm_string_node_t);
6718 pm_node_flags_t flags = 0;
6720 switch (parser->frozen_string_literal) {
6721 case PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED:
6722 flags = PM_STRING_FLAGS_MUTABLE;
6724 case PM_OPTIONS_FROZEN_STRING_LITERAL_ENABLED:
6725 flags = PM_NODE_FLAG_STATIC_LITERAL | PM_STRING_FLAGS_FROZEN;
6729 *new_node = (pm_string_node_t) {
6730 .base = PM_NODE_INIT_NODE(parser, PM_STRING_NODE, flags, node),
6731 .opening_loc = node->opening_loc,
6732 .content_loc = node->value_loc,
6733 .closing_loc = node->closing_loc,
6734 .unescaped = node->unescaped
6737 // We are explicitly _not_ using pm_node_destroy here because we don't want
6738 // to trash the unescaped string. We could instead copy the string if we
6739 // know that it is owned, but we're taking the fast path for now.
6748static pm_true_node_t *
6749pm_true_node_create(pm_parser_t *parser, const pm_token_t *token) {
6750 assert(token->type == PM_TOKEN_KEYWORD_TRUE);
6751 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6753 *node = (pm_true_node_t) {
6754 .base = PM_NODE_INIT_TOKEN(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL, token)
6763static pm_true_node_t *
6764pm_true_node_synthesized_create(pm_parser_t *parser) {
6765 pm_true_node_t *node = PM_NODE_ALLOC(parser, pm_true_node_t);
6767 *node = (pm_true_node_t) {
6768 .base = PM_NODE_INIT_BASE(parser, PM_TRUE_NODE, PM_NODE_FLAG_STATIC_LITERAL)
6777static pm_undef_node_t *
6778pm_undef_node_create(pm_parser_t *parser, const pm_token_t *token) {
6779 assert(token->type == PM_TOKEN_KEYWORD_UNDEF);
6780 pm_undef_node_t *node = PM_NODE_ALLOC(parser, pm_undef_node_t);
6782 *node = (pm_undef_node_t) {
6783 .base = PM_NODE_INIT_TOKEN(parser, PM_UNDEF_NODE, 0, token),
6784 .keyword_loc = PM_LOCATION_TOKEN_VALUE(token),
6795pm_undef_node_append(pm_undef_node_t *node, pm_node_t *name) {
6796 node->base.location.end = name->location.end;
6797 pm_node_list_append(&node->names, name);
6803static pm_unless_node_t *
6804pm_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) {
6805 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6807 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6808 pm_node_t *end = statements == NULL ? predicate : UP(statements);
6810 *node = (pm_unless_node_t) {
6811 .base = PM_NODE_INIT_TOKEN_NODE(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, keyword, end),
6812 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6813 .predicate = predicate,
6814 .then_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(then_keyword),
6815 .statements = statements,
6816 .else_clause = NULL,
6817 .end_keyword_loc = { 0 }
6826static pm_unless_node_t *
6827pm_unless_node_modifier_create(pm_parser_t *parser, pm_node_t *statement, const pm_token_t *unless_keyword, pm_node_t *predicate) {
6828 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6829 pm_unless_node_t *node = PM_NODE_ALLOC(parser, pm_unless_node_t);
6831 pm_statements_node_t *statements = pm_statements_node_create(parser);
6832 pm_statements_node_body_append(parser, statements, statement, true);
6834 *node = (pm_unless_node_t) {
6835 .base = PM_NODE_INIT_NODES(parser, PM_UNLESS_NODE, PM_NODE_FLAG_NEWLINE, statement, predicate),
6836 .keyword_loc = PM_LOCATION_TOKEN_VALUE(unless_keyword),
6837 .predicate = predicate,
6838 .then_keyword_loc = { 0 },
6839 .statements = statements,
6840 .else_clause = NULL,
6841 .end_keyword_loc = { 0 }
6848pm_unless_node_end_keyword_loc_set(pm_unless_node_t *node, const pm_token_t *end_keyword) {
6849 node->end_keyword_loc = PM_LOCATION_TOKEN_VALUE(end_keyword);
6850 node->base.location.end = end_keyword->end;
6859pm_loop_modifier_block_exits(pm_parser_t *parser, pm_statements_node_t *statements) {
6860 assert(parser->current_block_exits != NULL);
6862 // All of the block exits that we want to remove should be within the
6863 // statements, and since we are modifying the statements, we shouldn't have
6864 // to check the end location.
6865 const uint8_t *start = statements->base.location.start;
6867 for (size_t index = parser->current_block_exits->size; index > 0; index--) {
6868 pm_node_t *block_exit = parser->current_block_exits->nodes[index - 1];
6869 if (block_exit->location.start < start) break;
6871 // Implicitly remove from the list by lowering the size.
6872 parser->current_block_exits->size--;
6879static pm_until_node_t *
6880pm_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) {
6881 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6882 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6884 *node = (pm_until_node_t) {
6885 .base = PM_NODE_INIT_TOKENS(parser, PM_UNTIL_NODE, flags, keyword, closing),
6886 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6887 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6888 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6889 .predicate = predicate,
6890 .statements = statements
6899static pm_until_node_t *
6900pm_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) {
6901 pm_until_node_t *node = PM_NODE_ALLOC(parser, pm_until_node_t);
6902 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6903 pm_loop_modifier_block_exits(parser, statements);
6905 *node = (pm_until_node_t) {
6906 .base = PM_NODE_INIT_NODES(parser, PM_UNTIL_NODE, flags, statements, predicate),
6907 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6908 .do_keyword_loc = { 0 },
6909 .closing_loc = { 0 },
6910 .predicate = predicate,
6911 .statements = statements
6920static pm_when_node_t *
6921pm_when_node_create(pm_parser_t *parser, const pm_token_t *keyword) {
6922 pm_when_node_t *node = PM_NODE_ALLOC(parser, pm_when_node_t);
6924 *node = (pm_when_node_t) {
6925 .base = PM_NODE_INIT_TOKEN(parser, PM_WHEN_NODE, 0, keyword),
6926 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6928 .then_keyword_loc = { 0 },
6939pm_when_node_conditions_append(pm_when_node_t *node, pm_node_t *condition) {
6940 node->base.location.end = condition->location.end;
6941 pm_node_list_append(&node->conditions, condition);
6948pm_when_node_then_keyword_loc_set(pm_when_node_t *node, const pm_token_t *then_keyword) {
6949 node->base.location.end = then_keyword->end;
6950 node->then_keyword_loc = PM_LOCATION_TOKEN_VALUE(then_keyword);
6957pm_when_node_statements_set(pm_when_node_t *node, pm_statements_node_t *statements) {
6958 if (statements->base.location.end > node->base.location.end) {
6959 node->base.location.end = statements->base.location.end;
6962 node->statements = statements;
6968static pm_while_node_t *
6969pm_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) {
6970 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6971 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6973 *node = (pm_while_node_t) {
6974 .base = PM_NODE_INIT_TOKENS(parser, PM_WHILE_NODE, flags, keyword, closing),
6975 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6976 .do_keyword_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(do_keyword),
6977 .closing_loc = PM_OPTIONAL_LOCATION_TOKEN_VALUE(closing),
6978 .predicate = predicate,
6979 .statements = statements
6988static pm_while_node_t *
6989pm_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) {
6990 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
6991 pm_conditional_predicate(parser, predicate, PM_CONDITIONAL_PREDICATE_TYPE_CONDITIONAL);
6992 pm_loop_modifier_block_exits(parser, statements);
6994 *node = (pm_while_node_t) {
6995 .base = PM_NODE_INIT_NODES(parser, PM_WHILE_NODE, flags, statements, predicate),
6996 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
6997 .do_keyword_loc = { 0 },
6998 .closing_loc = { 0 },
6999 .predicate = predicate,
7000 .statements = statements
7009static pm_while_node_t *
7010pm_while_node_synthesized_create(pm_parser_t *parser, pm_node_t *predicate, pm_statements_node_t *statements) {
7011 pm_while_node_t *node = PM_NODE_ALLOC(parser, pm_while_node_t);
7013 *node = (pm_while_node_t) {
7014 .base = PM_NODE_INIT_BASE(parser, PM_WHILE_NODE, 0),
7015 .keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7016 .do_keyword_loc = PM_LOCATION_NULL_VALUE(parser),
7017 .closing_loc = PM_LOCATION_NULL_VALUE(parser),
7018 .predicate = predicate,
7019 .statements = statements
7029static pm_x_string_node_t *
7030pm_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) {
7031 pm_x_string_node_t *node = PM_NODE_ALLOC(parser, pm_x_string_node_t);
7033 *node = (pm_x_string_node_t) {
7034 .base = PM_NODE_INIT_TOKENS(parser, PM_X_STRING_NODE, PM_STRING_FLAGS_FROZEN, opening, closing),
7035 .opening_loc = PM_LOCATION_TOKEN_VALUE(opening),
7036 .content_loc = PM_LOCATION_TOKEN_VALUE(content),
7037 .closing_loc = PM_LOCATION_TOKEN_VALUE(closing),
7038 .unescaped = *unescaped
7047static inline pm_x_string_node_t *
7048pm_xstring_node_create(pm_parser_t *parser, const pm_token_t *opening, const pm_token_t *content, const pm_token_t *closing) {
7049 return pm_xstring_node_create_unescaped(parser, opening, content, closing, &PM_STRING_EMPTY);
7055static pm_yield_node_t *
7056pm_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) {
7057 pm_yield_node_t *node = PM_NODE_ALLOC(parser, pm_yield_node_t);
7060 if (rparen_loc->start != NULL) {
7061 end = rparen_loc->end;
7062 } else if (arguments != NULL) {
7063 end = arguments->base.location.end;
7064 } else if (lparen_loc->start != NULL) {
7065 end = lparen_loc->end;
7070 *node = (pm_yield_node_t) {
7071 .base = PM_NODE_INIT(parser, PM_YIELD_NODE, 0, keyword->start, end),
7072 .keyword_loc = PM_LOCATION_TOKEN_VALUE(keyword),
7073 .lparen_loc = *lparen_loc,
7074 .arguments = arguments,
7075 .rparen_loc = *rparen_loc
7086pm_parser_local_depth_constant_id(pm_parser_t *parser, pm_constant_id_t constant_id) {
7087 pm_scope_t *scope = parser->current_scope;
7090 while (scope != NULL) {
7091 if (pm_locals_find(&scope->locals, constant_id) != UINT32_MAX) return depth;
7092 if (scope->closed) break;
7094 scope = scope->previous;
7107pm_parser_local_depth(pm_parser_t *parser, pm_token_t *token) {
7108 return pm_parser_local_depth_constant_id(parser, pm_parser_constant_id_token(parser, token));
7115pm_parser_local_add(pm_parser_t *parser, pm_constant_id_t constant_id, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7116 pm_locals_write(&parser->current_scope->locals, constant_id, start, end, reads);
7122static pm_constant_id_t
7123pm_parser_local_add_location(pm_parser_t *parser, const uint8_t *start, const uint8_t *end, uint32_t reads) {
7124 pm_constant_id_t constant_id = pm_parser_constant_id_location(parser, start, end);
7125 if (constant_id != 0) pm_parser_local_add(parser, constant_id, start, end, reads);
7132static inline pm_constant_id_t
7133pm_parser_local_add_token(pm_parser_t *parser, pm_token_t *token, uint32_t reads) {
7134 return pm_parser_local_add_location(parser, token->start, token->end, reads);
7140static pm_constant_id_t
7141pm_parser_local_add_owned(pm_parser_t *parser, uint8_t *start, size_t length) {
7142 pm_constant_id_t constant_id = pm_parser_constant_id_owned(parser, start, length);
7143 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7150static pm_constant_id_t
7151pm_parser_local_add_constant(pm_parser_t *parser, const char *start, size_t length) {
7152 pm_constant_id_t constant_id = pm_parser_constant_id_constant(parser, start, length);
7153 if (constant_id != 0) pm_parser_local_add(parser, constant_id, parser->start, parser->start, 1);
7165pm_parser_parameter_name_check(pm_parser_t *parser, const pm_token_t *name) {
7166 // We want to check whether the parameter name is a numbered parameter or
7168 pm_refute_numbered_parameter(parser, name->start, name->end);
7170 // Otherwise we'll fetch the constant id for the parameter name and check
7171 // whether it's already in the current scope.
7172 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, name);
7174 if (pm_locals_find(&parser->current_scope->locals, constant_id) != UINT32_MAX) {
7175 // Add an error if the parameter doesn't start with _ and has been seen before
7176 if ((name->start < name->end) && (*name->start != '_')) {
7177 pm_parser_err_token(parser, name, PM_ERR_PARAMETER_NAME_DUPLICATED);
7188pm_parser_scope_pop(pm_parser_t *parser) {
7189 pm_scope_t *scope = parser->current_scope;
7190 parser->current_scope = scope->previous;
7191 pm_locals_free(&scope->locals);
7192 pm_node_list_free(&scope->implicit_parameters);
7196/******************************************************************************/
7198/******************************************************************************/
7204pm_state_stack_push(pm_state_stack_t *stack, bool value) {
7205 *stack = (*stack << 1) | (value & 1);
7212pm_state_stack_pop(pm_state_stack_t *stack) {
7220pm_state_stack_p(const pm_state_stack_t *stack) {
7225pm_accepts_block_stack_push(pm_parser_t *parser, bool value) {
7226 // Use the negation of the value to prevent stack overflow.
7227 pm_state_stack_push(&parser->accepts_block_stack, !value);
7231pm_accepts_block_stack_pop(pm_parser_t *parser) {
7232 pm_state_stack_pop(&parser->accepts_block_stack);
7236pm_accepts_block_stack_p(pm_parser_t *parser) {
7237 return !pm_state_stack_p(&parser->accepts_block_stack);
7241pm_do_loop_stack_push(pm_parser_t *parser, bool value) {
7242 pm_state_stack_push(&parser->do_loop_stack, value);
7246pm_do_loop_stack_pop(pm_parser_t *parser) {
7247 pm_state_stack_pop(&parser->do_loop_stack);
7251pm_do_loop_stack_p(pm_parser_t *parser) {
7252 return pm_state_stack_p(&parser->do_loop_stack);
7255/******************************************************************************/
7256/* Lexer check helpers */
7257/******************************************************************************/
7263static inline uint8_t
7264peek_at(const pm_parser_t *parser, const uint8_t *cursor) {
7265 if (cursor < parser->end) {
7277static inline uint8_t
7278peek_offset(pm_parser_t *parser, ptrdiff_t offset) {
7279 return peek_at(parser, parser->current.end + offset);
7286static inline uint8_t
7287peek(const pm_parser_t *parser) {
7288 return peek_at(parser, parser->current.end);
7296match(pm_parser_t *parser, uint8_t value) {
7297 if (peek(parser) == value) {
7298 parser->current.end++;
7309match_eol_at(pm_parser_t *parser, const uint8_t *cursor) {
7310 if (peek_at(parser, cursor) == '\n') {
7313 if (peek_at(parser, cursor) == '\r' && peek_at(parser, cursor + 1) == '\n') {
7325match_eol_offset(pm_parser_t *parser, ptrdiff_t offset) {
7326 return match_eol_at(parser, parser->current.end + offset);
7335match_eol(pm_parser_t *parser) {
7336 return match_eol_at(parser, parser->current.end);
7342static inline const uint8_t *
7343next_newline(const uint8_t *cursor, ptrdiff_t length) {
7344 assert(length >= 0);
7346 // Note that it's okay for us to use memchr here to look for \n because none
7347 // of the encodings that we support have \n as a component of a multi-byte
7349 return memchr(cursor, '\n', (size_t) length);
7356ambiguous_operator_p(const pm_parser_t *parser, bool space_seen) {
7357 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));
7365parser_lex_magic_comment_encoding_value(pm_parser_t *parser, const uint8_t *start, const uint8_t *end) {
7366 const pm_encoding_t *encoding = pm_encoding_find(start, end);
7368 if (encoding != NULL) {
7369 if (parser->encoding != encoding) {
7370 parser->encoding = encoding;
7371 if (parser->encoding_changed_callback != NULL) parser->encoding_changed_callback(parser);
7374 parser->encoding_changed = (encoding != PM_ENCODING_UTF_8_ENTRY);
7386parser_lex_magic_comment_encoding(pm_parser_t *parser) {
7387 const uint8_t *cursor = parser->current.start + 1;
7388 const uint8_t *end = parser->current.end;
7390 bool separator = false;
7392 if (end - cursor <= 6) return;
7393 switch (cursor[6]) {
7394 case 'C': case 'c': cursor += 6; continue;
7395 case 'O': case 'o': cursor += 5; continue;
7396 case 'D': case 'd': cursor += 4; continue;
7397 case 'I': case 'i': cursor += 3; continue;
7398 case 'N': case 'n': cursor += 2; continue;
7399 case 'G': case 'g': cursor += 1; continue;
7406 if (pm_char_is_whitespace(*cursor)) break;
7409 if (pm_strncasecmp(cursor - 6, (const uint8_t *) "coding", 6) == 0) break;
7415 if (++cursor >= end) return;
7416 } while (pm_char_is_whitespace(*cursor));
7418 if (separator) break;
7419 if (*cursor != '=' && *cursor != ':') return;
7425 const uint8_t *value_start = cursor;
7426 while ((*cursor == '-' || *cursor == '_' || parser->encoding->alnum_char(cursor, 1)) && ++cursor < end);
7428 if (!parser_lex_magic_comment_encoding_value(parser, value_start, cursor)) {
7429 // If we were unable to parse the encoding value, then we've got an
7430 // issue because we didn't understand the encoding that the user was
7431 // trying to use. In this case we'll keep using the default encoding but
7432 // add an error to the parser to indicate an unsuccessful parse.
7433 pm_parser_err(parser, value_start, cursor, PM_ERR_INVALID_ENCODING_MAGIC_COMMENT);
7438 PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE,
7439 PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE,
7440 PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID
7441} pm_magic_comment_boolean_value_t;
7447static pm_magic_comment_boolean_value_t
7448parser_lex_magic_comment_boolean_value(const uint8_t *value_start, uint32_t value_length) {
7449 if (value_length == 4 && pm_strncasecmp(value_start, (const uint8_t *) "true", 4) == 0) {
7450 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE;
7451 } else if (value_length == 5 && pm_strncasecmp(value_start, (const uint8_t *) "false", 5) == 0) {
7452 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE;
7454 return PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID;
7459pm_char_is_magic_comment_key_delimiter(const uint8_t b) {
7460 return b == '\'' || b == '"' || b == ':' || b == ';';
7468static inline const uint8_t *
7469parser_lex_magic_comment_emacs_marker(
pm_parser_t *parser,
const uint8_t *cursor,
const uint8_t *end) {
7470 while ((cursor + 3 <= end) && (cursor = pm_memchr(cursor,
'-', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding)) != NULL) {
7471 if (cursor + 3 <= end && cursor[1] ==
'*' && cursor[2] ==
'-') {
7490parser_lex_magic_comment(
pm_parser_t *parser,
bool semantic_token_seen) {
7493 const uint8_t *start = parser->
current.start + 1;
7494 const uint8_t *end = parser->
current.end;
7495 if (end - start <= 7)
return false;
7497 const uint8_t *cursor;
7498 bool indicator =
false;
7500 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7503 if ((cursor = parser_lex_magic_comment_emacs_marker(parser, start, end)) != NULL) {
7514 while (cursor < end) {
7515 while (cursor < end && (pm_char_is_magic_comment_key_delimiter(*cursor) || pm_char_is_whitespace(*cursor))) cursor++;
7517 const uint8_t *key_start = cursor;
7518 while (cursor < end && (!pm_char_is_magic_comment_key_delimiter(*cursor) && !pm_char_is_whitespace(*cursor))) cursor++;
7520 const uint8_t *key_end = cursor;
7521 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7522 if (cursor == end)
break;
7524 if (*cursor ==
':') {
7527 if (!indicator)
return false;
7531 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7532 if (cursor == end)
break;
7534 const uint8_t *value_start;
7535 const uint8_t *value_end;
7537 if (*cursor ==
'"') {
7538 value_start = ++cursor;
7539 for (; cursor < end && *cursor !=
'"'; cursor++) {
7540 if (*cursor ==
'\\' && (cursor + 1 < end)) cursor++;
7543 if (cursor < end && *cursor ==
'"') cursor++;
7545 value_start = cursor;
7546 while (cursor < end && *cursor !=
'"' && *cursor !=
';' && !pm_char_is_whitespace(*cursor)) cursor++;
7551 while (cursor < end && (*cursor ==
';' || pm_char_is_whitespace(*cursor))) cursor++;
7553 while (cursor < end && pm_char_is_whitespace(*cursor)) cursor++;
7554 if (cursor != end)
return false;
7560 const size_t key_length = (size_t) (key_end - key_start);
7564 pm_string_shared_init(&key, key_start, key_end);
7566 uint8_t *buffer =
xmalloc(key_length);
7567 if (buffer == NULL)
break;
7569 memcpy(buffer, key_start, key_length);
7570 buffer[dash - key_start] =
'_';
7572 while ((dash = pm_memchr(dash + 1,
'-', (
size_t) (key_end - dash - 1), parser->
encoding_changed, parser->
encoding)) != NULL) {
7573 buffer[dash - key_start] =
'_';
7576 pm_string_owned_init(&key, buffer, key_length);
7582 uint32_t value_length = (uint32_t) (value_end - value_start);
7588 (key_length == 8 && pm_strncasecmp(key_source, (
const uint8_t *)
"encoding", 8) == 0) ||
7589 (key_length == 6 && pm_strncasecmp(key_source, (
const uint8_t *)
"coding", 6) == 0)
7591 result = parser_lex_magic_comment_encoding_value(parser, value_start, value_end);
7595 if (key_length == 11) {
7596 if (pm_strncasecmp(key_source, (
const uint8_t *)
"warn_indent", 11) == 0) {
7597 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7598 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7599 PM_PARSER_WARN_TOKEN_FORMAT(
7602 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7604 (
const char *) key_source,
7606 (
const char *) value_start
7609 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7612 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7617 }
else if (key_length == 21) {
7618 if (pm_strncasecmp(key_source, (
const uint8_t *)
"frozen_string_literal", 21) == 0) {
7621 if (semantic_token_seen) {
7622 pm_parser_warn_token(parser, &parser->
current, PM_WARN_IGNORED_FROZEN_STRING_LITERAL);
7624 switch (parser_lex_magic_comment_boolean_value(value_start, value_length)) {
7625 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_INVALID:
7626 PM_PARSER_WARN_TOKEN_FORMAT(
7629 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7631 (
const char *) key_source,
7633 (
const char *) value_start
7636 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_FALSE:
7639 case PM_MAGIC_COMMENT_BOOLEAN_VALUE_TRUE:
7645 }
else if (key_length == 24) {
7646 if (pm_strncasecmp(key_source, (
const uint8_t *)
"shareable_constant_value", 24) == 0) {
7647 const uint8_t *cursor = parser->
current.start;
7648 while ((cursor > parser->
start) && ((cursor[-1] ==
' ') || (cursor[-1] ==
'\t'))) cursor--;
7650 if (!((cursor == parser->
start) || (cursor[-1] ==
'\n'))) {
7651 pm_parser_warn_token(parser, &parser->
current, PM_WARN_SHAREABLE_CONSTANT_VALUE_LINE);
7652 }
else if (value_length == 4 && pm_strncasecmp(value_start, (
const uint8_t *)
"none", 4) == 0) {
7653 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_NONE);
7654 }
else if (value_length == 7 && pm_strncasecmp(value_start, (
const uint8_t *)
"literal", 7) == 0) {
7655 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_LITERAL);
7656 }
else if (value_length == 23 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_everything", 23) == 0) {
7657 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_EVERYTHING);
7658 }
else if (value_length == 17 && pm_strncasecmp(value_start, (
const uint8_t *)
"experimental_copy", 17) == 0) {
7659 pm_parser_scope_shareable_constant_set(parser, PM_SCOPE_SHAREABLE_CONSTANT_EXPERIMENTAL_COPY);
7661 PM_PARSER_WARN_TOKEN_FORMAT(
7664 PM_WARN_INVALID_MAGIC_COMMENT_VALUE,
7666 (
const char *) key_source,
7668 (
const char *) value_start
7696static const uint32_t context_terminators[] = {
7698 [
PM_CONTEXT_BEGIN] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7701 [
PM_CONTEXT_BEGIN_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7703 [
PM_CONTEXT_BLOCK_KEYWORDS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7707 [
PM_CONTEXT_BLOCK_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7708 [
PM_CONTEXT_CASE_WHEN] = (1U << PM_TOKEN_KEYWORD_WHEN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7709 [
PM_CONTEXT_CASE_IN] = (1U << PM_TOKEN_KEYWORD_IN) | (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_ELSE),
7710 [
PM_CONTEXT_CLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7713 [
PM_CONTEXT_CLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7714 [
PM_CONTEXT_DEF] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7717 [
PM_CONTEXT_DEF_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7722 [
PM_CONTEXT_ELSIF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7726 [
PM_CONTEXT_IF] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_ELSIF) | (1U << PM_TOKEN_KEYWORD_END),
7728 [
PM_CONTEXT_LAMBDA_DO_END] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7731 [
PM_CONTEXT_LAMBDA_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7734 [
PM_CONTEXT_MODULE] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7737 [
PM_CONTEXT_MODULE_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7741 [
PM_CONTEXT_PREDICATE] = (1U << PM_TOKEN_KEYWORD_THEN) | (1U << PM_TOKEN_NEWLINE) | (1U << PM_TOKEN_SEMICOLON),
7744 [
PM_CONTEXT_SCLASS] = (1U << PM_TOKEN_KEYWORD_END) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ENSURE),
7747 [
PM_CONTEXT_SCLASS_RESCUE] = (1U << PM_TOKEN_KEYWORD_ENSURE) | (1U << PM_TOKEN_KEYWORD_RESCUE) | (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7749 [
PM_CONTEXT_UNLESS] = (1U << PM_TOKEN_KEYWORD_ELSE) | (1U << PM_TOKEN_KEYWORD_END),
7756 return token->type < 32 && (context_terminators[context] & (1U << token->type));
7767 while (context_node != NULL) {
7768 if (context_terminator(context_node->
context, token))
return context_node->
context;
7769 context_node = context_node->
prev;
7778 if (context_node == NULL)
return false;
7803 while (context_node != NULL) {
7804 if (context_node->
context == context)
return true;
7805 context_node = context_node->
prev;
7815 while (context_node != NULL) {
7816 switch (context_node->
context) {
7837 context_node = context_node->
prev;
7852 assert(
false &&
"unreachable");
7910 assert(
false &&
"unreachable");
7919pm_strspn_number_validate(
pm_parser_t *parser,
const uint8_t *
string,
size_t length,
const uint8_t *invalid) {
7920 if (invalid != NULL) {
7921 pm_diagnostic_id_t diag_id = (invalid == (
string + length - 1)) ? PM_ERR_INVALID_NUMBER_UNDERSCORE_TRAILING : PM_ERR_INVALID_NUMBER_UNDERSCORE_INNER;
7922 pm_parser_err(parser, invalid, invalid + 1, diag_id);
7927pm_strspn_binary_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7928 const uint8_t *invalid = NULL;
7929 size_t length = pm_strspn_binary_number(
string, parser->
end -
string, &invalid);
7930 pm_strspn_number_validate(parser,
string, length, invalid);
7935pm_strspn_octal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7936 const uint8_t *invalid = NULL;
7937 size_t length = pm_strspn_octal_number(
string, parser->
end -
string, &invalid);
7938 pm_strspn_number_validate(parser,
string, length, invalid);
7943pm_strspn_decimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7944 const uint8_t *invalid = NULL;
7945 size_t length = pm_strspn_decimal_number(
string, parser->
end -
string, &invalid);
7946 pm_strspn_number_validate(parser,
string, length, invalid);
7951pm_strspn_hexadecimal_number_validate(
pm_parser_t *parser,
const uint8_t *
string) {
7952 const uint8_t *invalid = NULL;
7953 size_t length = pm_strspn_hexadecimal_number(
string, parser->
end -
string, &invalid);
7954 pm_strspn_number_validate(parser,
string, length, invalid);
7958static pm_token_type_t
7959lex_optional_float_suffix(
pm_parser_t *parser,
bool* seen_e) {
7960 pm_token_type_t
type = PM_TOKEN_INTEGER;
7964 if (peek(parser) ==
'.') {
7965 if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7967 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7968 type = PM_TOKEN_FLOAT;
7978 if ((peek(parser) ==
'e') || (peek(parser) ==
'E')) {
7979 if ((peek_offset(parser, 1) ==
'+') || (peek_offset(parser, 1) ==
'-')) {
7982 if (pm_char_is_decimal_digit(peek(parser))) {
7984 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7986 pm_parser_err_current(parser, PM_ERR_INVALID_FLOAT_EXPONENT);
7988 }
else if (pm_char_is_decimal_digit(peek_offset(parser, 1))) {
7990 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
7996 type = PM_TOKEN_FLOAT;
8002static pm_token_type_t
8003lex_numeric_prefix(
pm_parser_t *parser,
bool* seen_e) {
8004 pm_token_type_t
type = PM_TOKEN_INTEGER;
8007 if (peek_offset(parser, -1) ==
'0') {
8008 switch (*parser->
current.end) {
8013 if (pm_char_is_decimal_digit(peek(parser))) {
8014 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8017 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_DECIMAL);
8026 if (pm_char_is_binary_digit(peek(parser))) {
8027 parser->
current.end += pm_strspn_binary_number_validate(parser, parser->
current.end);
8030 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_BINARY);
8040 if (pm_char_is_octal_digit(peek(parser))) {
8041 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8044 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_OCTAL);
8060 parser->
current.end += pm_strspn_octal_number_validate(parser, parser->
current.end);
8068 if (pm_char_is_hexadecimal_digit(peek(parser))) {
8069 parser->
current.end += pm_strspn_hexadecimal_number_validate(parser, parser->
current.end);
8072 pm_parser_err_current(parser, PM_ERR_INVALID_NUMBER_HEXADECIMAL);
8075 parser->
integer_base = PM_INTEGER_BASE_FLAGS_HEXADECIMAL;
8080 type = lex_optional_float_suffix(parser, seen_e);
8087 type = lex_optional_float_suffix(parser, seen_e);
8094 parser->
current.end += pm_strspn_decimal_number_validate(parser, parser->
current.end);
8097 type = lex_optional_float_suffix(parser, seen_e);
8103 if (peek_offset(parser, 0) ==
'.' && pm_char_is_decimal_digit(peek_offset(parser, 1))) {
8104 const uint8_t *fraction_start = parser->
current.end;
8105 const uint8_t *fraction_end = parser->
current.end + 2;
8106 fraction_end += pm_strspn_decimal_digit(fraction_end, parser->
end - fraction_end);
8107 pm_parser_err(parser, fraction_start, fraction_end, PM_ERR_INVALID_NUMBER_FRACTION);
8113static pm_token_type_t
8115 pm_token_type_t
type = PM_TOKEN_INTEGER;
8119 bool seen_e =
false;
8120 type = lex_numeric_prefix(parser, &seen_e);
8122 const uint8_t *end = parser->
current.end;
8123 pm_token_type_t suffix_type =
type;
8125 if (
type == PM_TOKEN_INTEGER) {
8126 if (match(parser,
'r')) {
8127 suffix_type = PM_TOKEN_INTEGER_RATIONAL;
8129 if (match(parser,
'i')) {
8130 suffix_type = PM_TOKEN_INTEGER_RATIONAL_IMAGINARY;
8132 }
else if (match(parser,
'i')) {
8133 suffix_type = PM_TOKEN_INTEGER_IMAGINARY;
8136 if (!seen_e && match(parser,
'r')) {
8137 suffix_type = PM_TOKEN_FLOAT_RATIONAL;
8139 if (match(parser,
'i')) {
8140 suffix_type = PM_TOKEN_FLOAT_RATIONAL_IMAGINARY;
8142 }
else if (match(parser,
'i')) {
8143 suffix_type = PM_TOKEN_FLOAT_IMAGINARY;
8147 const uint8_t b = peek(parser);
8148 if (b !=
'\0' && (b >= 0x80 || ((b >=
'a' && b <=
'z') || (b >=
'A' && b <=
'Z')) || b ==
'_')) {
8158static pm_token_type_t
8161 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8162 return PM_TOKEN_GLOBAL_VARIABLE;
8167 bool allow_multiple =
true;
8169 switch (*parser->
current.end) {
8187 return PM_TOKEN_GLOBAL_VARIABLE;
8194 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_BACK_REFERENCE;
8200 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8203 }
while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8207 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
current, diag_id);
8210 return PM_TOKEN_GLOBAL_VARIABLE;
8223 return lex_state_p(parser, PM_LEX_STATE_FNAME) ? PM_TOKEN_GLOBAL_VARIABLE : PM_TOKEN_NUMBERED_REFERENCE;
8227 allow_multiple =
false;
8232 if ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8235 }
while (allow_multiple && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) > 0);
8236 }
else if (pm_char_is_whitespace(peek(parser))) {
8239 pm_parser_err_token(parser, &parser->
current, PM_ERR_GLOBAL_VARIABLE_BARE);
8245 PM_PARSER_ERR_FORMAT(parser, parser->
current.start, end, diag_id, (
int) (end - parser->
current.start), (
const char *) parser->
current.start);
8248 return PM_TOKEN_GLOBAL_VARIABLE;
8265static inline pm_token_type_t
8266lex_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) {
8267 if (memcmp(current_start, value, vlen) == 0) {
8270 if (parser->
lex_state & PM_LEX_STATE_FNAME) {
8271 lex_state_set(parser, PM_LEX_STATE_ENDFN);
8273 lex_state_set(parser, state);
8274 if (state == PM_LEX_STATE_BEG) {
8278 if ((modifier_type != PM_TOKEN_EOF) && !(last_state & (PM_LEX_STATE_BEG | PM_LEX_STATE_LABELED | PM_LEX_STATE_CLASS))) {
8279 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
8280 return modifier_type;
8287 return PM_TOKEN_EOF;
8290static pm_token_type_t
8291lex_identifier(
pm_parser_t *parser,
bool previous_command_start) {
8294 const uint8_t *end = parser->
end;
8295 const uint8_t *current_start = parser->
current.start;
8296 const uint8_t *current_end = parser->
current.end;
8299 if (encoding_changed) {
8300 while ((width = char_is_identifier(parser, current_end, end - current_end)) > 0) {
8301 current_end += width;
8304 while ((width = char_is_identifier_utf8(current_end, end - current_end)) > 0) {
8305 current_end += width;
8308 parser->
current.end = current_end;
8312 width = (size_t) (current_end - current_start);
8314 if (current_end < end) {
8315 if (((current_end + 1 >= end) || (current_end[1] !=
'=')) && (match(parser,
'!') || match(parser,
'?'))) {
8321 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8322 (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')
8326 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8327 (void) match(parser,
':');
8328 return PM_TOKEN_LABEL;
8331 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8332 if (width == 8 && (lex_keyword(parser, current_start,
"defined?", width, PM_LEX_STATE_ARG, PM_TOKEN_KEYWORD_DEFINED, PM_TOKEN_EOF) != PM_TOKEN_EOF)) {
8333 return PM_TOKEN_KEYWORD_DEFINED;
8337 return PM_TOKEN_METHOD_NAME;
8340 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,
'=')) {
8343 return PM_TOKEN_IDENTIFIER;
8347 ((lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser)) &&
8348 peek(parser) ==
':' && peek_offset(parser, 1) !=
':'
8352 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
8353 (void) match(parser,
':');
8354 return PM_TOKEN_LABEL;
8358 if (parser->
lex_state != PM_LEX_STATE_DOT) {
8359 pm_token_type_t
type;
8362 if (lex_keyword(parser, current_start,
"do", width, PM_LEX_STATE_BEG, PM_TOKEN_KEYWORD_DO, PM_TOKEN_EOF) != PM_TOKEN_EOF) {
8363 if (pm_do_loop_stack_p(parser)) {
8364 return PM_TOKEN_KEYWORD_DO_LOOP;
8366 return PM_TOKEN_KEYWORD_DO;
8369 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;
8370 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;
8371 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;
8374 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;
8375 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;
8376 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;
8377 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;
8378 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;
8379 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;
8380 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;
8383 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;
8384 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;
8385 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;
8386 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;
8387 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;
8388 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;
8389 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;
8390 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;
8393 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;
8394 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;
8395 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;
8396 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;
8397 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;
8398 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;
8399 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;
8400 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;
8401 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;
8402 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;
8403 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;
8404 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;
8405 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;
8408 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;
8409 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;
8410 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;
8411 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;
8412 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;
8415 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;
8416 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;
8419 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;
8424 if (encoding_changed) {
8425 return parser->
encoding->
isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8427 return pm_encoding_utf_8_isupper_char(current_start, end - current_start) ? PM_TOKEN_CONSTANT : PM_TOKEN_IDENTIFIER;
8453static pm_token_type_t
8454lex_interpolation(
pm_parser_t *parser,
const uint8_t *pound) {
8457 if (pound + 1 >= parser->
end) {
8458 parser->
current.end = pound + 1;
8459 return PM_TOKEN_STRING_CONTENT;
8468 if (pound + 2 >= parser->
end) {
8469 parser->
current.end = pound + 1;
8470 return PM_TOKEN_STRING_CONTENT;
8475 const uint8_t *variable = pound + 2;
8476 if (*variable ==
'@' && pound + 3 < parser->
end) variable++;
8478 if (char_is_identifier_start(parser, variable, parser->
end - variable)) {
8482 if (pound > parser->
current.start) {
8484 return PM_TOKEN_STRING_CONTENT;
8489 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8490 parser->
current.end = pound + 1;
8491 return PM_TOKEN_EMBVAR;
8497 parser->
current.end = pound + 1;
8498 return PM_TOKEN_NOT_PROVIDED;
8503 if (pound + 2 >= parser->
end) {
8504 parser->
current.end = pound + 1;
8505 return PM_TOKEN_STRING_CONTENT;
8511 const uint8_t *check = pound + 2;
8513 if (pound[2] ==
'-') {
8514 if (pound + 3 >= parser->
end) {
8515 parser->
current.end = pound + 2;
8516 return PM_TOKEN_STRING_CONTENT;
8527 char_is_identifier_start(parser, check, parser->
end - check) ||
8528 (pound[2] !=
'-' && (pm_char_is_decimal_digit(pound[2]) || char_is_global_name_punctuation(pound[2])))
8533 if (pound > parser->
current.start) {
8535 return PM_TOKEN_STRING_CONTENT;
8540 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBVAR });
8541 parser->
current.end = pound + 1;
8542 return PM_TOKEN_EMBVAR;
8547 parser->
current.end = pound + 1;
8548 return PM_TOKEN_NOT_PROVIDED;
8553 if (pound > parser->
current.start) {
8555 return PM_TOKEN_STRING_CONTENT;
8562 lex_mode_push(parser, (
pm_lex_mode_t) { .mode = PM_LEX_EMBEXPR });
8563 parser->
current.end = pound + 2;
8565 pm_do_loop_stack_push(parser,
false);
8566 return PM_TOKEN_EMBEXPR_BEGIN;
8571 parser->
current.end = pound + 1;
8572 return PM_TOKEN_NOT_PROVIDED;
8576static const uint8_t PM_ESCAPE_FLAG_NONE = 0x0;
8577static const uint8_t PM_ESCAPE_FLAG_CONTROL = 0x1;
8578static const uint8_t PM_ESCAPE_FLAG_META = 0x2;
8579static const uint8_t PM_ESCAPE_FLAG_SINGLE = 0x4;
8580static const uint8_t PM_ESCAPE_FLAG_REGEXP = 0x8;
8585static const bool ascii_printable_chars[] = {
8586 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0,
8587 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
8588 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8589 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8590 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
8591 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
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, 0
8597char_is_ascii_printable(
const uint8_t b) {
8598 return (b < 0x80) && ascii_printable_chars[b];
8605static inline uint8_t
8606escape_hexadecimal_digit(
const uint8_t value) {
8607 return (uint8_t) ((value <=
'9') ? (value -
'0') : (value & 0x7) + 9);
8615static inline uint32_t
8618 for (
size_t index = 0; index < length; index++) {
8619 if (index != 0) value <<= 4;
8620 value |= escape_hexadecimal_digit(
string[index]);
8625 if (value >= 0xD800 && value <= 0xDFFF) {
8626 if (error_location != NULL) {
8627 pm_parser_err(parser, error_location->
start, error_location->
end, PM_ERR_ESCAPE_INVALID_UNICODE);
8629 pm_parser_err(parser,
string,
string + length, PM_ERR_ESCAPE_INVALID_UNICODE);
8640static inline uint8_t
8641escape_byte(uint8_t value,
const uint8_t flags) {
8642 if (flags & PM_ESCAPE_FLAG_CONTROL) value &= 0x9f;
8643 if (flags & PM_ESCAPE_FLAG_META) value |= 0x80;
8651escape_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) {
8655 if (value >= 0x80 || flags & PM_ESCAPE_FLAG_SINGLE) {
8663 if (!pm_buffer_append_unicode_codepoint(buffer, value)) {
8664 pm_parser_err(parser, start, end, PM_ERR_ESCAPE_INVALID_UNICODE);
8665 pm_buffer_append_byte(buffer, 0xEF);
8666 pm_buffer_append_byte(buffer, 0xBF);
8667 pm_buffer_append_byte(buffer, 0xBD);
8679 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_MIXED_ENCODING, parser->
encoding->
name);
8685 pm_buffer_append_byte(buffer,
byte);
8705 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8706 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X",
byte);
8709 escape_write_byte_encoded(parser, buffer,
byte);
8721 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
8725 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(*parser->
current.end++, flags));
8726 }
else if (width > 1) {
8728 pm_buffer_t *b = (flags & PM_ESCAPE_FLAG_REGEXP) ? regular_expression_buffer : buffer;
8729 pm_buffer_append_bytes(b, parser->
current.end, width);
8735 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
8745escape_read_warn(
pm_parser_t *parser, uint8_t flags, uint8_t flag,
const char *
type) {
8746#define FLAG(value) ((value & PM_ESCAPE_FLAG_CONTROL) ? "\\C-" : (value & PM_ESCAPE_FLAG_META) ? "\\M-" : "")
8748 PM_PARSER_WARN_TOKEN_FORMAT(
8751 PM_WARN_INVALID_CHARACTER,
8765 uint8_t peeked = peek(parser);
8769 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\\', flags));
8774 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\'', flags));
8779 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\a', flags));
8784 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\b', flags));
8789 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\033', flags));
8794 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\f', flags));
8799 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\n', flags));
8804 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\r', flags));
8809 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
' ', flags));
8814 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\t', flags));
8819 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(
'\v', flags));
8822 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7': {
8823 uint8_t value = (uint8_t) (*parser->
current.end -
'0');
8826 if (pm_char_is_octal_digit(peek(parser))) {
8827 value = ((uint8_t) (value << 3)) | ((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'));
8836 value = escape_byte(value, flags);
8837 escape_write_byte(parser, buffer, regular_expression_buffer, flags, value);
8841 const uint8_t *start = parser->
current.end - 1;
8844 uint8_t
byte = peek(parser);
8846 if (pm_char_is_hexadecimal_digit(
byte)) {
8847 uint8_t value = escape_hexadecimal_digit(
byte);
8850 byte = peek(parser);
8851 if (pm_char_is_hexadecimal_digit(
byte)) {
8852 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(
byte));
8856 value = escape_byte(value, flags);
8857 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8858 if (flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) {
8859 pm_buffer_append_format(regular_expression_buffer,
"\\x%02X", value);
8861 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8865 escape_write_byte_encoded(parser, buffer, value);
8867 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_HEXADECIMAL);
8873 const uint8_t *start = parser->
current.end - 1;
8877 const uint8_t *start = parser->
current.end - 2;
8878 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8879 }
else if (peek(parser) ==
'{') {
8880 const uint8_t *unicode_codepoints_start = parser->
current.end - 2;
8885 if ((whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end)) > 0) {
8886 parser->
current.end += whitespace;
8887 }
else if (peek(parser) ==
'\\' && peek_offset(parser, 1) ==
'n') {
8898 const uint8_t *extra_codepoints_start = NULL;
8899 int codepoints_count = 0;
8902 const uint8_t *unicode_start = parser->
current.end;
8903 size_t hexadecimal_length = pm_strspn_hexadecimal_digit(parser->
current.end, parser->
end - parser->
current.end);
8905 if (hexadecimal_length > 6) {
8907 pm_parser_err(parser, unicode_start, unicode_start + hexadecimal_length, PM_ERR_ESCAPE_INVALID_UNICODE_LONG);
8908 }
else if (hexadecimal_length == 0) {
8911 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8915 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8917 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE);
8918 pm_parser_err(parser, parser->
current.end, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8924 parser->
current.end += hexadecimal_length;
8926 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count == 2) {
8927 extra_codepoints_start = unicode_start;
8930 uint32_t value = escape_unicode(parser, unicode_start, hexadecimal_length, NULL);
8931 escape_write_unicode(parser, buffer, flags, unicode_start, parser->
current.end, value);
8938 if (flags & PM_ESCAPE_FLAG_SINGLE && codepoints_count > 1) {
8939 pm_parser_err(parser, extra_codepoints_start, parser->
current.end - 1, PM_ERR_ESCAPE_INVALID_UNICODE_LITERAL);
8943 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_LIST, (
int) (parser->
current.end - start), start);
8944 }
else if (peek(parser) ==
'}') {
8947 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8951 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8953 pm_parser_err(parser, unicode_codepoints_start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_TERM);
8957 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8958 pm_buffer_append_bytes(regular_expression_buffer, unicode_codepoints_start, (
size_t) (parser->
current.end - unicode_codepoints_start));
8961 size_t length = pm_strspn_hexadecimal_digit(parser->
current.end, MIN(parser->
end - parser->
current.end, 4));
8964 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8965 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8967 const uint8_t *start = parser->
current.end - 2;
8968 PM_PARSER_ERR_FORMAT(parser, start, parser->
current.end, PM_ERR_ESCAPE_INVALID_UNICODE_SHORT, 2, start);
8970 }
else if (length == 4) {
8971 uint32_t value = escape_unicode(parser, parser->
current.end, 4, NULL);
8973 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8974 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end + 4 - start));
8977 escape_write_unicode(parser, buffer, flags, start, parser->
current.end + 4, value);
8980 parser->
current.end += length;
8982 if (flags & PM_ESCAPE_FLAG_REGEXP) {
8986 pm_buffer_append_bytes(regular_expression_buffer, start, (
size_t) (parser->
current.end - start));
8988 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_UNICODE);
8997 if (flags & PM_ESCAPE_FLAG_CONTROL) {
8998 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9002 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9006 uint8_t peeked = peek(parser);
9010 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9016 if (match(parser,
'u') || match(parser,
'U')) {
9017 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9021 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9025 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9026 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9030 escape_read_warn(parser, flags, 0,
"\\t");
9031 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9034 if (!char_is_ascii_printable(peeked)) {
9035 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9040 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9047 if (flags & PM_ESCAPE_FLAG_CONTROL) {
9048 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL_REPEAT);
9051 if (peek(parser) !=
'-') {
9053 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9059 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_CONTROL);
9063 uint8_t peeked = peek(parser);
9067 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(0x7f, flags));
9073 if (match(parser,
'u') || match(parser,
'U')) {
9074 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9078 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_CONTROL);
9082 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_CONTROL,
"\\s");
9083 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9087 escape_read_warn(parser, flags, 0,
"\\t");
9088 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9091 if (!char_is_ascii_printable(peeked)) {
9093 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_CONTROL);
9098 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_CONTROL));
9105 if (flags & PM_ESCAPE_FLAG_META) {
9106 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META_REPEAT);
9109 if (peek(parser) !=
'-') {
9111 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9117 pm_parser_err_current(parser, PM_ERR_ESCAPE_INVALID_META);
9121 uint8_t peeked = peek(parser);
9126 if (match(parser,
'u') || match(parser,
'U')) {
9127 pm_parser_err(parser, parser->
current.start, parser->
current.end, PM_ERR_INVALID_ESCAPE_CHARACTER);
9131 escape_read(parser, buffer, regular_expression_buffer, flags | PM_ESCAPE_FLAG_META);
9135 escape_read_warn(parser, flags, PM_ESCAPE_FLAG_META,
"\\s");
9136 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9140 escape_read_warn(parser, flags & ((uint8_t) ~PM_ESCAPE_FLAG_CONTROL), PM_ESCAPE_FLAG_META,
"\\t");
9141 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9144 if (!char_is_ascii_printable(peeked)) {
9146 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9151 escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte(peeked, flags | PM_ESCAPE_FLAG_META));
9156 if (peek_offset(parser, 1) ==
'\n') {
9158 escape_write_byte_encoded(parser, buffer, escape_byte(
'\n', flags));
9164 if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
9166 pm_parser_err(parser, parser->
current.start, parser->
current.end + width, PM_ERR_ESCAPE_INVALID_META);
9170 escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
9172 pm_parser_err_current(parser, PM_ERR_INVALID_ESCAPE_CHARACTER);
9204static pm_token_type_t
9206 if (lex_state_end_p(parser)) {
9207 lex_state_set(parser, PM_LEX_STATE_BEG);
9208 return PM_TOKEN_QUESTION_MARK;
9212 pm_parser_err_current(parser, PM_ERR_INCOMPLETE_QUESTION_MARK);
9214 return PM_TOKEN_CHARACTER_LITERAL;
9217 if (pm_char_is_whitespace(*parser->
current.end)) {
9218 lex_state_set(parser, PM_LEX_STATE_BEG);
9219 return PM_TOKEN_QUESTION_MARK;
9222 lex_state_set(parser, PM_LEX_STATE_BEG);
9224 if (match(parser,
'\\')) {
9225 lex_state_set(parser, PM_LEX_STATE_END);
9228 pm_buffer_init_capacity(&buffer, 3);
9230 escape_read(parser, &buffer, NULL, PM_ESCAPE_FLAG_SINGLE);
9233 return PM_TOKEN_CHARACTER_LITERAL;
9242 (parser->
current.end + encoding_width >= parser->
end) ||
9243 !char_is_identifier(parser, parser->
current.end + encoding_width, parser->
end - (parser->
current.end + encoding_width))
9246 lex_state_set(parser, PM_LEX_STATE_END);
9247 parser->
current.end += encoding_width;
9249 return PM_TOKEN_CHARACTER_LITERAL;
9253 return PM_TOKEN_QUESTION_MARK;
9260static pm_token_type_t
9262 pm_token_type_t
type = match(parser,
'@') ? PM_TOKEN_CLASS_VARIABLE : PM_TOKEN_INSTANCE_VARIABLE;
9263 const uint8_t *end = parser->
end;
9266 if ((width = char_is_identifier_start(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9269 while ((width = char_is_identifier(parser, parser->
current.end, end - parser->
current.end)) > 0) {
9272 }
else if (parser->
current.end < end && pm_char_is_decimal_digit(*parser->
current.end)) {
9273 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE;
9275 diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_INCOMPLETE_VARIABLE_CLASS_3_3 : PM_ERR_INCOMPLETE_VARIABLE_INSTANCE_3_3;
9279 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, diag_id, (
int) ((parser->
current.end + width) - parser->
current.start), (
const char *) parser->
current.start);
9281 pm_diagnostic_id_t diag_id = (
type == PM_TOKEN_CLASS_VARIABLE) ? PM_ERR_CLASS_VARIABLE_BARE : PM_ERR_INSTANCE_VARIABLE_BARE;
9282 pm_parser_err_token(parser, &parser->
current, diag_id);
9288 lex_mode_pop(parser);
9310 if (comment == NULL)
return NULL;
9325static pm_token_type_t
9328 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9330 if (newline == NULL) {
9333 pm_newline_list_append(&parser->
newline_list, newline);
9334 parser->
current.end = newline + 1;
9337 parser->
current.type = PM_TOKEN_EMBDOC_BEGIN;
9338 parser_lex_callback(parser);
9341 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_EMBDOC);
9342 if (comment == NULL)
return PM_TOKEN_EOF;
9346 while (parser->
current.end + 4 <= parser->
end) {
9352 (memcmp(parser->
current.end,
"=end", 4) == 0) &&
9355 pm_char_is_whitespace(parser->
current.end[4]) ||
9356 (parser->
current.end[4] ==
'\0') ||
9357 (parser->
current.end[4] ==
'\004') ||
9358 (parser->
current.end[4] ==
'\032')
9361 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9363 if (newline == NULL) {
9366 pm_newline_list_append(&parser->
newline_list, newline);
9367 parser->
current.end = newline + 1;
9370 parser->
current.type = PM_TOKEN_EMBDOC_END;
9371 parser_lex_callback(parser);
9376 return PM_TOKEN_EMBDOC_END;
9381 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9383 if (newline == NULL) {
9386 pm_newline_list_append(&parser->
newline_list, newline);
9387 parser->
current.end = newline + 1;
9390 parser->
current.type = PM_TOKEN_EMBDOC_LINE;
9391 parser_lex_callback(parser);
9394 pm_parser_err_current(parser, PM_ERR_EMBDOC_TERM);
9399 return PM_TOKEN_EOF;
9409 parser->
current.type = PM_TOKEN_IGNORED_NEWLINE;
9410 parser_lex_callback(parser);
9434 const uint8_t *cursor = parser->
current.end;
9436 while (cursor < parser->end && *cursor !=
'\n' && *cursor !=
'#') {
9437 if (!pm_char_is_inline_whitespace(*cursor++))
return false;
9500 pm_buffer_append_byte(&token_buffer->
buffer,
byte);
9517 width = pm_encoding_utf_8_char_width(parser->
current.end, parser->
end - parser->
current.end);
9522 return (width == 0 ? 1 : width);
9530 size_t width = parser_char_width(parser);
9531 pm_buffer_append_bytes(&token_buffer->
buffer, parser->
current.end, width);
9537 size_t width = parser_char_width(parser);
9544pm_slice_ascii_only_p(
const uint8_t *value,
size_t length) {
9545 for (
size_t index = 0; index < length; index++) {
9546 if (value[index] & 0x80)
return false;
9581 if (token_buffer->
cursor == NULL) {
9584 pm_buffer_append_bytes(&token_buffer->
buffer, token_buffer->
cursor, (
size_t) (parser->
current.end - token_buffer->
cursor));
9585 pm_token_buffer_copy(parser, token_buffer);
9597 pm_regexp_token_buffer_copy(parser, token_buffer);
9601#define PM_TOKEN_BUFFER_DEFAULT_SIZE 16
9613 const uint8_t *start;
9614 if (token_buffer->
cursor == NULL) {
9615 pm_buffer_init_capacity(&token_buffer->
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9616 start = parser->
current.start;
9618 start = token_buffer->
cursor;
9621 const uint8_t *end = parser->
current.end - 1;
9622 assert(end >= start);
9623 pm_buffer_append_bytes(&token_buffer->
buffer, start, (
size_t) (end - start));
9625 token_buffer->
cursor = end;
9630 const uint8_t *start;
9632 pm_buffer_init_capacity(&token_buffer->
base.
buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9633 pm_buffer_init_capacity(&token_buffer->
regexp_buffer, PM_TOKEN_BUFFER_DEFAULT_SIZE);
9634 start = parser->
current.start;
9639 const uint8_t *end = parser->
current.end - 1;
9640 pm_buffer_append_bytes(&token_buffer->
base.
buffer, start, (
size_t) (end - start));
9641 pm_buffer_append_bytes(&token_buffer->
regexp_buffer, start, (
size_t) (end - start));
9646#undef PM_TOKEN_BUFFER_DEFAULT_SIZE
9654 size_t whitespace = 0;
9657 case PM_HEREDOC_INDENT_NONE:
9662 case PM_HEREDOC_INDENT_DASH:
9664 *cursor += pm_strspn_inline_whitespace(*cursor, parser->
end - *cursor);
9666 case PM_HEREDOC_INDENT_TILDE:
9669 while (*cursor < parser->end && pm_char_is_inline_whitespace(**cursor)) {
9670 if (**cursor ==
'\t') {
9671 whitespace = (whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
9690 size_t eol_length = match_eol(parser);
9697 parser_flush_heredoc_end(parser);
9703 uint8_t delimiter = *parser->
current.end;
9707 if (eol_length == 2) {
9708 delimiter = *(parser->
current.end + 1);
9711 parser->
current.end += eol_length;
9715 return *parser->
current.end++;
9722#define LEX(token_type) parser->current.type = token_type; parser_lex_callback(parser); return
9741 bool lexed_comment =
false;
9749 case PM_LEX_DEFAULT:
9750 case PM_LEX_EMBEXPR:
9767 bool space_seen =
false;
9771 bool chomping =
true;
9772 while (parser->
current.end < parser->
end && chomping) {
9773 switch (*parser->
current.end) {
9782 if (match_eol_offset(parser, 1)) {
9785 pm_parser_warn(parser, parser->
current.end, parser->
current.end + 1, PM_WARN_UNEXPECTED_CARRIAGE_RETURN);
9791 size_t eol_length = match_eol_offset(parser, 1);
9797 parser->
current.end += eol_length + 1;
9801 }
else if (pm_char_is_inline_whitespace(*parser->
current.end)) {
9834 switch (*parser->
current.end++) {
9842 const uint8_t *ending = next_newline(parser->
current.end, parser->
end - parser->
current.end);
9843 parser->
current.end = ending == NULL ? parser->
end : ending;
9848 pm_comment_t *comment = parser_comment(parser, PM_COMMENT_INLINE);
9851 if (ending) parser->
current.end++;
9852 parser->
current.type = PM_TOKEN_COMMENT;
9853 parser_lex_callback(parser);
9865 parser_lex_magic_comment_encoding(parser);
9869 lexed_comment =
true;
9875 size_t eol_length = match_eol_at(parser, parser->
current.end - 1);
9887 if (!lexed_comment) {
9888 parser->
current.end += eol_length - 1;
9897 parser_flush_heredoc_end(parser);
9902 switch (lex_state_ignored_p(parser)) {
9903 case PM_IGNORED_NEWLINE_NONE:
9905 case PM_IGNORED_NEWLINE_PATTERN:
9907 if (!lexed_comment) parser_lex_ignored_newline(parser);
9908 lex_state_set(parser, PM_LEX_STATE_BEG);
9910 parser->
current.type = PM_TOKEN_NEWLINE;
9914 case PM_IGNORED_NEWLINE_ALL:
9915 if (!lexed_comment) parser_lex_ignored_newline(parser);
9916 lexed_comment =
false;
9917 goto lex_next_token;
9925 next_content += pm_strspn_inline_whitespace(next_content, parser->
end - next_content);
9927 if (next_content < parser->end) {
9933 if (next_content[0] ==
'#') {
9935 const uint8_t *following = next_newline(next_content, parser->
end - next_content);
9937 while (following && (following + 1 < parser->
end)) {
9939 following += pm_strspn_inline_whitespace(following, parser->
end - following);
9943 if (peek_at(parser, following) !=
'#')
break;
9947 following = next_newline(following, parser->
end - following);
9952 if (lex_state_ignored_p(parser)) {
9953 if (!lexed_comment) parser_lex_ignored_newline(parser);
9954 lexed_comment =
false;
9955 goto lex_next_token;
9961 (peek_at(parser, following) ==
'.') ||
9962 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'.')
9964 if (!lexed_comment) parser_lex_ignored_newline(parser);
9965 lexed_comment =
false;
9966 goto lex_next_token;
9976 (peek_at(parser, following) ==
'&' && peek_at(parser, following + 1) ==
'&') ||
9977 (peek_at(parser, following) ==
'|' && peek_at(parser, following + 1) ==
'|') ||
9978 (peek_at(parser, following) ==
'a' && peek_at(parser, following + 1) ==
'n' && peek_at(parser, following + 2) ==
'd' && !char_is_identifier(parser, following + 3, parser->
end - (following + 3))) ||
9979 (peek_at(parser, following) ==
'o' && peek_at(parser, following + 1) ==
'r' && !char_is_identifier(parser, following + 2, parser->
end - (following + 2)))
9982 if (!lexed_comment) parser_lex_ignored_newline(parser);
9983 lexed_comment =
false;
9984 goto lex_next_token;
9990 if (next_content[0] ==
'.') {
9994 if (peek_at(parser, next_content + 1) ==
'.') {
9995 if (!lexed_comment) parser_lex_ignored_newline(parser);
9996 lex_state_set(parser, PM_LEX_STATE_BEG);
9998 parser->
current.type = PM_TOKEN_NEWLINE;
10002 if (!lexed_comment) parser_lex_ignored_newline(parser);
10003 lex_state_set(parser, PM_LEX_STATE_DOT);
10004 parser->
current.start = next_content;
10005 parser->
current.end = next_content + 1;
10012 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'.') {
10013 if (!lexed_comment) parser_lex_ignored_newline(parser);
10014 lex_state_set(parser, PM_LEX_STATE_DOT);
10015 parser->
current.start = next_content;
10016 parser->
current.end = next_content + 2;
10018 LEX(PM_TOKEN_AMPERSAND_DOT);
10024 if (peek_at(parser, next_content) ==
'&' && peek_at(parser, next_content + 1) ==
'&') {
10025 if (!lexed_comment) parser_lex_ignored_newline(parser);
10026 lex_state_set(parser, PM_LEX_STATE_BEG);
10027 parser->
current.start = next_content;
10028 parser->
current.end = next_content + 2;
10030 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10035 if (peek_at(parser, next_content) ==
'|' && peek_at(parser, next_content + 1) ==
'|') {
10036 if (!lexed_comment) parser_lex_ignored_newline(parser);
10037 lex_state_set(parser, PM_LEX_STATE_BEG);
10038 parser->
current.start = next_content;
10039 parser->
current.end = next_content + 2;
10041 LEX(PM_TOKEN_PIPE_PIPE);
10047 peek_at(parser, next_content) ==
'a' &&
10048 peek_at(parser, next_content + 1) ==
'n' &&
10049 peek_at(parser, next_content + 2) ==
'd' &&
10050 !char_is_identifier(parser, next_content + 3, parser->
end - (next_content + 3))
10052 if (!lexed_comment) parser_lex_ignored_newline(parser);
10053 lex_state_set(parser, PM_LEX_STATE_BEG);
10054 parser->
current.start = next_content;
10055 parser->
current.end = next_content + 3;
10058 LEX(PM_TOKEN_KEYWORD_AND);
10064 peek_at(parser, next_content) ==
'o' &&
10065 peek_at(parser, next_content + 1) ==
'r' &&
10066 !char_is_identifier(parser, next_content + 2, parser->
end - (next_content + 2))
10068 if (!lexed_comment) parser_lex_ignored_newline(parser);
10069 lex_state_set(parser, PM_LEX_STATE_BEG);
10070 parser->
current.start = next_content;
10071 parser->
current.end = next_content + 2;
10074 LEX(PM_TOKEN_KEYWORD_OR);
10081 lex_state_set(parser, PM_LEX_STATE_BEG);
10083 parser->
current.type = PM_TOKEN_NEWLINE;
10084 if (!lexed_comment) parser_lex_callback(parser);
10094 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10095 LEX(PM_TOKEN_COMMA);
10099 pm_token_type_t
type = PM_TOKEN_PARENTHESIS_LEFT;
10101 if (space_seen && (lex_state_arg_p(parser) || parser->
lex_state == (PM_LEX_STATE_END | PM_LEX_STATE_LABEL))) {
10102 type = PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES;
10106 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10107 pm_do_loop_stack_push(parser,
false);
10114 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10115 pm_do_loop_stack_pop(parser);
10116 LEX(PM_TOKEN_PARENTHESIS_RIGHT);
10120 lex_state_set(parser, PM_LEX_STATE_BEG);
10122 LEX(PM_TOKEN_SEMICOLON);
10127 pm_token_type_t
type = PM_TOKEN_BRACKET_LEFT;
10129 if (lex_state_operator_p(parser)) {
10130 if (match(parser,
']')) {
10132 lex_state_set(parser, PM_LEX_STATE_ARG);
10133 LEX(match(parser,
'=') ? PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL : PM_TOKEN_BRACKET_LEFT_RIGHT);
10136 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABEL);
10140 if (lex_state_beg_p(parser) || (lex_state_arg_p(parser) && (space_seen || lex_state_p(parser, PM_LEX_STATE_LABELED)))) {
10141 type = PM_TOKEN_BRACKET_LEFT_ARRAY;
10144 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10145 pm_do_loop_stack_push(parser,
false);
10151 lex_state_set(parser, PM_LEX_STATE_END);
10152 pm_do_loop_stack_pop(parser);
10153 LEX(PM_TOKEN_BRACKET_RIGHT);
10157 pm_token_type_t
type = PM_TOKEN_BRACE_LEFT;
10162 lex_state_set(parser, PM_LEX_STATE_BEG);
10163 type = PM_TOKEN_LAMBDA_BEGIN;
10164 }
else if (lex_state_p(parser, PM_LEX_STATE_LABELED)) {
10166 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10167 }
else if (lex_state_p(parser, PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_END | PM_LEX_STATE_ENDFN)) {
10170 lex_state_set(parser, PM_LEX_STATE_BEG);
10171 }
else if (lex_state_p(parser, PM_LEX_STATE_ENDARG)) {
10174 lex_state_set(parser, PM_LEX_STATE_BEG);
10177 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10182 pm_do_loop_stack_push(parser,
false);
10190 pm_do_loop_stack_pop(parser);
10193 lex_mode_pop(parser);
10194 LEX(PM_TOKEN_EMBEXPR_END);
10198 lex_state_set(parser, PM_LEX_STATE_END);
10199 LEX(PM_TOKEN_BRACE_RIGHT);
10203 if (match(parser,
'*')) {
10204 if (match(parser,
'=')) {
10205 lex_state_set(parser, PM_LEX_STATE_BEG);
10206 LEX(PM_TOKEN_STAR_STAR_EQUAL);
10209 pm_token_type_t
type = PM_TOKEN_STAR_STAR;
10211 if (lex_state_spcarg_p(parser, space_seen)) {
10212 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR_STAR);
10213 type = PM_TOKEN_USTAR_STAR;
10214 }
else if (lex_state_beg_p(parser)) {
10215 type = PM_TOKEN_USTAR_STAR;
10216 }
else if (ambiguous_operator_p(parser, space_seen)) {
10217 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"**",
"argument prefix");
10220 if (lex_state_operator_p(parser)) {
10221 lex_state_set(parser, PM_LEX_STATE_ARG);
10223 lex_state_set(parser, PM_LEX_STATE_BEG);
10229 if (match(parser,
'=')) {
10230 lex_state_set(parser, PM_LEX_STATE_BEG);
10231 LEX(PM_TOKEN_STAR_EQUAL);
10234 pm_token_type_t
type = PM_TOKEN_STAR;
10236 if (lex_state_spcarg_p(parser, space_seen)) {
10237 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_STAR);
10238 type = PM_TOKEN_USTAR;
10239 }
else if (lex_state_beg_p(parser)) {
10240 type = PM_TOKEN_USTAR;
10241 }
else if (ambiguous_operator_p(parser, space_seen)) {
10242 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"*",
"argument prefix");
10245 if (lex_state_operator_p(parser)) {
10246 lex_state_set(parser, PM_LEX_STATE_ARG);
10248 lex_state_set(parser, PM_LEX_STATE_BEG);
10256 if (lex_state_operator_p(parser)) {
10257 lex_state_set(parser, PM_LEX_STATE_ARG);
10258 if (match(parser,
'@')) {
10259 LEX(PM_TOKEN_BANG);
10262 lex_state_set(parser, PM_LEX_STATE_BEG);
10265 if (match(parser,
'=')) {
10266 LEX(PM_TOKEN_BANG_EQUAL);
10269 if (match(parser,
'~')) {
10270 LEX(PM_TOKEN_BANG_TILDE);
10273 LEX(PM_TOKEN_BANG);
10278 current_token_starts_line(parser) &&
10280 memcmp(parser->
current.end,
"begin", 5) == 0 &&
10281 (pm_char_is_whitespace(peek_offset(parser, 5)) || (peek_offset(parser, 5) ==
'\0'))
10283 pm_token_type_t
type = lex_embdoc(parser);
10284 if (
type == PM_TOKEN_EOF) {
10288 goto lex_next_token;
10291 if (lex_state_operator_p(parser)) {
10292 lex_state_set(parser, PM_LEX_STATE_ARG);
10294 lex_state_set(parser, PM_LEX_STATE_BEG);
10297 if (match(parser,
'>')) {
10298 LEX(PM_TOKEN_EQUAL_GREATER);
10301 if (match(parser,
'~')) {
10302 LEX(PM_TOKEN_EQUAL_TILDE);
10305 if (match(parser,
'=')) {
10306 LEX(match(parser,
'=') ? PM_TOKEN_EQUAL_EQUAL_EQUAL : PM_TOKEN_EQUAL_EQUAL);
10309 LEX(PM_TOKEN_EQUAL);
10313 if (match(parser,
'<')) {
10315 !lex_state_p(parser, PM_LEX_STATE_DOT | PM_LEX_STATE_CLASS) &&
10316 !lex_state_end_p(parser) &&
10317 (!lex_state_p(parser, PM_LEX_STATE_ARG_ANY) || lex_state_p(parser, PM_LEX_STATE_LABELED) || space_seen)
10319 const uint8_t *end = parser->
current.end;
10324 if (match(parser,
'-')) {
10325 indent = PM_HEREDOC_INDENT_DASH;
10327 else if (match(parser,
'~')) {
10328 indent = PM_HEREDOC_INDENT_TILDE;
10331 if (match(parser,
'`')) {
10332 quote = PM_HEREDOC_QUOTE_BACKTICK;
10334 else if (match(parser,
'"')) {
10335 quote = PM_HEREDOC_QUOTE_DOUBLE;
10337 else if (match(parser,
'\'')) {
10338 quote = PM_HEREDOC_QUOTE_SINGLE;
10341 const uint8_t *ident_start = parser->
current.end;
10346 }
else if (quote == PM_HEREDOC_QUOTE_NONE && (width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end)) == 0) {
10349 if (quote == PM_HEREDOC_QUOTE_NONE) {
10350 parser->
current.end += width;
10352 while ((width = char_is_identifier(parser, parser->
current.end, parser->
end - parser->
current.end))) {
10353 parser->
current.end += width;
10359 if (*parser->
current.end ==
'\r' || *parser->
current.end ==
'\n')
break;
10364 size_t ident_length = (size_t) (parser->
current.end - ident_start);
10365 bool ident_error =
false;
10367 if (quote != PM_HEREDOC_QUOTE_NONE && !match(parser, (uint8_t) quote)) {
10368 pm_parser_err(parser, ident_start, ident_start + ident_length, PM_ERR_HEREDOC_IDENTIFIER);
10369 ident_error =
true;
10374 .mode = PM_LEX_HEREDOC,
10377 .ident_start = ident_start,
10378 .ident_length = ident_length,
10382 .next_start = parser->
current.end,
10384 .line_continuation =
false
10389 const uint8_t *body_start = next_newline(parser->
current.end, parser->
end - parser->
current.end);
10391 if (body_start == NULL) {
10396 if (!ident_error) pm_parser_err_heredoc_term(parser, ident_start, ident_length);
10397 body_start = parser->
end;
10401 pm_newline_list_append(&parser->
newline_list, body_start);
10410 LEX(PM_TOKEN_HEREDOC_START);
10414 if (match(parser,
'=')) {
10415 lex_state_set(parser, PM_LEX_STATE_BEG);
10416 LEX(PM_TOKEN_LESS_LESS_EQUAL);
10419 if (ambiguous_operator_p(parser, space_seen)) {
10420 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"<<",
"here document");
10423 if (lex_state_operator_p(parser)) {
10424 lex_state_set(parser, PM_LEX_STATE_ARG);
10426 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10427 lex_state_set(parser, PM_LEX_STATE_BEG);
10430 LEX(PM_TOKEN_LESS_LESS);
10433 if (lex_state_operator_p(parser)) {
10434 lex_state_set(parser, PM_LEX_STATE_ARG);
10436 if (lex_state_p(parser, PM_LEX_STATE_CLASS)) parser->
command_start =
true;
10437 lex_state_set(parser, PM_LEX_STATE_BEG);
10440 if (match(parser,
'=')) {
10441 if (match(parser,
'>')) {
10442 LEX(PM_TOKEN_LESS_EQUAL_GREATER);
10445 LEX(PM_TOKEN_LESS_EQUAL);
10448 LEX(PM_TOKEN_LESS);
10452 if (match(parser,
'>')) {
10453 if (lex_state_operator_p(parser)) {
10454 lex_state_set(parser, PM_LEX_STATE_ARG);
10456 lex_state_set(parser, PM_LEX_STATE_BEG);
10458 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_GREATER_EQUAL : PM_TOKEN_GREATER_GREATER);
10461 if (lex_state_operator_p(parser)) {
10462 lex_state_set(parser, PM_LEX_STATE_ARG);
10464 lex_state_set(parser, PM_LEX_STATE_BEG);
10467 LEX(match(parser,
'=') ? PM_TOKEN_GREATER_EQUAL : PM_TOKEN_GREATER);
10471 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10472 lex_mode_push_string(parser,
true, label_allowed,
'\0',
'"');
10473 LEX(PM_TOKEN_STRING_BEGIN);
10478 if (lex_state_p(parser, PM_LEX_STATE_FNAME)) {
10479 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10480 LEX(PM_TOKEN_BACKTICK);
10483 if (lex_state_p(parser, PM_LEX_STATE_DOT)) {
10484 if (previous_command_start) {
10485 lex_state_set(parser, PM_LEX_STATE_CMDARG);
10487 lex_state_set(parser, PM_LEX_STATE_ARG);
10490 LEX(PM_TOKEN_BACKTICK);
10493 lex_mode_push_string(parser,
true,
false,
'\0',
'`');
10494 LEX(PM_TOKEN_BACKTICK);
10499 bool label_allowed = (lex_state_p(parser, PM_LEX_STATE_LABEL | PM_LEX_STATE_ENDFN) && !previous_command_start) || lex_state_arg_p(parser);
10500 lex_mode_push_string(parser,
false, label_allowed,
'\0',
'\'');
10501 LEX(PM_TOKEN_STRING_BEGIN);
10506 LEX(lex_question_mark(parser));
10510 if (match(parser,
'&')) {
10511 lex_state_set(parser, PM_LEX_STATE_BEG);
10513 if (match(parser,
'=')) {
10514 LEX(PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL);
10517 LEX(PM_TOKEN_AMPERSAND_AMPERSAND);
10520 if (match(parser,
'=')) {
10521 lex_state_set(parser, PM_LEX_STATE_BEG);
10522 LEX(PM_TOKEN_AMPERSAND_EQUAL);
10525 if (match(parser,
'.')) {
10526 lex_state_set(parser, PM_LEX_STATE_DOT);
10527 LEX(PM_TOKEN_AMPERSAND_DOT);
10530 pm_token_type_t
type = PM_TOKEN_AMPERSAND;
10531 if (lex_state_spcarg_p(parser, space_seen)) {
10532 if ((peek(parser) !=
':') || (peek_offset(parser, 1) ==
'\0')) {
10533 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10535 const uint8_t delim = peek_offset(parser, 1);
10537 if ((delim !=
'\'') && (delim !=
'"') && !char_is_identifier(parser, parser->
current.end + 1, parser->
end - (parser->
current.end + 1))) {
10538 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_PREFIX_AMPERSAND);
10542 type = PM_TOKEN_UAMPERSAND;
10543 }
else if (lex_state_beg_p(parser)) {
10544 type = PM_TOKEN_UAMPERSAND;
10545 }
else if (ambiguous_operator_p(parser, space_seen)) {
10546 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"&",
"argument prefix");
10549 if (lex_state_operator_p(parser)) {
10550 lex_state_set(parser, PM_LEX_STATE_ARG);
10552 lex_state_set(parser, PM_LEX_STATE_BEG);
10560 if (match(parser,
'|')) {
10561 if (match(parser,
'=')) {
10562 lex_state_set(parser, PM_LEX_STATE_BEG);
10563 LEX(PM_TOKEN_PIPE_PIPE_EQUAL);
10566 if (lex_state_p(parser, PM_LEX_STATE_BEG)) {
10568 LEX(PM_TOKEN_PIPE);
10571 lex_state_set(parser, PM_LEX_STATE_BEG);
10572 LEX(PM_TOKEN_PIPE_PIPE);
10575 if (match(parser,
'=')) {
10576 lex_state_set(parser, PM_LEX_STATE_BEG);
10577 LEX(PM_TOKEN_PIPE_EQUAL);
10580 if (lex_state_operator_p(parser)) {
10581 lex_state_set(parser, PM_LEX_STATE_ARG);
10583 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
10586 LEX(PM_TOKEN_PIPE);
10590 if (lex_state_operator_p(parser)) {
10591 lex_state_set(parser, PM_LEX_STATE_ARG);
10593 if (match(parser,
'@')) {
10594 LEX(PM_TOKEN_UPLUS);
10597 LEX(PM_TOKEN_PLUS);
10600 if (match(parser,
'=')) {
10601 lex_state_set(parser, PM_LEX_STATE_BEG);
10602 LEX(PM_TOKEN_PLUS_EQUAL);
10606 lex_state_beg_p(parser) ||
10607 (lex_state_spcarg_p(parser, space_seen) ? (pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_PLUS),
true) : false)
10609 lex_state_set(parser, PM_LEX_STATE_BEG);
10611 if (pm_char_is_decimal_digit(peek(parser))) {
10613 pm_token_type_t
type = lex_numeric(parser);
10614 lex_state_set(parser, PM_LEX_STATE_END);
10618 LEX(PM_TOKEN_UPLUS);
10621 if (ambiguous_operator_p(parser, space_seen)) {
10622 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"+",
"unary operator");
10625 lex_state_set(parser, PM_LEX_STATE_BEG);
10626 LEX(PM_TOKEN_PLUS);
10631 if (lex_state_operator_p(parser)) {
10632 lex_state_set(parser, PM_LEX_STATE_ARG);
10634 if (match(parser,
'@')) {
10635 LEX(PM_TOKEN_UMINUS);
10638 LEX(PM_TOKEN_MINUS);
10641 if (match(parser,
'=')) {
10642 lex_state_set(parser, PM_LEX_STATE_BEG);
10643 LEX(PM_TOKEN_MINUS_EQUAL);
10646 if (match(parser,
'>')) {
10647 lex_state_set(parser, PM_LEX_STATE_ENDFN);
10648 LEX(PM_TOKEN_MINUS_GREATER);
10651 bool spcarg = lex_state_spcarg_p(parser, space_seen);
10652 bool is_beg = lex_state_beg_p(parser);
10653 if (!is_beg && spcarg) {
10654 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_FIRST_ARGUMENT_MINUS);
10657 if (is_beg || spcarg) {
10658 lex_state_set(parser, PM_LEX_STATE_BEG);
10659 LEX(pm_char_is_decimal_digit(peek(parser)) ? PM_TOKEN_UMINUS_NUM : PM_TOKEN_UMINUS);
10662 if (ambiguous_operator_p(parser, space_seen)) {
10663 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"-",
"unary operator");
10666 lex_state_set(parser, PM_LEX_STATE_BEG);
10667 LEX(PM_TOKEN_MINUS);
10672 bool beg_p = lex_state_beg_p(parser);
10674 if (match(parser,
'.')) {
10675 if (match(parser,
'.')) {
10678 if (lex_state_p(parser, PM_LEX_STATE_END)) {
10679 lex_state_set(parser, PM_LEX_STATE_BEG);
10681 lex_state_set(parser, PM_LEX_STATE_ENDARG);
10683 LEX(PM_TOKEN_UDOT_DOT_DOT);
10687 pm_parser_warn_token(parser, &parser->
current, PM_WARN_DOT_DOT_DOT_EOL);
10690 lex_state_set(parser, PM_LEX_STATE_BEG);
10691 LEX(beg_p ? PM_TOKEN_UDOT_DOT_DOT : PM_TOKEN_DOT_DOT_DOT);
10694 lex_state_set(parser, PM_LEX_STATE_BEG);
10695 LEX(beg_p ? PM_TOKEN_UDOT_DOT : PM_TOKEN_DOT_DOT);
10698 lex_state_set(parser, PM_LEX_STATE_DOT);
10713 pm_token_type_t
type = lex_numeric(parser);
10714 lex_state_set(parser, PM_LEX_STATE_END);
10720 if (match(parser,
':')) {
10721 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)) {
10722 lex_state_set(parser, PM_LEX_STATE_BEG);
10723 LEX(PM_TOKEN_UCOLON_COLON);
10726 lex_state_set(parser, PM_LEX_STATE_DOT);
10727 LEX(PM_TOKEN_COLON_COLON);
10730 if (lex_state_end_p(parser) || pm_char_is_whitespace(peek(parser)) || peek(parser) ==
'#') {
10731 lex_state_set(parser, PM_LEX_STATE_BEG);
10732 LEX(PM_TOKEN_COLON);
10735 if (peek(parser) ==
'"' || peek(parser) ==
'\'') {
10736 lex_mode_push_string(parser, peek(parser) ==
'"',
false,
'\0', *parser->
current.end);
10740 lex_state_set(parser, PM_LEX_STATE_FNAME);
10741 LEX(PM_TOKEN_SYMBOL_BEGIN);
10745 if (lex_state_beg_p(parser)) {
10746 lex_mode_push_regexp(parser,
'\0',
'/');
10747 LEX(PM_TOKEN_REGEXP_BEGIN);
10750 if (match(parser,
'=')) {
10751 lex_state_set(parser, PM_LEX_STATE_BEG);
10752 LEX(PM_TOKEN_SLASH_EQUAL);
10755 if (lex_state_spcarg_p(parser, space_seen)) {
10756 pm_parser_warn_token(parser, &parser->
current, PM_WARN_AMBIGUOUS_SLASH);
10757 lex_mode_push_regexp(parser,
'\0',
'/');
10758 LEX(PM_TOKEN_REGEXP_BEGIN);
10761 if (ambiguous_operator_p(parser, space_seen)) {
10762 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"/",
"regexp literal");
10765 if (lex_state_operator_p(parser)) {
10766 lex_state_set(parser, PM_LEX_STATE_ARG);
10768 lex_state_set(parser, PM_LEX_STATE_BEG);
10771 LEX(PM_TOKEN_SLASH);
10775 if (lex_state_operator_p(parser)) {
10776 lex_state_set(parser, PM_LEX_STATE_ARG);
10778 lex_state_set(parser, PM_LEX_STATE_BEG);
10780 LEX(match(parser,
'=') ? PM_TOKEN_CARET_EQUAL : PM_TOKEN_CARET);
10784 if (lex_state_operator_p(parser)) {
10785 (void) match(parser,
'@');
10786 lex_state_set(parser, PM_LEX_STATE_ARG);
10788 lex_state_set(parser, PM_LEX_STATE_BEG);
10791 LEX(PM_TOKEN_TILDE);
10799 if ((lex_state_beg_p(parser) || lex_state_arg_p(parser)) && (parser->
current.end >= parser->
end)) {
10800 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT_EOF);
10801 LEX(PM_TOKEN_PERCENT);
10804 if (!lex_state_beg_p(parser) && match(parser,
'=')) {
10805 lex_state_set(parser, PM_LEX_STATE_BEG);
10806 LEX(PM_TOKEN_PERCENT_EQUAL);
10808 lex_state_beg_p(parser) ||
10809 (lex_state_p(parser, PM_LEX_STATE_FITEM) && (peek(parser) ==
's')) ||
10810 lex_state_spcarg_p(parser, space_seen)
10813 if (*parser->
current.end >= 0x80) {
10814 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10817 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10818 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10819 LEX(PM_TOKEN_STRING_BEGIN);
10824 uint8_t delimiter = peek_offset(parser, 1);
10826 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10827 goto lex_next_token;
10830 switch (peek(parser)) {
10835 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10837 lex_mode_push_list_eof(parser);
10840 LEX(PM_TOKEN_PERCENT_LOWER_I);
10846 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10848 lex_mode_push_list_eof(parser);
10851 LEX(PM_TOKEN_PERCENT_UPPER_I);
10857 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10858 lex_mode_push_regexp(parser, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10860 lex_mode_push_regexp(parser,
'\0',
'\0');
10863 LEX(PM_TOKEN_REGEXP_BEGIN);
10869 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10870 lex_mode_push_string(parser,
false,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10872 lex_mode_push_string_eof(parser);
10875 LEX(PM_TOKEN_STRING_BEGIN);
10881 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10882 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10884 lex_mode_push_string_eof(parser);
10887 LEX(PM_TOKEN_STRING_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));
10895 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
10897 lex_mode_push_string_eof(parser);
10900 LEX(PM_TOKEN_SYMBOL_BEGIN);
10906 lex_mode_push_list(parser,
false, pm_lex_percent_delimiter(parser));
10908 lex_mode_push_list_eof(parser);
10911 LEX(PM_TOKEN_PERCENT_LOWER_W);
10917 lex_mode_push_list(parser,
true, pm_lex_percent_delimiter(parser));
10919 lex_mode_push_list_eof(parser);
10922 LEX(PM_TOKEN_PERCENT_UPPER_W);
10928 const uint8_t delimiter = pm_lex_percent_delimiter(parser);
10929 lex_mode_push_string(parser,
true,
false, lex_mode_incrementor(delimiter), lex_mode_terminator(delimiter));
10931 lex_mode_push_string_eof(parser);
10934 LEX(PM_TOKEN_PERCENT_LOWER_X);
10941 pm_parser_err_current(parser, PM_ERR_INVALID_PERCENT);
10942 goto lex_next_token;
10946 if (ambiguous_operator_p(parser, space_seen)) {
10947 PM_PARSER_WARN_TOKEN_FORMAT(parser, parser->
current, PM_WARN_AMBIGUOUS_BINARY_OPERATOR,
"%",
"string literal");
10950 lex_state_set(parser, lex_state_operator_p(parser) ? PM_LEX_STATE_ARG : PM_LEX_STATE_BEG);
10951 LEX(PM_TOKEN_PERCENT);
10956 pm_token_type_t
type = lex_global_variable(parser);
10961 lex_mode_pop(parser);
10964 lex_state_set(parser, PM_LEX_STATE_END);
10970 lex_state_set(parser, parser->
lex_state & PM_LEX_STATE_FNAME ? PM_LEX_STATE_ENDFN : PM_LEX_STATE_END);
10971 LEX(lex_at_variable(parser));
10974 if (*parser->
current.start !=
'_') {
10975 size_t width = char_is_identifier_start(parser, parser->
current.start, parser->
end - parser->
current.start);
10982 if (*parser->
current.start >= 0x80) {
10983 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_MULTIBYTE_CHARACTER, *parser->
current.start);
10984 }
else if (*parser->
current.start ==
'\\') {
10985 switch (peek_at(parser, parser->
current.start + 1)) {
10988 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped space");
10992 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped form feed");
10996 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped horizontal tab");
11000 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped vertical tab");
11003 if (peek_at(parser, parser->
current.start + 2) !=
'\n') {
11005 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"escaped carriage return");
11010 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_IGNORE,
"backslash");
11013 }
else if (char_is_ascii_printable(*parser->
current.start)) {
11014 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_PRINTABLE_CHARACTER, *parser->
current.start);
11016 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_INVALID_CHARACTER, *parser->
current.start);
11019 goto lex_next_token;
11025 pm_token_type_t
type = lex_identifier(parser, previous_command_start);
11033 current_token_starts_line(parser) &&
11034 (memcmp(parser->
current.start,
"__END__", 7) == 0) &&
11035 (parser->
current.end == parser->
end || match_eol(parser))
11040 const uint8_t *cursor = parser->
current.end;
11041 while ((cursor = next_newline(cursor, parser->
end - cursor)) != NULL) {
11042 pm_newline_list_append(&parser->
newline_list, cursor++);
11046 parser->
current.type = PM_TOKEN___END__;
11047 parser_lex_callback(parser);
11057 if (
type == PM_TOKEN_IDENTIFIER ||
type == PM_TOKEN_CONSTANT ||
type == PM_TOKEN_METHOD_NAME) {
11058 if (lex_state_p(parser, PM_LEX_STATE_BEG_ANY | PM_LEX_STATE_ARG_ANY | PM_LEX_STATE_DOT)) {
11059 if (previous_command_start) {
11060 lex_state_set(parser, PM_LEX_STATE_CMDARG);
11062 lex_state_set(parser, PM_LEX_STATE_ARG);
11064 }
else if (parser->
lex_state == PM_LEX_STATE_FNAME) {
11065 lex_state_set(parser, PM_LEX_STATE_ENDFN);
11067 lex_state_set(parser, PM_LEX_STATE_END);
11072 !(last_state & (PM_LEX_STATE_DOT | PM_LEX_STATE_FNAME)) &&
11073 (
type == PM_TOKEN_IDENTIFIER) &&
11074 ((pm_parser_local_depth(parser, &parser->
current) != -1) ||
11075 pm_token_is_numbered_parameter(parser->
current.start, parser->
current.end))
11077 lex_state_set(parser, PM_LEX_STATE_END | PM_LEX_STATE_LABEL);
11084 case PM_LEX_LIST: {
11098 whitespace = pm_strspn_inline_whitespace(parser->
current.end, parser->
end - parser->
current.end);
11099 if (peek_offset(parser, (ptrdiff_t)whitespace) ==
'\n') {
11106 if (whitespace > 0) {
11107 parser->
current.end += whitespace;
11108 if (peek_offset(parser, -1) ==
'\n') {
11110 parser_flush_heredoc_end(parser);
11112 LEX(PM_TOKEN_WORDS_SEP);
11124 const uint8_t *breakpoints = lex_mode->
as.list.
breakpoints;
11125 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11131 while (breakpoint != NULL) {
11134 if (pm_char_is_whitespace(*breakpoint)) {
11135 parser->
current.end = breakpoint;
11136 pm_token_buffer_flush(parser, &token_buffer);
11137 LEX(PM_TOKEN_STRING_CONTENT);
11146 parser->
current.end = breakpoint + 1;
11147 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11154 if (breakpoint > parser->
current.start) {
11155 parser->
current.end = breakpoint;
11156 pm_token_buffer_flush(parser, &token_buffer);
11157 LEX(PM_TOKEN_STRING_CONTENT);
11162 parser->
current.end = breakpoint + 1;
11163 lex_mode_pop(parser);
11164 lex_state_set(parser, PM_LEX_STATE_END);
11165 LEX(PM_TOKEN_STRING_END);
11169 if (*breakpoint ==
'\0') {
11170 breakpoint = pm_strpbrk(parser, breakpoint + 1, breakpoints, parser->
end - (breakpoint + 1),
true);
11177 if (*breakpoint ==
'\\') {
11178 parser->
current.end = breakpoint + 1;
11187 pm_token_buffer_escape(parser, &token_buffer);
11188 uint8_t peeked = peek(parser);
11196 pm_token_buffer_push_byte(&token_buffer, peeked);
11201 if (peek(parser) !=
'\n') {
11202 pm_token_buffer_push_byte(&token_buffer,
'\r');
11207 pm_token_buffer_push_byte(&token_buffer,
'\n');
11213 parser_flush_heredoc_end(parser);
11214 pm_token_buffer_copy(parser, &token_buffer);
11215 LEX(PM_TOKEN_STRING_CONTENT);
11225 pm_token_buffer_push_byte(&token_buffer, peeked);
11228 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11230 pm_token_buffer_push_byte(&token_buffer,
'\\');
11231 pm_token_buffer_push_escaped(&token_buffer, parser);
11238 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11243 if (*breakpoint ==
'#') {
11244 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11246 if (
type == PM_TOKEN_NOT_PROVIDED) {
11251 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11255 if (
type == PM_TOKEN_STRING_CONTENT) {
11256 pm_token_buffer_flush(parser, &token_buffer);
11265 parser->
current.end = breakpoint + 1;
11266 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11272 pm_token_buffer_flush(parser, &token_buffer);
11273 LEX(PM_TOKEN_STRING_CONTENT);
11279 pm_token_buffer_flush(parser, &token_buffer);
11280 LEX(PM_TOKEN_STRING_CONTENT);
11282 case PM_LEX_REGEXP: {
11304 const uint8_t *breakpoints = lex_mode->
as.regexp.
breakpoints;
11305 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11308 while (breakpoint != NULL) {
11310 bool is_terminator = (*breakpoint == term);
11315 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11316 if (term ==
'\n') {
11317 is_terminator =
true;
11323 if (term ==
'\r') {
11324 is_terminator =
false;
11330 if (is_terminator) {
11332 parser->
current.end = breakpoint + 1;
11333 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11341 if (breakpoint > parser->
current.start) {
11342 parser->
current.end = breakpoint;
11343 pm_regexp_token_buffer_flush(parser, &token_buffer);
11344 LEX(PM_TOKEN_STRING_CONTENT);
11348 size_t eol_length = match_eol_at(parser, breakpoint);
11350 parser->
current.end = breakpoint + eol_length;
11359 parser->
current.end = breakpoint + 1;
11366 lex_mode_pop(parser);
11367 lex_state_set(parser, PM_LEX_STATE_END);
11368 LEX(PM_TOKEN_REGEXP_END);
11373 if (*breakpoint && *breakpoint == lex_mode->
as.regexp.
incrementor) {
11374 parser->
current.end = breakpoint + 1;
11375 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11380 switch (*breakpoint) {
11383 parser->
current.end = breakpoint + 1;
11384 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11387 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11388 parser->
current.end = breakpoint + 1;
11389 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11394 parser->
current.end = breakpoint;
11395 pm_regexp_token_buffer_escape(parser, &token_buffer);
11403 pm_newline_list_append(&parser->
newline_list, breakpoint);
11404 parser->
current.end = breakpoint + 1;
11405 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11409 parser->
current.end = breakpoint + 1;
11410 parser_flush_heredoc_end(parser);
11411 pm_regexp_token_buffer_flush(parser, &token_buffer);
11412 LEX(PM_TOKEN_STRING_CONTENT);
11417 parser->
current.end = breakpoint + 1;
11426 pm_regexp_token_buffer_escape(parser, &token_buffer);
11427 uint8_t peeked = peek(parser);
11432 if (peek(parser) !=
'\n') {
11434 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11436 pm_regexp_token_buffer_push_byte(&token_buffer,
'\r');
11437 pm_token_buffer_push_byte(&token_buffer.
base,
'\r');
11446 parser_flush_heredoc_end(parser);
11447 pm_regexp_token_buffer_copy(parser, &token_buffer);
11448 LEX(PM_TOKEN_STRING_CONTENT);
11469 case '$':
case ')':
case '*':
case '+':
11470 case '.':
case '>':
case '?':
case ']':
11471 case '^':
case '|':
case '}':
11472 pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11478 pm_regexp_token_buffer_push_byte(&token_buffer, peeked);
11479 pm_token_buffer_push_byte(&token_buffer.
base, peeked);
11484 if (peeked < 0x80) pm_token_buffer_push_byte(&token_buffer.
base,
'\\');
11485 pm_regexp_token_buffer_push_escaped(&token_buffer, parser);
11490 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11496 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11498 if (
type == PM_TOKEN_NOT_PROVIDED) {
11503 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
false);
11507 if (
type == PM_TOKEN_STRING_CONTENT) {
11508 pm_regexp_token_buffer_flush(parser, &token_buffer);
11514 assert(
false &&
"unreachable");
11520 pm_regexp_token_buffer_flush(parser, &token_buffer);
11521 LEX(PM_TOKEN_STRING_CONTENT);
11527 pm_regexp_token_buffer_flush(parser, &token_buffer);
11528 LEX(PM_TOKEN_STRING_CONTENT);
11530 case PM_LEX_STRING: {
11549 const uint8_t *breakpoints = lex_mode->
as.string.
breakpoints;
11550 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11556 while (breakpoint != NULL) {
11561 parser->
current.end = breakpoint + 1;
11562 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11567 bool is_terminator = (*breakpoint == term);
11572 if (*breakpoint ==
'\r' && peek_at(parser, breakpoint + 1) ==
'\n') {
11573 if (term ==
'\n') {
11574 is_terminator =
true;
11580 if (term ==
'\r') {
11581 is_terminator =
false;
11588 if (is_terminator) {
11592 parser->
current.end = breakpoint + 1;
11593 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11600 if (breakpoint > parser->
current.start) {
11601 parser->
current.end = breakpoint;
11602 pm_token_buffer_flush(parser, &token_buffer);
11603 LEX(PM_TOKEN_STRING_CONTENT);
11608 size_t eol_length = match_eol_at(parser, breakpoint);
11610 parser->
current.end = breakpoint + eol_length;
11619 parser->
current.end = breakpoint + 1;
11622 if (lex_mode->
as.string.
label_allowed && (peek(parser) ==
':') && (peek_offset(parser, 1) !=
':')) {
11624 lex_state_set(parser, PM_LEX_STATE_ARG | PM_LEX_STATE_LABELED);
11625 lex_mode_pop(parser);
11626 LEX(PM_TOKEN_LABEL_END);
11633 parser_flush_heredoc_end(parser);
11636 lex_state_set(parser, PM_LEX_STATE_END);
11637 lex_mode_pop(parser);
11638 LEX(PM_TOKEN_STRING_END);
11641 switch (*breakpoint) {
11644 parser->
current.end = breakpoint + 1;
11645 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11648 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11649 parser->
current.end = breakpoint + 1;
11650 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11657 parser->
current.end = breakpoint;
11658 pm_token_buffer_escape(parser, &token_buffer);
11659 token_buffer.
cursor = breakpoint;
11668 pm_newline_list_append(&parser->
newline_list, breakpoint);
11669 parser->
current.end = breakpoint + 1;
11670 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11674 parser->
current.end = breakpoint + 1;
11675 parser_flush_heredoc_end(parser);
11676 pm_token_buffer_flush(parser, &token_buffer);
11677 LEX(PM_TOKEN_STRING_CONTENT);
11680 parser->
current.end = breakpoint + 1;
11689 pm_token_buffer_escape(parser, &token_buffer);
11690 uint8_t peeked = peek(parser);
11694 pm_token_buffer_push_byte(&token_buffer,
'\\');
11699 if (peek(parser) !=
'\n') {
11701 pm_token_buffer_push_byte(&token_buffer,
'\\');
11703 pm_token_buffer_push_byte(&token_buffer,
'\r');
11709 pm_token_buffer_push_byte(&token_buffer,
'\\');
11710 pm_token_buffer_push_byte(&token_buffer,
'\n');
11717 parser_flush_heredoc_end(parser);
11718 pm_token_buffer_copy(parser, &token_buffer);
11719 LEX(PM_TOKEN_STRING_CONTENT);
11729 pm_token_buffer_push_byte(&token_buffer, peeked);
11732 pm_token_buffer_push_byte(&token_buffer, peeked);
11735 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
11737 pm_token_buffer_push_byte(&token_buffer,
'\\');
11738 pm_token_buffer_push_escaped(&token_buffer, parser);
11745 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11749 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
11751 if (
type == PM_TOKEN_NOT_PROVIDED) {
11756 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11760 if (
type == PM_TOKEN_STRING_CONTENT) {
11761 pm_token_buffer_flush(parser, &token_buffer);
11767 assert(
false &&
"unreachable");
11772 pm_token_buffer_flush(parser, &token_buffer);
11773 LEX(PM_TOKEN_STRING_CONTENT);
11779 pm_token_buffer_flush(parser, &token_buffer);
11780 LEX(PM_TOKEN_STRING_CONTENT);
11782 case PM_LEX_HEREDOC: {
11809 lex_state_set(parser, PM_LEX_STATE_END);
11810 lex_mode_pop(parser);
11811 LEX(PM_TOKEN_HEREDOC_END);
11814 const uint8_t *ident_start = heredoc_lex_mode->
ident_start;
11819 if (current_token_starts_line(parser)) {
11820 const uint8_t *start = parser->
current.start;
11822 if (!line_continuation && (start + ident_length <= parser->end)) {
11823 const uint8_t *newline = next_newline(start, parser->
end - start);
11824 const uint8_t *ident_end = newline;
11825 const uint8_t *terminator_end = newline;
11827 if (newline == NULL) {
11828 terminator_end = parser->
end;
11829 ident_end = parser->
end;
11832 if (newline[-1] ==
'\r') {
11837 const uint8_t *terminator_start = ident_end - ident_length;
11838 const uint8_t *cursor = start;
11840 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11841 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11847 (cursor == terminator_start) &&
11848 (memcmp(terminator_start, ident_start, ident_length) == 0)
11850 if (newline != NULL) {
11851 pm_newline_list_append(&parser->
newline_list, newline);
11854 parser->
current.end = terminator_end;
11862 lex_state_set(parser, PM_LEX_STATE_END);
11863 lex_mode_pop(parser);
11864 LEX(PM_TOKEN_HEREDOC_END);
11868 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, heredoc_lex_mode->
indent);
11870 heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE &&
11873 peek_at(parser, start) !=
'\n'
11882 uint8_t breakpoints[] =
"\r\n\\#";
11885 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
11886 breakpoints[3] =
'\0';
11889 const uint8_t *breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11891 bool was_line_continuation =
false;
11893 while (breakpoint != NULL) {
11894 switch (*breakpoint) {
11897 parser->
current.end = breakpoint + 1;
11898 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11901 parser->
current.end = breakpoint + 1;
11903 if (peek_at(parser, breakpoint + 1) !=
'\n') {
11904 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11911 pm_token_buffer_escape(parser, &token_buffer);
11912 token_buffer.
cursor = breakpoint;
11917 parser_flush_heredoc_end(parser);
11918 parser->
current.end = breakpoint + 1;
11919 pm_token_buffer_flush(parser, &token_buffer);
11920 LEX(PM_TOKEN_STRING_CONTENT);
11923 pm_newline_list_append(&parser->
newline_list, breakpoint);
11927 const uint8_t *start = breakpoint + 1;
11929 if (!was_line_continuation && (start + ident_length <= parser->end)) {
11932 const uint8_t *newline = next_newline(start, parser->
end - start);
11934 if (newline == NULL) {
11935 newline = parser->
end;
11936 }
else if (newline[-1] ==
'\r') {
11941 const uint8_t *terminator_start = newline - ident_length;
11945 const uint8_t *cursor = start;
11947 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_DASH || heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
11948 while (cursor < terminator_start && pm_char_is_inline_whitespace(*cursor)) {
11954 cursor == terminator_start &&
11955 (memcmp(terminator_start, ident_start, ident_length) == 0)
11957 parser->
current.end = breakpoint + 1;
11958 pm_token_buffer_flush(parser, &token_buffer);
11959 LEX(PM_TOKEN_STRING_CONTENT);
11963 size_t whitespace = pm_heredoc_strspn_inline_whitespace(parser, &start, lex_mode->
as.heredoc.
base.
indent);
11970 if (lex_mode->
as.heredoc.
base.
indent == PM_HEREDOC_INDENT_TILDE) {
11975 parser->
current.end = breakpoint + 1;
11976 pm_token_buffer_flush(parser, &token_buffer);
11977 LEX(PM_TOKEN_STRING_CONTENT);
11982 parser->
current.end = breakpoint + 1;
11983 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
11993 parser->
current.end = breakpoint + 1;
12002 pm_token_buffer_escape(parser, &token_buffer);
12003 uint8_t peeked = peek(parser);
12005 if (quote == PM_HEREDOC_QUOTE_SINGLE) {
12009 if (peek(parser) !=
'\n') {
12010 pm_token_buffer_push_byte(&token_buffer,
'\\');
12011 pm_token_buffer_push_byte(&token_buffer,
'\r');
12016 pm_token_buffer_push_byte(&token_buffer,
'\\');
12017 pm_token_buffer_push_byte(&token_buffer,
'\n');
12019 breakpoint = parser->
current.end;
12022 pm_token_buffer_push_byte(&token_buffer,
'\\');
12023 pm_token_buffer_push_escaped(&token_buffer, parser);
12030 if (peek(parser) !=
'\n') {
12031 pm_token_buffer_push_byte(&token_buffer,
'\r');
12039 if (heredoc_lex_mode->
indent == PM_HEREDOC_INDENT_TILDE) {
12040 const uint8_t *end = parser->
current.end;
12048 parser->
current.end = breakpoint;
12049 pm_token_buffer_flush(parser, &token_buffer);
12053 parser->
current.end = end + 1;
12055 LEX(PM_TOKEN_STRING_CONTENT);
12058 was_line_continuation =
true;
12060 breakpoint = parser->
current.end;
12063 escape_read(parser, &token_buffer.
buffer, NULL, PM_ESCAPE_FLAG_NONE);
12069 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12073 pm_token_type_t
type = lex_interpolation(parser, breakpoint);
12075 if (
type == PM_TOKEN_NOT_PROVIDED) {
12081 breakpoint = pm_strpbrk(parser, parser->
current.end, breakpoints, parser->
end - parser->
current.end,
true);
12085 if (
type == PM_TOKEN_STRING_CONTENT) {
12086 pm_token_buffer_flush(parser, &token_buffer);
12092 assert(
false &&
"unreachable");
12095 was_line_continuation =
false;
12100 pm_token_buffer_flush(parser, &token_buffer);
12101 LEX(PM_TOKEN_STRING_CONTENT);
12107 pm_token_buffer_flush(parser, &token_buffer);
12108 LEX(PM_TOKEN_STRING_CONTENT);
12112 assert(
false &&
"unreachable");
12130 PM_BINDING_POWER_UNSET = 0,
12131 PM_BINDING_POWER_STATEMENT = 2,
12132 PM_BINDING_POWER_MODIFIER_RESCUE = 4,
12133 PM_BINDING_POWER_MODIFIER = 6,
12134 PM_BINDING_POWER_COMPOSITION = 8,
12135 PM_BINDING_POWER_NOT = 10,
12136 PM_BINDING_POWER_MATCH = 12,
12137 PM_BINDING_POWER_DEFINED = 14,
12138 PM_BINDING_POWER_MULTI_ASSIGNMENT = 16,
12139 PM_BINDING_POWER_ASSIGNMENT = 18,
12140 PM_BINDING_POWER_TERNARY = 20,
12141 PM_BINDING_POWER_RANGE = 22,
12142 PM_BINDING_POWER_LOGICAL_OR = 24,
12143 PM_BINDING_POWER_LOGICAL_AND = 26,
12144 PM_BINDING_POWER_EQUALITY = 28,
12145 PM_BINDING_POWER_COMPARISON = 30,
12146 PM_BINDING_POWER_BITWISE_OR = 32,
12147 PM_BINDING_POWER_BITWISE_AND = 34,
12148 PM_BINDING_POWER_SHIFT = 36,
12149 PM_BINDING_POWER_TERM = 38,
12150 PM_BINDING_POWER_FACTOR = 40,
12151 PM_BINDING_POWER_UMINUS = 42,
12152 PM_BINDING_POWER_EXPONENT = 44,
12153 PM_BINDING_POWER_UNARY = 46,
12154 PM_BINDING_POWER_INDEX = 48,
12155 PM_BINDING_POWER_CALL = 50,
12156 PM_BINDING_POWER_MAX = 52
12157} pm_binding_power_t;
12180#define BINDING_POWER_ASSIGNMENT { PM_BINDING_POWER_UNARY, PM_BINDING_POWER_ASSIGNMENT, true, false }
12181#define LEFT_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, false }
12182#define RIGHT_ASSOCIATIVE(precedence) { precedence, precedence, true, false }
12183#define NON_ASSOCIATIVE(precedence) { precedence, precedence + 1, true, true }
12184#define RIGHT_ASSOCIATIVE_UNARY(precedence) { precedence, precedence, false, false }
12188 [PM_TOKEN_KEYWORD_RESCUE_MODIFIER] = { PM_BINDING_POWER_MODIFIER_RESCUE, PM_BINDING_POWER_COMPOSITION,
true,
false },
12191 [PM_TOKEN_KEYWORD_IF_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12192 [PM_TOKEN_KEYWORD_UNLESS_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12193 [PM_TOKEN_KEYWORD_UNTIL_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12194 [PM_TOKEN_KEYWORD_WHILE_MODIFIER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_MODIFIER),
12197 [PM_TOKEN_KEYWORD_AND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12198 [PM_TOKEN_KEYWORD_OR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPOSITION),
12201 [PM_TOKEN_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12202 [PM_TOKEN_KEYWORD_IN] = NON_ASSOCIATIVE(PM_BINDING_POWER_MATCH),
12205 [PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12206 [PM_TOKEN_AMPERSAND_EQUAL] = BINDING_POWER_ASSIGNMENT,
12207 [PM_TOKEN_CARET_EQUAL] = BINDING_POWER_ASSIGNMENT,
12208 [PM_TOKEN_EQUAL] = BINDING_POWER_ASSIGNMENT,
12209 [PM_TOKEN_GREATER_GREATER_EQUAL] = BINDING_POWER_ASSIGNMENT,
12210 [PM_TOKEN_LESS_LESS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12211 [PM_TOKEN_MINUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12212 [PM_TOKEN_PERCENT_EQUAL] = BINDING_POWER_ASSIGNMENT,
12213 [PM_TOKEN_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12214 [PM_TOKEN_PIPE_PIPE_EQUAL] = BINDING_POWER_ASSIGNMENT,
12215 [PM_TOKEN_PLUS_EQUAL] = BINDING_POWER_ASSIGNMENT,
12216 [PM_TOKEN_SLASH_EQUAL] = BINDING_POWER_ASSIGNMENT,
12217 [PM_TOKEN_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12218 [PM_TOKEN_STAR_STAR_EQUAL] = BINDING_POWER_ASSIGNMENT,
12221 [PM_TOKEN_QUESTION_MARK] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_TERNARY),
12224 [PM_TOKEN_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12225 [PM_TOKEN_DOT_DOT_DOT] = NON_ASSOCIATIVE(PM_BINDING_POWER_RANGE),
12226 [PM_TOKEN_UDOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12227 [PM_TOKEN_UDOT_DOT_DOT] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_LOGICAL_OR),
12230 [PM_TOKEN_PIPE_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_OR),
12233 [PM_TOKEN_AMPERSAND_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_LOGICAL_AND),
12236 [PM_TOKEN_BANG_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12237 [PM_TOKEN_BANG_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12238 [PM_TOKEN_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12239 [PM_TOKEN_EQUAL_EQUAL_EQUAL] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12240 [PM_TOKEN_EQUAL_TILDE] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12241 [PM_TOKEN_LESS_EQUAL_GREATER] = NON_ASSOCIATIVE(PM_BINDING_POWER_EQUALITY),
12244 [PM_TOKEN_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12245 [PM_TOKEN_GREATER_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12246 [PM_TOKEN_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12247 [PM_TOKEN_LESS_EQUAL] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_COMPARISON),
12250 [PM_TOKEN_CARET] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12251 [PM_TOKEN_PIPE] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_OR),
12254 [PM_TOKEN_AMPERSAND] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_BITWISE_AND),
12257 [PM_TOKEN_GREATER_GREATER] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12258 [PM_TOKEN_LESS_LESS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_SHIFT),
12261 [PM_TOKEN_MINUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12262 [PM_TOKEN_PLUS] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_TERM),
12265 [PM_TOKEN_PERCENT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12266 [PM_TOKEN_SLASH] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12267 [PM_TOKEN_STAR] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_FACTOR),
12268 [PM_TOKEN_USTAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_FACTOR),
12271 [PM_TOKEN_UMINUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UMINUS),
12272 [PM_TOKEN_UMINUS_NUM] = { PM_BINDING_POWER_UMINUS, PM_BINDING_POWER_MAX,
false,
false },
12275 [PM_TOKEN_STAR_STAR] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_EXPONENT),
12276 [PM_TOKEN_USTAR_STAR] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12279 [PM_TOKEN_BANG] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12280 [PM_TOKEN_TILDE] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12281 [PM_TOKEN_UPLUS] = RIGHT_ASSOCIATIVE_UNARY(PM_BINDING_POWER_UNARY),
12284 [PM_TOKEN_BRACKET_LEFT] = LEFT_ASSOCIATIVE(PM_BINDING_POWER_INDEX),
12287 [PM_TOKEN_COLON_COLON] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12288 [PM_TOKEN_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL),
12289 [PM_TOKEN_AMPERSAND_DOT] = RIGHT_ASSOCIATIVE(PM_BINDING_POWER_CALL)
12292#undef BINDING_POWER_ASSIGNMENT
12293#undef LEFT_ASSOCIATIVE
12294#undef RIGHT_ASSOCIATIVE
12295#undef RIGHT_ASSOCIATIVE_UNARY
12309match2(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12310 return match1(parser, type1) || match1(parser, type2);
12317match3(
const pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2, pm_token_type_t type3) {
12318 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3);
12325match4(
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) {
12326 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4);
12333match7(
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) {
12334 return match1(parser, type1) || match1(parser, type2) || match1(parser, type3) || match1(parser, type4) || match1(parser, type5) || match1(parser, type6) || match1(parser, type7);
12341match8(
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) {
12342 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);
12353 if (match1(parser,
type)) {
12354 parser_lex(parser);
12365accept2(
pm_parser_t *parser, pm_token_type_t type1, pm_token_type_t type2) {
12366 if (match2(parser, type1, type2)) {
12367 parser_lex(parser);
12386 if (accept1(parser,
type))
return;
12389 pm_parser_err(parser, location, location, diag_id);
12401 if (accept2(parser, type1, type2))
return;
12404 pm_parser_err(parser, location, location, diag_id);
12415expect1_heredoc_term(
pm_parser_t *parser,
const uint8_t *ident_start,
size_t ident_length) {
12416 if (match1(parser, PM_TOKEN_HEREDOC_END)) {
12417 parser_lex(parser);
12419 pm_parser_err_heredoc_term(parser, ident_start, ident_length);
12433 if (accept1(parser,
type))
return;
12435 pm_parser_err(parser, opening->
start, opening->
end, diag_id);
12442parse_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);
12449parse_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) {
12450 pm_node_t *node = parse_expression(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
12451 pm_assert_value_expression(parser, node);
12474token_begins_expression_p(pm_token_type_t
type) {
12476 case PM_TOKEN_EQUAL_GREATER:
12477 case PM_TOKEN_KEYWORD_IN:
12481 case PM_TOKEN_BRACE_RIGHT:
12482 case PM_TOKEN_BRACKET_RIGHT:
12483 case PM_TOKEN_COLON:
12484 case PM_TOKEN_COMMA:
12485 case PM_TOKEN_EMBEXPR_END:
12487 case PM_TOKEN_LAMBDA_BEGIN:
12488 case PM_TOKEN_KEYWORD_DO:
12489 case PM_TOKEN_KEYWORD_DO_LOOP:
12490 case PM_TOKEN_KEYWORD_END:
12491 case PM_TOKEN_KEYWORD_ELSE:
12492 case PM_TOKEN_KEYWORD_ELSIF:
12493 case PM_TOKEN_KEYWORD_ENSURE:
12494 case PM_TOKEN_KEYWORD_THEN:
12495 case PM_TOKEN_KEYWORD_RESCUE:
12496 case PM_TOKEN_KEYWORD_WHEN:
12497 case PM_TOKEN_NEWLINE:
12498 case PM_TOKEN_PARENTHESIS_RIGHT:
12499 case PM_TOKEN_SEMICOLON:
12505 assert(pm_binding_powers[
type].left == PM_BINDING_POWER_UNSET);
12507 case PM_TOKEN_UAMPERSAND:
12511 case PM_TOKEN_UCOLON_COLON:
12512 case PM_TOKEN_UMINUS:
12513 case PM_TOKEN_UMINUS_NUM:
12514 case PM_TOKEN_UPLUS:
12515 case PM_TOKEN_BANG:
12516 case PM_TOKEN_TILDE:
12517 case PM_TOKEN_UDOT_DOT:
12518 case PM_TOKEN_UDOT_DOT_DOT:
12525 return pm_binding_powers[
type].
left == PM_BINDING_POWER_UNSET;
12534parse_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) {
12535 if (accept1(parser, PM_TOKEN_USTAR)) {
12537 pm_node_t *expression = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
12538 return UP(pm_splat_node_create(parser, &
operator, expression));
12541 return parse_value_expression(parser, binding_power, accepts_command_call,
false, diag_id, depth);
12545pm_node_unreference_each(
const pm_node_t *node,
void *data) {
12546 switch (PM_NODE_TYPE(node)) {
12551 case PM_BREAK_NODE:
12553 case PM_REDO_NODE: {
12557 while (index < parser->current_block_exits->size) {
12560 if (block_exit == node) {
12583 case PM_LOCAL_VARIABLE_READ_NODE:
12584 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12588 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
12589 if (implicit_parameters->
nodes[index] == node) {
12593 if (index != implicit_parameters->
size - 1) {
12594 memmove(&implicit_parameters->
nodes[index], &implicit_parameters->
nodes[index + 1], (implicit_parameters->
size - index - 1) *
sizeof(
pm_node_t *));
12597 implicit_parameters->
size--;
12616 pm_visit_node(node, pm_node_unreference_each, parser);
12630 size_t length = constant->
length;
12631 uint8_t *name =
xcalloc(length + 1,
sizeof(uint8_t));
12632 if (name == NULL)
return;
12634 memcpy(name, constant->
start, length);
12635 name[length] =
'=';
12640 *name_field = pm_constant_pool_insert_owned(&parser->
constant_pool, name, length + 1);
12651 switch (PM_NODE_TYPE(target)) {
12652 case PM_SOURCE_ENCODING_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
12653 case PM_FALSE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
12654 case PM_SOURCE_FILE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
12655 case PM_SOURCE_LINE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
12656 case PM_NIL_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
12657 case PM_SELF_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
12658 case PM_TRUE_NODE: pm_parser_err_node(parser, target, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
12665 pm_node_destroy(parser, target);
12679 switch (PM_NODE_TYPE(target)) {
12680 case PM_MISSING_NODE:
12682 case PM_SOURCE_ENCODING_NODE:
12683 case PM_FALSE_NODE:
12684 case PM_SOURCE_FILE_NODE:
12685 case PM_SOURCE_LINE_NODE:
12688 case PM_TRUE_NODE: {
12691 return parse_unwriteable_target(parser, target);
12693 case PM_CLASS_VARIABLE_READ_NODE:
12695 target->
type = PM_CLASS_VARIABLE_TARGET_NODE;
12697 case PM_CONSTANT_PATH_NODE:
12698 if (context_def_p(parser)) {
12699 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12703 target->
type = PM_CONSTANT_PATH_TARGET_NODE;
12706 case PM_CONSTANT_READ_NODE:
12707 if (context_def_p(parser)) {
12708 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_IN_METHOD);
12712 target->
type = PM_CONSTANT_TARGET_NODE;
12715 case PM_BACK_REFERENCE_READ_NODE:
12716 case PM_NUMBERED_REFERENCE_READ_NODE:
12717 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12719 case PM_GLOBAL_VARIABLE_READ_NODE:
12721 target->
type = PM_GLOBAL_VARIABLE_TARGET_NODE;
12723 case PM_LOCAL_VARIABLE_READ_NODE: {
12726 pm_node_unreference(parser, target);
12730 uint32_t name = cast->
name;
12731 uint32_t depth = cast->
depth;
12732 pm_locals_unread(&pm_parser_scope_find(parser, depth)->locals, name);
12735 target->
type = PM_LOCAL_VARIABLE_TARGET_NODE;
12739 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12741 pm_node_t *node = UP(pm_local_variable_target_node_create(parser, &target->
location, name, 0));
12743 pm_node_unreference(parser, target);
12744 pm_node_destroy(parser, target);
12748 case PM_INSTANCE_VARIABLE_READ_NODE:
12750 target->
type = PM_INSTANCE_VARIABLE_TARGET_NODE;
12752 case PM_MULTI_TARGET_NODE:
12753 if (splat_parent) {
12756 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12760 case PM_SPLAT_NODE: {
12769 case PM_CALL_NODE: {
12781 (call->
block == NULL)
12796 pm_node_destroy(parser, target);
12798 return UP(pm_local_variable_target_node_create(parser, &message_loc, name, 0));
12802 if (multiple && PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_SAFE_NAVIGATION)) {
12803 pm_parser_err_node(parser, (
const pm_node_t *) call, PM_ERR_UNEXPECTED_SAFE_NAVIGATION);
12806 parse_write_name(parser, &call->
name);
12807 return UP(pm_call_target_node_create(parser, call));
12814 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
12815 return UP(pm_index_target_node_create(parser, call));
12823 pm_parser_err_node(parser, target, PM_ERR_WRITE_TARGET_UNEXPECTED);
12834 pm_node_t *result = parse_target(parser, target, multiple,
false);
12839 !match1(parser, PM_TOKEN_EQUAL) &&
12841 !(context_p(parser,
PM_CONTEXT_PARENS) && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
12843 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
12857 if (shareable_constant != PM_SCOPE_SHAREABLE_CONSTANT_NONE) {
12858 return UP(pm_shareable_constant_node_create(parser, write, shareable_constant));
12869 switch (PM_NODE_TYPE(target)) {
12870 case PM_MISSING_NODE:
12871 pm_node_destroy(parser, value);
12873 case PM_CLASS_VARIABLE_READ_NODE: {
12875 pm_node_destroy(parser, target);
12878 case PM_CONSTANT_PATH_NODE: {
12881 if (context_def_p(parser)) {
12882 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12885 return parse_shareable_constant_write(parser, node);
12887 case PM_CONSTANT_READ_NODE: {
12890 if (context_def_p(parser)) {
12891 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_IN_METHOD);
12894 pm_node_destroy(parser, target);
12895 return parse_shareable_constant_write(parser, node);
12897 case PM_BACK_REFERENCE_READ_NODE:
12898 case PM_NUMBERED_REFERENCE_READ_NODE:
12899 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, target, PM_ERR_WRITE_TARGET_READONLY);
12901 case PM_GLOBAL_VARIABLE_READ_NODE: {
12903 pm_node_destroy(parser, target);
12906 case PM_LOCAL_VARIABLE_READ_NODE: {
12912 uint32_t depth = local_read->
depth;
12913 pm_scope_t *scope = pm_parser_scope_find(parser, depth);
12916 pm_diagnostic_id_t diag_id = (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND) ? PM_ERR_EXPRESSION_NOT_WRITABLE_NUMBERED : PM_ERR_PARAMETER_NUMBERED_RESERVED;
12918 pm_node_unreference(parser, target);
12921 pm_locals_unread(&scope->
locals, name);
12922 pm_node_destroy(parser, target);
12924 return UP(pm_local_variable_write_node_create(parser, name, depth, value, &name_loc,
operator));
12926 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
12928 pm_node_t *node = UP(pm_local_variable_write_node_create(parser, name, 0, value, &target->
location,
operator));
12930 pm_node_unreference(parser, target);
12931 pm_node_destroy(parser, target);
12935 case PM_INSTANCE_VARIABLE_READ_NODE: {
12937 pm_node_destroy(parser, target);
12940 case PM_MULTI_TARGET_NODE:
12942 case PM_SPLAT_NODE: {
12950 pm_multi_target_node_targets_append(parser, multi_target, UP(splat));
12952 return UP(pm_multi_write_node_create(parser, multi_target,
operator, value));
12954 case PM_CALL_NODE: {
12966 (call->
block == NULL)
12980 pm_parser_local_add_location(parser, message.
start, message.
end, 0);
12981 pm_node_destroy(parser, target);
12984 target = UP(pm_local_variable_write_node_create(parser, constant_id, 0, value, &message,
operator));
12986 pm_refute_numbered_parameter(parser, message.
start, message.
end);
13004 pm_arguments_node_arguments_append(arguments, value);
13006 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13008 parse_write_name(parser, &call->
name);
13009 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13018 if (PM_NODE_FLAG_P(call, PM_CALL_NODE_FLAGS_INDEX)) {
13020 call->
arguments = pm_arguments_node_create(parser);
13023 pm_arguments_node_arguments_append(call->
arguments, value);
13027 call->
name = pm_parser_constant_id_constant(parser,
"[]=", 3);
13028 call->
equal_loc = PM_LOCATION_TOKEN_VALUE(
operator);
13032 pm_node_flag_set(UP(call), PM_CALL_NODE_FLAGS_ATTRIBUTE_WRITE | pm_implicit_array_write_flags(value, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY));
13047 pm_node_unreference(parser, value);
13048 pm_node_destroy(parser, value);
13055 pm_parser_err_token(parser,
operator, PM_ERR_WRITE_TARGET_UNEXPECTED);
13068 switch (PM_NODE_TYPE(target)) {
13069 case PM_SOURCE_ENCODING_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_ENCODING);
break;
13070 case PM_FALSE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FALSE);
break;
13071 case PM_SOURCE_FILE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_FILE);
break;
13072 case PM_SOURCE_LINE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_LINE);
break;
13073 case PM_NIL_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_NIL);
break;
13074 case PM_SELF_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_SELF);
break;
13075 case PM_TRUE_NODE: pm_parser_err_token(parser, equals, PM_ERR_EXPRESSION_NOT_WRITABLE_TRUE);
break;
13082 pm_node_destroy(parser, target);
13097parse_targets(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13098 bool has_rest = PM_NODE_TYPE_P(first_target, PM_SPLAT_NODE);
13101 pm_multi_target_node_targets_append(parser, result, parse_target(parser, first_target,
true,
false));
13103 while (accept1(parser, PM_TOKEN_COMMA)) {
13104 if (accept1(parser, PM_TOKEN_USTAR)) {
13109 pm_parser_err_previous(parser, PM_ERR_MULTI_ASSIGN_MULTI_SPLATS);
13115 if (token_begins_expression_p(parser->
current.type)) {
13116 name = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
13117 name = parse_target(parser, name,
true,
true);
13120 pm_node_t *splat = UP(pm_splat_node_create(parser, &star_operator, name));
13121 pm_multi_target_node_targets_append(parser, result, splat);
13123 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13125 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13126 target = parse_target(parser, target,
true,
false);
13128 pm_multi_target_node_targets_append(parser, result, target);
13129 context_pop(parser);
13130 }
else if (token_begins_expression_p(parser->
current.type)) {
13131 pm_node_t *target = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
13132 target = parse_target(parser, target,
true,
false);
13134 pm_multi_target_node_targets_append(parser, result, target);
13135 }
else if (!match1(parser, PM_TOKEN_EOF)) {
13139 pm_multi_target_node_targets_append(parser, result, rest);
13152parse_targets_validate(
pm_parser_t *parser,
pm_node_t *first_target, pm_binding_power_t binding_power, uint16_t depth) {
13153 pm_node_t *result = parse_targets(parser, first_target, binding_power, depth);
13154 accept1(parser, PM_TOKEN_NEWLINE);
13157 if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
13158 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
13171 while (accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE));
13174 if (context_terminator(context, &parser->
current))
return NULL;
13180 context_push(parser, context);
13183 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
13184 pm_statements_node_body_append(parser, statements, node,
true);
13197 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
13200 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13201 if (context_terminator(context, &parser->
current))
break;
13211 if (context_terminator(context, &parser->
current))
break;
13223 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE)) {
13224 parser_lex(parser);
13230 if (match1(parser, PM_TOKEN_EOF)) {
13235 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
13236 if (context_terminator(context, &parser->
current))
break;
13237 }
else if (!accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_EOF)) {
13247 context_pop(parser);
13248 bool last_value =
true;
13252 last_value =
false;
13257 pm_void_statements_check(parser, statements, last_value);
13270 if (duplicated != NULL) {
13274 pm_diagnostic_list_append_format(
13278 PM_WARN_DUPLICATED_HASH_KEY,
13296 if ((previous = pm_static_literals_add(&parser->
newline_list, parser->
start_line, literals, node,
false)) != NULL) {
13297 pm_diagnostic_list_append_format(
13301 PM_WARN_DUPLICATED_WHEN_CLAUSE,
13313 assert(PM_NODE_TYPE_P(node, PM_HASH_NODE) || PM_NODE_TYPE_P(node, PM_KEYWORD_HASH_NODE));
13314 bool contains_keyword_splat =
false;
13319 switch (parser->
current.type) {
13320 case PM_TOKEN_USTAR_STAR: {
13321 parser_lex(parser);
13325 if (match1(parser, PM_TOKEN_BRACE_LEFT)) {
13331 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13332 }
else if (token_begins_expression_p(parser->
current.type)) {
13333 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT_HASH, (uint16_t) (depth + 1));
13335 pm_parser_scope_forwarding_keywords_check(parser, &
operator);
13338 element = UP(pm_assoc_splat_node_create(parser, value, &
operator));
13339 contains_keyword_splat =
true;
13342 case PM_TOKEN_LABEL: {
13344 parser_lex(parser);
13346 pm_node_t *key = UP(pm_symbol_node_label_create(parser, &label));
13347 pm_hash_key_static_literals_add(parser, literals, key);
13352 if (token_begins_expression_p(parser->
current.type)) {
13353 value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_EXPRESSION_AFTER_LABEL, (uint16_t) (depth + 1));
13356 pm_token_t constant = { .type = PM_TOKEN_CONSTANT, .start = label.
start, .end = label.
end - 1 };
13357 value = UP(pm_constant_read_node_create(parser, &constant));
13362 if (identifier.
end[-1] ==
'!' || identifier.
end[-1] ==
'?') {
13363 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, identifier, PM_ERR_INVALID_LOCAL_VARIABLE_READ);
13365 depth = pm_parser_local_depth(parser, &identifier);
13369 value = UP(pm_call_node_variable_call_create(parser, &identifier));
13371 value = UP(pm_local_variable_read_node_create(parser, &identifier, (uint32_t) depth));
13376 value = UP(pm_implicit_node_create(parser, value));
13379 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13383 pm_node_t *key = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_HASH_KEY, (uint16_t) (depth + 1));
13387 if (PM_NODE_TYPE_P(key, PM_STRING_NODE)) {
13388 pm_node_flag_set(key, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
13391 pm_hash_key_static_literals_add(parser, literals, key);
13394 if (pm_symbol_node_label_p(key)) {
13395 operator = not_provided(parser);
13397 expect1(parser, PM_TOKEN_EQUAL_GREATER, PM_ERR_HASH_ROCKET);
13401 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13402 element = UP(pm_assoc_node_create(parser, key, &
operator, value));
13407 if (PM_NODE_TYPE_P(node, PM_HASH_NODE)) {
13414 if (!accept1(parser, PM_TOKEN_COMMA))
break;
13418 if (match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL))
continue;
13422 if (token_begins_expression_p(parser->
current.type))
continue;
13428 return contains_keyword_splat;
13433 if (pm_symbol_node_label_p(argument)) {
13437 switch (PM_NODE_TYPE(argument)) {
13438 case PM_CALL_NODE: {
13441 if (PM_NODE_FLAG_P(cast->
arguments, PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS | PM_ARGUMENTS_NODE_FLAGS_CONTAINS_SPLAT)) {
13444 if (cast->
block != NULL) {
13452 return accept1(parser, PM_TOKEN_EQUAL_GREATER);
13461 arguments->
arguments = pm_arguments_node_create(parser);
13464 pm_arguments_node_arguments_append(arguments->
arguments, argument);
13471parse_arguments(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_forwarding, pm_token_type_t terminator, uint16_t depth) {
13472 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
13477 match2(parser, terminator, PM_TOKEN_EOF) ||
13478 (binding_power != PM_BINDING_POWER_UNSET && binding_power < PM_BINDING_POWER_RANGE) ||
13484 bool parsed_first_argument =
false;
13485 bool parsed_bare_hash =
false;
13486 bool parsed_block_argument =
false;
13487 bool parsed_forwarding_arguments =
false;
13489 while (!match1(parser, PM_TOKEN_EOF)) {
13490 if (parsed_forwarding_arguments) {
13491 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_FORWARDING_ELLIPSES);
13496 switch (parser->
current.type) {
13497 case PM_TOKEN_USTAR_STAR:
13498 case PM_TOKEN_LABEL: {
13499 if (parsed_bare_hash) {
13500 pm_parser_err_current(parser, PM_ERR_ARGUMENT_BARE_HASH);
13504 argument = UP(hash);
13507 bool contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(hash), (uint16_t) (depth + 1));
13509 parse_arguments_append(parser, arguments, argument);
13511 pm_node_flags_t flags = PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13512 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13513 pm_node_flag_set(UP(arguments->
arguments), flags);
13515 pm_static_literals_free(&hash_keys);
13516 parsed_bare_hash =
true;
13520 case PM_TOKEN_UAMPERSAND: {
13521 parser_lex(parser);
13525 if (token_begins_expression_p(parser->
current.type)) {
13526 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13528 pm_parser_scope_forwarding_block_check(parser, &
operator);
13531 argument = UP(pm_block_argument_node_create(parser, &
operator, expression));
13532 if (parsed_block_argument) {
13533 parse_arguments_append(parser, arguments, argument);
13535 arguments->
block = argument;
13538 if (match1(parser, PM_TOKEN_COMMA)) {
13539 pm_parser_err_current(parser, PM_ERR_ARGUMENT_AFTER_BLOCK);
13542 parsed_block_argument =
true;
13545 case PM_TOKEN_USTAR: {
13546 parser_lex(parser);
13549 if (match4(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_SEMICOLON, PM_TOKEN_BRACKET_RIGHT)) {
13550 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
13551 argument = UP(pm_splat_node_create(parser, &
operator, NULL));
13552 if (parsed_bare_hash) {
13553 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13556 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_SPLAT, (uint16_t) (depth + 1));
13558 if (parsed_bare_hash) {
13559 pm_parser_err(parser,
operator.start, expression->
location.
end, PM_ERR_ARGUMENT_SPLAT_AFTER_ASSOC_SPLAT);
13562 argument = UP(pm_splat_node_create(parser, &
operator, expression));
13565 parse_arguments_append(parser, arguments, argument);
13568 case PM_TOKEN_UDOT_DOT_DOT: {
13569 if (accepts_forwarding) {
13570 parser_lex(parser);
13572 if (token_begins_expression_p(parser->
current.type)) {
13577 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_RANGE,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
13582 if (PM_NODE_TYPE_P(right, PM_RANGE_NODE)) {
13584 pm_parser_err(parser, range->operator_loc.start, range->operator_loc.end, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
13587 argument = UP(pm_range_node_create(parser, NULL, &
operator, right));
13589 pm_parser_scope_forwarding_all_check(parser, &parser->
previous);
13590 if (parsed_first_argument && terminator == PM_TOKEN_EOF) {
13591 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORWARDING_UNBOUND);
13594 argument = UP(pm_forwarding_arguments_node_create(parser, &parser->
previous));
13595 parse_arguments_append(parser, arguments, argument);
13596 pm_node_flag_set(UP(arguments->
arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_FORWARDING);
13598 parsed_forwarding_arguments =
true;
13605 if (argument == NULL) {
13606 argument = parse_value_expression(parser, PM_BINDING_POWER_DEFINED, !parsed_first_argument,
true, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
13609 bool contains_keywords =
false;
13610 bool contains_keyword_splat =
false;
13612 if (argument_allowed_for_bare_hash(parser, argument)){
13613 if (parsed_bare_hash) {
13614 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_BARE_HASH);
13618 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
13621 operator = not_provided(parser);
13625 contains_keywords =
true;
13629 pm_hash_key_static_literals_add(parser, &hash_keys, argument);
13632 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
13633 argument = UP(pm_assoc_node_create(parser, argument, &
operator, value));
13635 pm_keyword_hash_node_elements_append(bare_hash, argument);
13636 argument = UP(bare_hash);
13639 if (accept1(parser, PM_TOKEN_COMMA) && (
13640 token_begins_expression_p(parser->
current.type) ||
13641 match2(parser, PM_TOKEN_USTAR_STAR, PM_TOKEN_LABEL)
13643 contains_keyword_splat = parse_assocs(parser, &hash_keys, UP(bare_hash), (uint16_t) (depth + 1));
13646 pm_static_literals_free(&hash_keys);
13647 parsed_bare_hash =
true;
13650 parse_arguments_append(parser, arguments, argument);
13652 pm_node_flags_t flags = 0;
13653 if (contains_keywords) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS;
13654 if (contains_keyword_splat) flags |= PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORD_SPLAT;
13655 pm_node_flag_set(UP(arguments->
arguments), flags);
13661 parsed_first_argument =
true;
13664 if (PM_NODE_TYPE_P(argument, PM_MISSING_NODE) || parser->
recovering)
break;
13669 bool accepted_newline =
false;
13670 if (terminator != PM_TOKEN_EOF) {
13671 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
13674 if (parser->
previous.
type == PM_TOKEN_COMMA && parsed_bare_hash) {
13678 }
else if (accept1(parser, PM_TOKEN_COMMA)) {
13681 if (accepted_newline) {
13682 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13688 if (PM_NODE_TYPE_P(argument, PM_CALL_NODE)) {
13691 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
13703 if (match1(parser, terminator))
break;
13718parse_required_destructured_parameter(
pm_parser_t *parser) {
13719 expect1(parser, PM_TOKEN_PARENTHESIS_LEFT, PM_ERR_EXPECT_LPAREN_REQ_PARAMETER);
13722 pm_multi_target_node_opening_set(node, &parser->
previous);
13731 if (node->
lefts.
size > 0 && match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
13732 param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
13733 pm_multi_target_node_targets_append(parser, node, param);
13734 pm_parser_err_current(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
13738 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
13739 param = UP(parse_required_destructured_parameter(parser));
13740 }
else if (accept1(parser, PM_TOKEN_USTAR)) {
13744 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13746 value = UP(pm_required_parameter_node_create(parser, &name));
13747 if (pm_parser_parameter_name_check(parser, &name)) {
13748 pm_node_flag_set_repeated_parameter(value);
13750 pm_parser_local_add_token(parser, &name, 1);
13753 param = UP(pm_splat_node_create(parser, &star, value));
13755 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EXPECT_IDENT_REQ_PARAMETER);
13758 param = UP(pm_required_parameter_node_create(parser, &name));
13759 if (pm_parser_parameter_name_check(parser, &name)) {
13760 pm_node_flag_set_repeated_parameter(param);
13762 pm_parser_local_add_token(parser, &name, 1);
13765 pm_multi_target_node_targets_append(parser, node, param);
13766 }
while (accept1(parser, PM_TOKEN_COMMA));
13768 accept1(parser, PM_TOKEN_NEWLINE);
13769 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN_REQ_PARAMETER);
13770 pm_multi_target_node_closing_set(node, &parser->
previous);
13780 PM_PARAMETERS_NO_CHANGE = 0,
13781 PM_PARAMETERS_ORDER_NOTHING_AFTER = 1,
13782 PM_PARAMETERS_ORDER_KEYWORDS_REST,
13783 PM_PARAMETERS_ORDER_KEYWORDS,
13784 PM_PARAMETERS_ORDER_REST,
13785 PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13786 PM_PARAMETERS_ORDER_OPTIONAL,
13787 PM_PARAMETERS_ORDER_NAMED,
13788 PM_PARAMETERS_ORDER_NONE,
13789} pm_parameters_order_t;
13794static pm_parameters_order_t parameters_ordering[PM_TOKEN_MAXIMUM] = {
13795 [0] = PM_PARAMETERS_NO_CHANGE,
13796 [PM_TOKEN_UAMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13797 [PM_TOKEN_AMPERSAND] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13798 [PM_TOKEN_UDOT_DOT_DOT] = PM_PARAMETERS_ORDER_NOTHING_AFTER,
13799 [PM_TOKEN_IDENTIFIER] = PM_PARAMETERS_ORDER_NAMED,
13800 [PM_TOKEN_PARENTHESIS_LEFT] = PM_PARAMETERS_ORDER_NAMED,
13801 [PM_TOKEN_EQUAL] = PM_PARAMETERS_ORDER_OPTIONAL,
13802 [PM_TOKEN_LABEL] = PM_PARAMETERS_ORDER_KEYWORDS,
13803 [PM_TOKEN_USTAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13804 [PM_TOKEN_STAR] = PM_PARAMETERS_ORDER_AFTER_OPTIONAL,
13805 [PM_TOKEN_USTAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST,
13806 [PM_TOKEN_STAR_STAR] = PM_PARAMETERS_ORDER_KEYWORDS_REST
13818 pm_parameters_order_t state = parameters_ordering[token->type];
13819 if (state == PM_PARAMETERS_NO_CHANGE)
return true;
13823 if (*current == PM_PARAMETERS_ORDER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13824 *current = PM_PARAMETERS_ORDER_AFTER_OPTIONAL;
13826 }
else if (*current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL && state == PM_PARAMETERS_ORDER_NAMED) {
13830 if (token->type == PM_TOKEN_USTAR && *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13831 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_STAR);
13833 }
else if (token->type == PM_TOKEN_UDOT_DOT_DOT && (*current >= PM_PARAMETERS_ORDER_KEYWORDS_REST && *current <= PM_PARAMETERS_ORDER_AFTER_OPTIONAL)) {
13834 pm_parser_err_token(parser, token, *current == PM_PARAMETERS_ORDER_AFTER_OPTIONAL ? PM_ERR_PARAMETER_FORWARDING_AFTER_REST : PM_ERR_PARAMETER_ORDER);
13836 }
else if (*current == PM_PARAMETERS_ORDER_NOTHING_AFTER || state > *current) {
13838 pm_parser_err_token(parser, token, PM_ERR_PARAMETER_ORDER);
13842 if (state < *current) *current = state;
13852 pm_binding_power_t binding_power,
13853 bool uses_parentheses,
13854 bool allows_trailing_comma,
13855 bool allows_forwarding_parameters,
13856 bool accepts_blocks_in_defaults,
13860 pm_do_loop_stack_push(parser,
false);
13863 pm_parameters_order_t order = PM_PARAMETERS_ORDER_NONE;
13866 bool parsing =
true;
13868 switch (parser->
current.type) {
13869 case PM_TOKEN_PARENTHESIS_LEFT: {
13870 update_parameter_state(parser, &parser->
current, &order);
13871 pm_node_t *param = UP(parse_required_destructured_parameter(parser));
13873 if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
13874 pm_parameters_node_requireds_append(params, param);
13876 pm_parameters_node_posts_append(params, param);
13880 case PM_TOKEN_UAMPERSAND:
13881 case PM_TOKEN_AMPERSAND: {
13882 update_parameter_state(parser, &parser->
current, &order);
13883 parser_lex(parser);
13888 bool repeated =
false;
13889 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
13891 repeated = pm_parser_parameter_name_check(parser, &name);
13892 pm_parser_local_add_token(parser, &name, 1);
13894 name = not_provided(parser);
13900 pm_node_flag_set_repeated_parameter(UP(param));
13902 if (params->
block == NULL) {
13903 pm_parameters_node_block_set(params, param);
13905 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_BLOCK_MULTI);
13906 pm_parameters_node_posts_append(params, UP(param));
13911 case PM_TOKEN_UDOT_DOT_DOT: {
13912 if (!allows_forwarding_parameters) {
13913 pm_parser_err_current(parser, PM_ERR_ARGUMENT_NO_FORWARDING_ELLIPSES);
13916 bool succeeded = update_parameter_state(parser, &parser->
current, &order);
13917 parser_lex(parser);
13926 pm_parameters_node_posts_append(params, keyword_rest);
13927 if (succeeded) pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_FWD);
13931 pm_parameters_node_keyword_rest_set(params, UP(param));
13934 case PM_TOKEN_CLASS_VARIABLE:
13935 case PM_TOKEN_IDENTIFIER:
13936 case PM_TOKEN_CONSTANT:
13937 case PM_TOKEN_INSTANCE_VARIABLE:
13938 case PM_TOKEN_GLOBAL_VARIABLE:
13939 case PM_TOKEN_METHOD_NAME: {
13940 parser_lex(parser);
13942 case PM_TOKEN_CONSTANT:
13943 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
13945 case PM_TOKEN_INSTANCE_VARIABLE:
13946 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
13948 case PM_TOKEN_GLOBAL_VARIABLE:
13949 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
13951 case PM_TOKEN_CLASS_VARIABLE:
13952 pm_parser_err_previous(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
13954 case PM_TOKEN_METHOD_NAME:
13955 pm_parser_err_previous(parser, PM_ERR_PARAMETER_METHOD_NAME);
13960 if (parser->
current.type == PM_TOKEN_EQUAL) {
13961 update_parameter_state(parser, &parser->
current, &order);
13963 update_parameter_state(parser, &parser->
previous, &order);
13967 bool repeated = pm_parser_parameter_name_check(parser, &name);
13968 pm_parser_local_add_token(parser, &name, 1);
13970 if (match1(parser, PM_TOKEN_EQUAL)) {
13973 parser_lex(parser);
13978 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
13979 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT, (uint16_t) (depth + 1));
13980 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
13985 pm_node_flag_set_repeated_parameter(UP(param));
13987 pm_parameters_node_optionals_append(params, param);
13993 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, name, PM_ERR_PARAMETER_CIRCULAR);
13996 context_pop(parser);
14005 }
else if (order > PM_PARAMETERS_ORDER_AFTER_OPTIONAL) {
14008 pm_node_flag_set_repeated_parameter(UP(param));
14010 pm_parameters_node_requireds_append(params, UP(param));
14014 pm_node_flag_set_repeated_parameter(UP(param));
14016 pm_parameters_node_posts_append(params, UP(param));
14021 case PM_TOKEN_LABEL: {
14022 if (!uses_parentheses && !in_block) parser->
in_keyword_arg =
true;
14023 update_parameter_state(parser, &parser->
current, &order);
14026 parser_lex(parser);
14033 pm_parser_err(parser, local.
start, local.
end, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14034 }
else if (local.
end[-1] ==
'!' || local.
end[-1] ==
'?') {
14035 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_INVALID_LOCAL_VARIABLE_WRITE);
14038 bool repeated = pm_parser_parameter_name_check(parser, &local);
14039 pm_parser_local_add_token(parser, &local, 1);
14041 switch (parser->
current.type) {
14042 case PM_TOKEN_COMMA:
14043 case PM_TOKEN_PARENTHESIS_RIGHT:
14044 case PM_TOKEN_PIPE: {
14045 context_pop(parser);
14047 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14049 pm_node_flag_set_repeated_parameter(param);
14052 pm_parameters_node_keywords_append(params, param);
14055 case PM_TOKEN_SEMICOLON:
14056 case PM_TOKEN_NEWLINE: {
14057 context_pop(parser);
14059 if (uses_parentheses) {
14064 pm_node_t *param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14066 pm_node_flag_set_repeated_parameter(param);
14069 pm_parameters_node_keywords_append(params, param);
14075 if (token_begins_expression_p(parser->
current.type)) {
14079 if (accepts_blocks_in_defaults) pm_accepts_block_stack_push(parser,
true);
14080 pm_node_t *value = parse_value_expression(parser, binding_power,
false,
false, PM_ERR_PARAMETER_NO_DEFAULT_KW, (uint16_t) (depth + 1));
14081 if (accepts_blocks_in_defaults) pm_accepts_block_stack_pop(parser);
14084 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, local, PM_ERR_PARAMETER_CIRCULAR);
14087 param = UP(pm_optional_keyword_parameter_node_create(parser, &name, value));
14090 param = UP(pm_required_keyword_parameter_node_create(parser, &name));
14094 pm_node_flag_set_repeated_parameter(param);
14097 context_pop(parser);
14098 pm_parameters_node_keywords_append(params, param);
14113 case PM_TOKEN_USTAR:
14114 case PM_TOKEN_STAR: {
14115 update_parameter_state(parser, &parser->
current, &order);
14116 parser_lex(parser);
14120 bool repeated =
false;
14122 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14124 repeated = pm_parser_parameter_name_check(parser, &name);
14125 pm_parser_local_add_token(parser, &name, 1);
14127 name = not_provided(parser);
14131 pm_node_t *param = UP(pm_rest_parameter_node_create(parser, &
operator, &name));
14133 pm_node_flag_set_repeated_parameter(param);
14136 if (params->
rest == NULL) {
14137 pm_parameters_node_rest_set(params, param);
14139 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_SPLAT_MULTI);
14140 pm_parameters_node_posts_append(params, param);
14145 case PM_TOKEN_STAR_STAR:
14146 case PM_TOKEN_USTAR_STAR: {
14147 pm_parameters_order_t previous_order = order;
14148 update_parameter_state(parser, &parser->
current, &order);
14149 parser_lex(parser);
14154 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
14155 if (previous_order <= PM_PARAMETERS_ORDER_KEYWORDS) {
14156 pm_parser_err_previous(parser, PM_ERR_PARAMETER_UNEXPECTED_NO_KW);
14159 param = UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
14163 bool repeated =
false;
14164 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
14166 repeated = pm_parser_parameter_name_check(parser, &name);
14167 pm_parser_local_add_token(parser, &name, 1);
14169 name = not_provided(parser);
14173 param = UP(pm_keyword_rest_parameter_node_create(parser, &
operator, &name));
14175 pm_node_flag_set_repeated_parameter(param);
14180 pm_parameters_node_keyword_rest_set(params, param);
14182 pm_parser_err_node(parser, param, PM_ERR_PARAMETER_ASSOC_SPLAT_MULTI);
14183 pm_parameters_node_posts_append(params, param);
14190 if (allows_trailing_comma && order >= PM_PARAMETERS_ORDER_NAMED) {
14193 pm_node_t *param = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
14195 if (params->
rest == NULL) {
14196 pm_parameters_node_rest_set(params, param);
14198 pm_parser_err_node(parser, UP(param), PM_ERR_PARAMETER_SPLAT_MULTI);
14199 pm_parameters_node_posts_append(params, UP(param));
14202 pm_parser_err_previous(parser, PM_ERR_PARAMETER_WILD_LOOSE_COMMA);
14213 if (!parsing)
break;
14215 bool accepted_newline =
false;
14216 if (uses_parentheses) {
14217 accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
14220 if (accept1(parser, PM_TOKEN_COMMA)) {
14223 if (accepted_newline) {
14224 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
14232 pm_do_loop_stack_pop(parser);
14236 pm_node_destroy(parser, UP(params));
14268token_column(
const pm_parser_t *parser,
size_t newline_index,
const pm_token_t *token,
bool break_on_non_space) {
14270 const uint8_t *end = token->start;
14274 newline_index == 0 &&
14275 parser->
start[0] == 0xef &&
14276 parser->
start[1] == 0xbb &&
14277 parser->
start[2] == 0xbf
14280 int64_t column = 0;
14281 for (; cursor < end; cursor++) {
14284 column = ((column / PM_TAB_WHITESPACE_SIZE) + 1) * PM_TAB_WHITESPACE_SIZE;
14291 if (break_on_non_space)
return -1;
14304parser_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) {
14309 size_t closing_newline_index = token_newline_index(parser);
14310 if (opening_newline_index == closing_newline_index)
return;
14315 int64_t opening_column = token_column(parser, opening_newline_index, opening_token, !if_after_else);
14316 if (!if_after_else && (opening_column == -1))
return;
14323 int64_t closing_column = token_column(parser, closing_newline_index, closing_token,
true);
14324 if ((closing_column == -1) || (opening_column == closing_column))
return;
14328 if (allow_indent && (closing_column > opening_column))
return;
14331 PM_PARSER_WARN_FORMAT(
14333 closing_token->
start,
14334 closing_token->
end,
14335 PM_WARN_INDENTATION_MISMATCH,
14336 (
int) (closing_token->
end - closing_token->
start),
14337 (
const char *) closing_token->
start,
14338 (
int) (opening_token->
end - opening_token->
start),
14339 (
const char *) opening_token->
start,
14340 ((int32_t) opening_newline_index) + parser->
start_line
14345 PM_RESCUES_BEGIN = 1,
14352} pm_rescues_type_t;
14362 while (match1(parser, PM_TOKEN_KEYWORD_RESCUE)) {
14363 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14364 parser_lex(parser);
14368 switch (parser->
current.type) {
14369 case PM_TOKEN_EQUAL_GREATER: {
14373 parser_lex(parser);
14374 pm_rescue_node_operator_set(rescue, &parser->
previous);
14376 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14377 reference = parse_target(parser, reference,
false,
false);
14379 pm_rescue_node_reference_set(rescue, reference);
14382 case PM_TOKEN_NEWLINE:
14383 case PM_TOKEN_SEMICOLON:
14384 case PM_TOKEN_KEYWORD_THEN:
14389 if (token_begins_expression_p(parser->
current.type) || match1(parser, PM_TOKEN_USTAR)) {
14394 pm_node_t *expression = parse_starred_expression(parser, PM_BINDING_POWER_DEFINED,
false, PM_ERR_RESCUE_EXPRESSION, (uint16_t) (depth + 1));
14395 pm_rescue_node_exceptions_append(rescue, expression);
14399 if (match3(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_TOKEN_KEYWORD_THEN))
break;
14403 if (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
14404 pm_rescue_node_operator_set(rescue, &parser->
previous);
14406 pm_node_t *reference = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_RESCUE_VARIABLE, (uint16_t) (depth + 1));
14407 reference = parse_target(parser, reference,
false,
false);
14409 pm_rescue_node_reference_set(rescue, reference);
14412 }
while (accept1(parser, PM_TOKEN_COMMA));
14417 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
14418 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
14422 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_RESCUE_TERM);
14426 if (!match3(parser, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_END)) {
14427 pm_accepts_block_stack_push(parser,
true);
14442 if (statements != NULL) pm_rescue_node_statements_set(rescue, statements);
14444 pm_accepts_block_stack_pop(parser);
14445 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14448 if (current == NULL) {
14449 pm_begin_node_rescue_clause_set(parent_node, rescue);
14451 pm_rescue_node_subsequent_set(current, rescue);
14460 if (current != NULL) {
14464 while (clause != NULL) {
14471 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
14472 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14473 opening_newline_index = token_newline_index(parser);
14475 else_keyword = parser->
current;
14476 opening = &else_keyword;
14478 parser_lex(parser);
14479 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14482 if (!match2(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_ENSURE)) {
14483 pm_accepts_block_stack_push(parser,
true);
14497 else_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14498 pm_accepts_block_stack_pop(parser);
14500 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14503 pm_else_node_t *else_clause = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
current);
14504 pm_begin_node_else_clause_set(parent_node, else_clause);
14508 if (current == NULL) pm_parser_err_node(parser, UP(else_clause), PM_ERR_BEGIN_LONELY_ELSE);
14511 if (match1(parser, PM_TOKEN_KEYWORD_ENSURE)) {
14512 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14515 parser_lex(parser);
14516 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14519 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14520 pm_accepts_block_stack_push(parser,
true);
14534 ensure_statements = parse_statements(parser, context, (uint16_t) (depth + 1));
14535 pm_accepts_block_stack_pop(parser);
14537 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
14540 pm_ensure_node_t *ensure_clause = pm_ensure_node_create(parser, &ensure_keyword, ensure_statements, &parser->
current);
14541 pm_begin_node_ensure_clause_set(parent_node, ensure_clause);
14544 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
14545 if (opening != NULL) parser_warn_indentation_mismatch(parser, opening_newline_index, opening,
false,
false);
14546 pm_begin_node_end_keyword_set(parent_node, &parser->
current);
14549 pm_begin_node_end_keyword_set(parent_node, &end_keyword);
14559 pm_token_t begin_keyword = not_provided(parser);
14560 pm_begin_node_t *node = pm_begin_node_create(parser, &begin_keyword, statements);
14562 parse_rescues(parser, opening_newline_index, opening, node,
type, (uint16_t) (depth + 1));
14572parse_block_parameters(
14574 bool allows_trailing_comma,
14576 bool is_lambda_literal,
14577 bool accepts_blocks_in_defaults,
14581 if (!match1(parser, PM_TOKEN_SEMICOLON)) {
14582 if (!is_lambda_literal) {
14585 parameters = parse_parameters(
14587 is_lambda_literal ? PM_BINDING_POWER_DEFINED : PM_BINDING_POWER_INDEX,
14589 allows_trailing_comma,
14591 accepts_blocks_in_defaults,
14593 (uint16_t) (depth + 1)
14595 if (!is_lambda_literal) {
14596 context_pop(parser);
14601 if ((opening->
type != PM_TOKEN_NOT_PROVIDED)) {
14602 accept1(parser, PM_TOKEN_NEWLINE);
14604 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
14606 switch (parser->
current.type) {
14607 case PM_TOKEN_CONSTANT:
14608 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CONSTANT);
14609 parser_lex(parser);
14611 case PM_TOKEN_INSTANCE_VARIABLE:
14612 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_IVAR);
14613 parser_lex(parser);
14615 case PM_TOKEN_GLOBAL_VARIABLE:
14616 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_GLOBAL);
14617 parser_lex(parser);
14619 case PM_TOKEN_CLASS_VARIABLE:
14620 pm_parser_err_current(parser, PM_ERR_ARGUMENT_FORMAL_CLASS);
14621 parser_lex(parser);
14624 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_BLOCK_PARAM_LOCAL_VARIABLE);
14628 bool repeated = pm_parser_parameter_name_check(parser, &parser->
previous);
14629 pm_parser_local_add_token(parser, &parser->
previous, 1);
14632 if (repeated) pm_node_flag_set_repeated_parameter(UP(local));
14634 pm_block_parameters_node_append_local(block_parameters, local);
14635 }
while (accept1(parser, PM_TOKEN_COMMA));
14639 return block_parameters;
14647outer_scope_using_numbered_parameters_p(
pm_parser_t *parser) {
14649 if (scope->
parameters & PM_SCOPE_PARAMETERS_NUMBERED_FOUND)
return true;
14660static const char *
const pm_numbered_parameter_names[] = {
14661 "_1",
"_2",
"_3",
"_4",
"_5",
"_6",
"_7",
"_8",
"_9"
14675 if (parameters != NULL) {
14677 if (implicit_parameters->
size > 0) {
14680 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14681 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_ORDINARY);
14682 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14683 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_ORDINARY);
14685 assert(
false &&
"unreachable");
14694 if (implicit_parameters->
size == 0) {
14701 uint8_t numbered_parameter = 0;
14702 bool it_parameter =
false;
14704 for (
size_t index = 0; index < implicit_parameters->
size; index++) {
14707 if (PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE)) {
14708 if (it_parameter) {
14709 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_IT);
14710 }
else if (outer_scope_using_numbered_parameters_p(parser)) {
14711 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_OUTER_BLOCK);
14713 pm_parser_err_node(parser, node, PM_ERR_NUMBERED_PARAMETER_INNER_BLOCK);
14715 numbered_parameter = MAX(numbered_parameter, (uint8_t) (node->
location.
start[1] -
'0'));
14717 assert(
false &&
"unreachable");
14719 }
else if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
14720 if (numbered_parameter > 0) {
14721 pm_parser_err_node(parser, node, PM_ERR_IT_NOT_ALLOWED_NUMBERED);
14723 it_parameter =
true;
14728 if (numbered_parameter > 0) {
14732 scope->
parameters |= PM_SCOPE_PARAMETERS_NUMBERED_INNER;
14736 return UP(pm_numbered_parameters_node_create(parser, &location, numbered_parameter));
14739 if (it_parameter) {
14740 return UP(pm_it_parameters_node_create(parser, opening, closing));
14750parse_block(
pm_parser_t *parser, uint16_t depth) {
14752 accept1(parser, PM_TOKEN_NEWLINE);
14754 pm_accepts_block_stack_push(parser,
true);
14755 pm_parser_scope_push(parser,
false);
14759 if (accept1(parser, PM_TOKEN_PIPE)) {
14761 if (match1(parser, PM_TOKEN_PIPE)) {
14762 block_parameters = pm_block_parameters_node_create(parser, NULL, &block_parameters_opening);
14764 parser_lex(parser);
14766 block_parameters = parse_block_parameters(parser,
true, &block_parameters_opening,
false,
true, (uint16_t) (depth + 1));
14767 accept1(parser, PM_TOKEN_NEWLINE);
14769 expect1(parser, PM_TOKEN_PIPE, PM_ERR_BLOCK_PARAM_PIPE_TERM);
14772 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
14775 accept1(parser, PM_TOKEN_NEWLINE);
14778 if (opening.
type == PM_TOKEN_BRACE_LEFT) {
14779 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
14783 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BLOCK_TERM_BRACE, &opening);
14785 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
14786 if (!match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_ENSURE)) {
14787 pm_accepts_block_stack_push(parser,
true);
14789 pm_accepts_block_stack_pop(parser);
14792 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
14793 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
14794 statements = UP(parse_rescues_implicit_begin(parser, 0, NULL, opening.
start, (
pm_statements_node_t *) statements, PM_RESCUES_BLOCK, (uint16_t) (depth + 1)));
14798 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BLOCK_TERM_END, &opening);
14802 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
14803 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &opening, &parser->
previous);
14805 pm_parser_scope_pop(parser);
14806 pm_accepts_block_stack_pop(parser);
14808 return pm_block_node_create(parser, &locals, &opening, parameters, statements, &parser->
previous);
14817parse_arguments_list(
pm_parser_t *parser,
pm_arguments_t *arguments,
bool accepts_block,
bool accepts_command_call, uint16_t depth) {
14818 bool found =
false;
14820 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
14824 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14827 pm_accepts_block_stack_push(parser,
true);
14828 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_PARENTHESIS_RIGHT, (uint16_t) (depth + 1));
14830 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
14836 pm_accepts_block_stack_pop(parser);
14839 }
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)) {
14841 pm_accepts_block_stack_push(parser,
false);
14846 parse_arguments(parser, arguments, accepts_block, PM_TOKEN_EOF, (uint16_t) (depth + 1));
14851 if (parser->
previous.
type == PM_TOKEN_COMMA && !match1(parser, PM_TOKEN_SEMICOLON)) {
14855 pm_accepts_block_stack_pop(parser);
14861 if (accepts_block) {
14864 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
14866 block = parse_block(parser, (uint16_t) (depth + 1));
14867 pm_arguments_validate_block(parser, arguments, block);
14868 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
14870 block = parse_block(parser, (uint16_t) (depth + 1));
14873 if (block != NULL) {
14875 arguments->
block = UP(block);
14877 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_BLOCK_MULTI);
14879 if (arguments->
block != NULL) {
14881 arguments->
arguments = pm_arguments_node_create(parser);
14883 pm_arguments_node_arguments_append(arguments->
arguments, arguments->
block);
14885 arguments->
block = UP(block);
14899 bool in_sclass =
false;
14901 switch (context_node->
context) {
14946 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14969 assert(
false &&
"unreachable");
14974 pm_parser_err_node(parser, node, PM_ERR_RETURN_INVALID);
14985 switch (context_node->
context) {
15060 assert(
false &&
"unreachable");
15074 return previous_block_exits;
15088 switch (PM_NODE_TYPE(block_exit)) {
15089 case PM_BREAK_NODE:
type =
"break";
break;
15090 case PM_NEXT_NODE:
type =
"next";
break;
15091 case PM_REDO_NODE:
type =
"redo";
break;
15092 default: assert(
false &&
"unreachable");
type =
"";
break;
15095 PM_PARSER_ERR_NODE_FORMAT(parser, block_exit, PM_ERR_INVALID_BLOCK_EXIT,
type);
15107 if (match2(parser, PM_TOKEN_KEYWORD_WHILE_MODIFIER, PM_TOKEN_KEYWORD_UNTIL_MODIFIER)) {
15112 }
else if (previous_block_exits != NULL) {
15124 flush_block_exits(parser, previous_block_exits);
15132 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, error_id, (uint16_t) (depth + 1));
15135 bool predicate_closed = accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15137 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
15138 predicate_closed =
true;
15142 if (!predicate_closed) {
15143 pm_parser_err_current(parser, PM_ERR_CONDITIONAL_PREDICATE_TERM);
15146 context_pop(parser);
15151parse_conditional(
pm_parser_t *parser,
pm_context_t context,
size_t opening_newline_index,
bool if_after_else, uint16_t depth) {
15153 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
15156 pm_token_t then_keyword = not_provided(parser);
15158 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER, context, &then_keyword, (uint16_t) (depth + 1));
15161 if (!match3(parser, PM_TOKEN_KEYWORD_ELSIF, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
15162 pm_accepts_block_stack_push(parser,
true);
15163 statements = parse_statements(parser, context, (uint16_t) (depth + 1));
15164 pm_accepts_block_stack_pop(parser);
15165 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15168 pm_token_t end_keyword = not_provided(parser);
15173 parent = UP(pm_if_node_create(parser, &keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15176 parent = UP(pm_unless_node_create(parser, &keyword, predicate, &then_keyword, statements));
15179 assert(
false &&
"unreachable");
15188 while (match1(parser, PM_TOKEN_KEYWORD_ELSIF)) {
15189 if (parser_end_of_line_p(parser)) {
15190 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
15193 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15195 parser_lex(parser);
15197 pm_node_t *predicate = parse_predicate(parser, PM_BINDING_POWER_MODIFIER,
PM_CONTEXT_ELSIF, &then_keyword, (uint16_t) (depth + 1));
15198 pm_accepts_block_stack_push(parser,
true);
15201 pm_accepts_block_stack_pop(parser);
15202 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15204 pm_node_t *elsif = UP(pm_if_node_create(parser, &elsif_keyword, predicate, &then_keyword, statements, NULL, &end_keyword));
15210 if (match1(parser, PM_TOKEN_KEYWORD_ELSE)) {
15211 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
15212 opening_newline_index = token_newline_index(parser);
15214 parser_lex(parser);
15217 pm_accepts_block_stack_push(parser,
true);
15219 pm_accepts_block_stack_pop(parser);
15221 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
15222 parser_warn_indentation_mismatch(parser, opening_newline_index, &else_keyword,
false,
false);
15223 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM_ELSE, &keyword);
15225 pm_else_node_t *else_node = pm_else_node_create(parser, &else_keyword, else_statements, &parser->
previous);
15229 ((
pm_if_node_t *) current)->subsequent = UP(else_node);
15235 assert(
false &&
"unreachable");
15239 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword, if_after_else,
false);
15240 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CONDITIONAL_TERM, &keyword);
15247 bool recursing =
true;
15249 while (recursing) {
15250 switch (PM_NODE_TYPE(current)) {
15254 recursing = current != NULL;
15272 assert(
false &&
"unreachable");
15276 pop_block_exits(parser, previous_block_exits);
15277 pm_node_list_free(¤t_block_exits);
15286#define PM_CASE_KEYWORD PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15287 case PM_TOKEN_KEYWORD_ALIAS: case PM_TOKEN_KEYWORD_AND: case PM_TOKEN_KEYWORD_BEGIN: case PM_TOKEN_KEYWORD_BEGIN_UPCASE: \
15288 case PM_TOKEN_KEYWORD_BREAK: case PM_TOKEN_KEYWORD_CASE: case PM_TOKEN_KEYWORD_CLASS: case PM_TOKEN_KEYWORD_DEF: \
15289 case PM_TOKEN_KEYWORD_DEFINED: case PM_TOKEN_KEYWORD_DO: case PM_TOKEN_KEYWORD_DO_LOOP: case PM_TOKEN_KEYWORD_ELSE: \
15290 case PM_TOKEN_KEYWORD_ELSIF: case PM_TOKEN_KEYWORD_END: case PM_TOKEN_KEYWORD_END_UPCASE: case PM_TOKEN_KEYWORD_ENSURE: \
15291 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD_FOR: case PM_TOKEN_KEYWORD_IF: case PM_TOKEN_KEYWORD_IN: \
15292 case PM_TOKEN_KEYWORD_MODULE: case PM_TOKEN_KEYWORD_NEXT: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_NOT: \
15293 case PM_TOKEN_KEYWORD_OR: case PM_TOKEN_KEYWORD_REDO: case PM_TOKEN_KEYWORD_RESCUE: case PM_TOKEN_KEYWORD_RETRY: \
15294 case PM_TOKEN_KEYWORD_RETURN: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_SUPER: case PM_TOKEN_KEYWORD_THEN: \
15295 case PM_TOKEN_KEYWORD_TRUE: case PM_TOKEN_KEYWORD_UNDEF: case PM_TOKEN_KEYWORD_UNLESS: case PM_TOKEN_KEYWORD_UNTIL: \
15296 case PM_TOKEN_KEYWORD_WHEN: case PM_TOKEN_KEYWORD_WHILE: case PM_TOKEN_KEYWORD_YIELD
15302#define PM_CASE_OPERATOR PM_TOKEN_AMPERSAND: case PM_TOKEN_BACKTICK: case PM_TOKEN_BANG_EQUAL: \
15303 case PM_TOKEN_BANG_TILDE: case PM_TOKEN_BANG: case PM_TOKEN_BRACKET_LEFT_RIGHT_EQUAL: \
15304 case PM_TOKEN_BRACKET_LEFT_RIGHT: case PM_TOKEN_CARET: case PM_TOKEN_EQUAL_EQUAL_EQUAL: case PM_TOKEN_EQUAL_EQUAL: \
15305 case PM_TOKEN_EQUAL_TILDE: case PM_TOKEN_GREATER_EQUAL: case PM_TOKEN_GREATER_GREATER: case PM_TOKEN_GREATER: \
15306 case PM_TOKEN_LESS_EQUAL_GREATER: case PM_TOKEN_LESS_EQUAL: case PM_TOKEN_LESS_LESS: case PM_TOKEN_LESS: \
15307 case PM_TOKEN_MINUS: case PM_TOKEN_PERCENT: case PM_TOKEN_PIPE: case PM_TOKEN_PLUS: case PM_TOKEN_SLASH: \
15308 case PM_TOKEN_STAR_STAR: case PM_TOKEN_STAR: case PM_TOKEN_TILDE: case PM_TOKEN_UAMPERSAND: case PM_TOKEN_UMINUS: \
15309 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_UPLUS: case PM_TOKEN_USTAR: case PM_TOKEN_USTAR_STAR
15316#define PM_CASE_PRIMITIVE PM_TOKEN_INTEGER: case PM_TOKEN_INTEGER_IMAGINARY: case PM_TOKEN_INTEGER_RATIONAL: \
15317 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: case PM_TOKEN_FLOAT: case PM_TOKEN_FLOAT_IMAGINARY: \
15318 case PM_TOKEN_FLOAT_RATIONAL: case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY: case PM_TOKEN_SYMBOL_BEGIN: \
15319 case PM_TOKEN_REGEXP_BEGIN: case PM_TOKEN_BACKTICK: case PM_TOKEN_PERCENT_LOWER_X: case PM_TOKEN_PERCENT_LOWER_I: \
15320 case PM_TOKEN_PERCENT_LOWER_W: case PM_TOKEN_PERCENT_UPPER_I: case PM_TOKEN_PERCENT_UPPER_W: \
15321 case PM_TOKEN_STRING_BEGIN: case PM_TOKEN_KEYWORD_NIL: case PM_TOKEN_KEYWORD_SELF: case PM_TOKEN_KEYWORD_TRUE: \
15322 case PM_TOKEN_KEYWORD_FALSE: case PM_TOKEN_KEYWORD___FILE__: case PM_TOKEN_KEYWORD___LINE__: \
15323 case PM_TOKEN_KEYWORD___ENCODING__: case PM_TOKEN_MINUS_GREATER: case PM_TOKEN_HEREDOC_START: \
15324 case PM_TOKEN_UMINUS_NUM: case PM_TOKEN_CHARACTER_LITERAL
15330#define PM_CASE_PARAMETER PM_TOKEN_UAMPERSAND: case PM_TOKEN_AMPERSAND: case PM_TOKEN_UDOT_DOT_DOT: \
15331 case PM_TOKEN_IDENTIFIER: case PM_TOKEN_LABEL: case PM_TOKEN_USTAR: case PM_TOKEN_STAR: case PM_TOKEN_STAR_STAR: \
15332 case PM_TOKEN_USTAR_STAR: case PM_TOKEN_CONSTANT: case PM_TOKEN_INSTANCE_VARIABLE: case PM_TOKEN_GLOBAL_VARIABLE: \
15333 case PM_TOKEN_CLASS_VARIABLE
15339#define PM_CASE_WRITABLE PM_CLASS_VARIABLE_READ_NODE: case PM_CONSTANT_PATH_NODE: \
15340 case PM_CONSTANT_READ_NODE: case PM_GLOBAL_VARIABLE_READ_NODE: case PM_LOCAL_VARIABLE_READ_NODE: \
15341 case PM_INSTANCE_VARIABLE_READ_NODE: case PM_MULTI_TARGET_NODE: case PM_BACK_REFERENCE_READ_NODE: \
15342 case PM_NUMBERED_REFERENCE_READ_NODE: case PM_IT_LOCAL_VARIABLE_READ_NODE
15346PM_STATIC_ASSERT(__LINE__, ((
int) PM_STRING_FLAGS_FORCED_UTF8_ENCODING) == ((
int) PM_ENCODING_FLAGS_FORCED_UTF8_ENCODING),
"Expected the flags to match.");
15352static inline pm_node_flags_t
15353parse_unescaped_encoding(
const pm_parser_t *parser) {
15358 return PM_STRING_FLAGS_FORCED_UTF8_ENCODING;
15364 return PM_STRING_FLAGS_FORCED_BINARY_ENCODING;
15375parse_string_part(
pm_parser_t *parser, uint16_t depth) {
15376 switch (parser->
current.type) {
15383 case PM_TOKEN_STRING_CONTENT: {
15387 pm_node_t *node = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
15388 pm_node_flag_set(node, parse_unescaped_encoding(parser));
15390 parser_lex(parser);
15399 case PM_TOKEN_EMBEXPR_BEGIN: {
15408 lex_state_set(parser, PM_LEX_STATE_BEG);
15409 parser_lex(parser);
15414 if (!match1(parser, PM_TOKEN_EMBEXPR_END)) {
15415 pm_accepts_block_stack_push(parser,
true);
15417 pm_accepts_block_stack_pop(parser);
15421 lex_state_set(parser, state);
15423 expect1(parser, PM_TOKEN_EMBEXPR_END, PM_ERR_EMBEXPR_END);
15429 if (statements != NULL && statements->
body.
size == 1) {
15430 pm_node_flag_unset(statements->
body.
nodes[0], PM_NODE_FLAG_NEWLINE);
15433 return UP(pm_embedded_statements_node_create(parser, &opening, statements, &closing));
15442 case PM_TOKEN_EMBVAR: {
15447 lex_state_set(parser, PM_LEX_STATE_BEG);
15448 parser_lex(parser);
15453 switch (parser->
current.type) {
15456 case PM_TOKEN_BACK_REFERENCE:
15457 parser_lex(parser);
15458 variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15462 case PM_TOKEN_NUMBERED_REFERENCE:
15463 parser_lex(parser);
15464 variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15468 case PM_TOKEN_GLOBAL_VARIABLE:
15469 parser_lex(parser);
15470 variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15474 case PM_TOKEN_INSTANCE_VARIABLE:
15475 parser_lex(parser);
15476 variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
15480 case PM_TOKEN_CLASS_VARIABLE:
15481 parser_lex(parser);
15482 variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
15488 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_EMBVAR_INVALID);
15489 variable = UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15493 return UP(pm_embedded_variable_node_create(parser, &
operator, variable));
15496 parser_lex(parser);
15497 pm_parser_err_previous(parser, PM_ERR_CANNOT_PARSE_STRING_PART);
15507static const uint8_t *
15508parse_operator_symbol_name(
const pm_token_t *name) {
15509 switch (name->
type) {
15510 case PM_TOKEN_TILDE:
15511 case PM_TOKEN_BANG:
15512 if (name->
end[-1] ==
'@')
return name->
end - 1;
15524 const uint8_t *end = parse_operator_symbol_name(&parser->
current);
15526 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15527 parser_lex(parser);
15530 pm_node_flag_set(UP(symbol), PM_SYMBOL_FLAGS_FORCED_US_ASCII_ENCODING);
15544 if (lex_mode->
mode != PM_LEX_STRING) {
15545 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15547 switch (parser->
current.type) {
15548 case PM_CASE_OPERATOR:
15549 return parse_operator_symbol(parser, &opening, next_state == PM_LEX_STATE_NONE ? PM_LEX_STATE_ENDFN : next_state);
15550 case PM_TOKEN_IDENTIFIER:
15551 case PM_TOKEN_CONSTANT:
15552 case PM_TOKEN_INSTANCE_VARIABLE:
15553 case PM_TOKEN_METHOD_NAME:
15554 case PM_TOKEN_CLASS_VARIABLE:
15555 case PM_TOKEN_GLOBAL_VARIABLE:
15556 case PM_TOKEN_NUMBERED_REFERENCE:
15557 case PM_TOKEN_BACK_REFERENCE:
15558 case PM_CASE_KEYWORD:
15559 parser_lex(parser);
15562 expect2(parser, PM_TOKEN_IDENTIFIER, PM_TOKEN_METHOD_NAME, PM_ERR_SYMBOL_INVALID);
15570 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15577 if (match1(parser, PM_TOKEN_STRING_END)) {
15578 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15579 parser_lex(parser);
15583 return UP(pm_symbol_node_create(parser, &opening, &content, &closing));
15587 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
15591 if (part && PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15592 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15593 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15599 if (part) pm_interpolated_symbol_node_append(symbol, part);
15601 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15602 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
15603 pm_interpolated_symbol_node_append(symbol, part);
15607 if (next_state != PM_LEX_STATE_NONE) lex_state_set(parser, next_state);
15608 if (match1(parser, PM_TOKEN_EOF)) {
15609 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15611 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_INTERPOLATED);
15614 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15621 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15624 parser_lex(parser);
15635 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
15639 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &unescaped));
15640 pm_interpolated_symbol_node_append(symbol, part);
15642 part = UP(pm_string_node_create_unescaped(parser, &bounds, &parser->
current, &bounds, &parser->
current_string));
15643 pm_interpolated_symbol_node_append(symbol, part);
15645 if (next_state != PM_LEX_STATE_NONE) {
15646 lex_state_set(parser, next_state);
15649 parser_lex(parser);
15650 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15652 pm_interpolated_symbol_node_closing_loc_set(symbol, &parser->
previous);
15657 pm_string_shared_init(&unescaped, content.
start, content.
end);
15660 if (next_state != PM_LEX_STATE_NONE) {
15661 lex_state_set(parser, next_state);
15664 if (match1(parser, PM_TOKEN_EOF)) {
15665 pm_parser_err_token(parser, &opening, PM_ERR_SYMBOL_TERM_DYNAMIC);
15667 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_SYMBOL_TERM_DYNAMIC);
15670 return UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
false)));
15678parse_undef_argument(
pm_parser_t *parser, uint16_t depth) {
15679 switch (parser->
current.type) {
15680 case PM_CASE_OPERATOR: {
15681 const pm_token_t opening = not_provided(parser);
15682 return parse_operator_symbol(parser, &opening, PM_LEX_STATE_NONE);
15684 case PM_CASE_KEYWORD:
15685 case PM_TOKEN_CONSTANT:
15686 case PM_TOKEN_IDENTIFIER:
15687 case PM_TOKEN_METHOD_NAME: {
15688 parser_lex(parser);
15695 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15699 case PM_TOKEN_SYMBOL_BEGIN: {
15701 parser_lex(parser);
15703 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15706 pm_parser_err_current(parser, PM_ERR_UNDEF_ARGUMENT);
15707 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15718parse_alias_argument(
pm_parser_t *parser,
bool first, uint16_t depth) {
15719 switch (parser->
current.type) {
15720 case PM_CASE_OPERATOR: {
15721 const pm_token_t opening = not_provided(parser);
15722 return parse_operator_symbol(parser, &opening, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE);
15724 case PM_CASE_KEYWORD:
15725 case PM_TOKEN_CONSTANT:
15726 case PM_TOKEN_IDENTIFIER:
15727 case PM_TOKEN_METHOD_NAME: {
15728 if (first) lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
15729 parser_lex(parser);
15736 pm_node_flag_set(UP(symbol), parse_symbol_encoding(parser, &parser->
previous, &symbol->
unescaped,
false));
15740 case PM_TOKEN_SYMBOL_BEGIN: {
15742 parser_lex(parser);
15744 return parse_symbol(parser, &lex_mode, first ? PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM : PM_LEX_STATE_NONE, (uint16_t) (depth + 1));
15746 case PM_TOKEN_BACK_REFERENCE:
15747 parser_lex(parser);
15748 return UP(pm_back_reference_read_node_create(parser, &parser->
previous));
15749 case PM_TOKEN_NUMBERED_REFERENCE:
15750 parser_lex(parser);
15751 return UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
15752 case PM_TOKEN_GLOBAL_VARIABLE:
15753 parser_lex(parser);
15754 return UP(pm_global_variable_read_node_create(parser, &parser->
previous));
15756 pm_parser_err_current(parser, PM_ERR_ALIAS_ARGUMENT);
15757 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
15771 if (!is_numbered_param && ((depth = pm_parser_local_depth_constant_id(parser, name_id)) != -1)) {
15772 return UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, (uint32_t) depth,
false));
15776 if (!current_scope->
closed && !(current_scope->
parameters & PM_SCOPE_PARAMETERS_IMPLICIT_DISALLOWED)) {
15777 if (is_numbered_param) {
15782 uint8_t maximum = (uint8_t) (parser->
previous.
start[1] -
'0');
15783 for (uint8_t number = 1; number <= maximum; number++) {
15784 pm_parser_local_add_constant(parser, pm_numbered_parameter_names[number - 1], 2);
15787 if (!match1(parser, PM_TOKEN_EQUAL)) {
15791 pm_node_t *node = UP(pm_local_variable_read_node_create_constant_id(parser, &parser->
previous, name_id, 0,
false));
15796 pm_node_t *node = UP(pm_it_local_variable_read_node_create(parser, &parser->
previous));
15811 pm_node_flags_t flags = 0;
15813 if (!match1(parser, PM_TOKEN_PARENTHESIS_LEFT) && (parser->
previous.
end[-1] !=
'!') && (parser->
previous.
end[-1] !=
'?')) {
15814 pm_node_t *node = parse_variable(parser);
15815 if (node != NULL)
return node;
15816 flags |= PM_CALL_NODE_FLAGS_VARIABLE_CALL;
15820 pm_node_flag_set(UP(node), flags);
15831parse_method_definition_name(
pm_parser_t *parser) {
15832 switch (parser->
current.type) {
15833 case PM_CASE_KEYWORD:
15834 case PM_TOKEN_CONSTANT:
15835 case PM_TOKEN_METHOD_NAME:
15836 parser_lex(parser);
15838 case PM_TOKEN_IDENTIFIER:
15839 pm_refute_numbered_parameter(parser, parser->
current.start, parser->
current.end);
15840 parser_lex(parser);
15842 case PM_CASE_OPERATOR:
15843 lex_state_set(parser, PM_LEX_STATE_ENDFN);
15844 parser_lex(parser);
15853parse_heredoc_dedent_string(
pm_string_t *
string,
size_t common_whitespace) {
15856 pm_string_ensure_owned(
string);
15862 const uint8_t *source_cursor = (uint8_t *) string->
source;
15863 const uint8_t *source_end = source_cursor + dest_length;
15868 size_t trimmed_whitespace = 0;
15874 while ((source_cursor < source_end) && pm_char_is_inline_whitespace(*source_cursor) && trimmed_whitespace < common_whitespace) {
15875 if (*source_cursor ==
'\t') {
15876 trimmed_whitespace = (trimmed_whitespace / PM_TAB_WHITESPACE_SIZE + 1) * PM_TAB_WHITESPACE_SIZE;
15877 if (trimmed_whitespace > common_whitespace)
break;
15879 trimmed_whitespace++;
15886 memmove((uint8_t *) string->source, source_cursor, (
size_t) (source_end - source_cursor));
15887 string->length = dest_length;
15897 bool dedent_next =
true;
15902 size_t write_index = 0;
15909 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE)) {
15910 nodes->
nodes[write_index++] = node;
15911 dedent_next =
false;
15917 parse_heredoc_dedent_string(&string_node->
unescaped, common_whitespace);
15921 pm_node_destroy(parser, node);
15923 nodes->
nodes[write_index++] = node;
15927 dedent_next =
true;
15930 nodes->
size = write_index;
15937parse_strings_empty_content(
const uint8_t *location) {
15938 return (
pm_token_t) { .
type = PM_TOKEN_STRING_CONTENT, .start = location, .end = location };
15946 assert(parser->
current.type == PM_TOKEN_STRING_BEGIN);
15947 bool concating =
false;
15949 while (match1(parser, PM_TOKEN_STRING_BEGIN)) {
15955 assert(lex_mode->
mode == PM_LEX_STRING);
15957 bool label_allowed = lex_mode->
as.string.
label_allowed && accepts_label;
15960 parser_lex(parser);
15962 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
15963 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
15972 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
15982 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
15983 }
else if (!lex_interpolation) {
15989 if (match1(parser, PM_TOKEN_EOF)) {
15991 content = not_provided(parser);
15994 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_EXPECT_STRING_CONTENT);
16009 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16012 pm_token_t delimiters = not_provided(parser);
16013 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &delimiters, &content, &delimiters, &unescaped));
16014 pm_node_list_append(&parts, part);
16017 part = UP(pm_string_node_create_current_string(parser, &delimiters, &parser->
current, &delimiters));
16018 pm_node_list_append(&parts, part);
16019 parser_lex(parser);
16020 }
while (match1(parser, PM_TOKEN_STRING_CONTENT));
16022 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_LITERAL_EOF);
16023 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16025 pm_node_list_free(&parts);
16026 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16027 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16028 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16029 }
else if (match1(parser, PM_TOKEN_EOF)) {
16030 pm_parser_err_token(parser, &opening, PM_ERR_STRING_LITERAL_EOF);
16031 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16032 }
else if (accept1(parser, PM_TOKEN_STRING_END)) {
16033 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16038 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped));
16040 }
else if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
16047 parser_lex(parser);
16049 if (match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
16050 node = UP(pm_string_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
16051 pm_node_flag_set(node, parse_unescaped_encoding(parser));
16057 if (!accept1(parser, PM_TOKEN_STRING_END)) {
16059 if (location > parser->
start && location[-1] ==
'\n') location--;
16060 pm_parser_err(parser, location, location, PM_ERR_STRING_LITERAL_EOF);
16065 }
else if (accept1(parser, PM_TOKEN_LABEL_END)) {
16066 node = UP(pm_symbol_node_create_unescaped(parser, &opening, &content, &parser->
previous, &unescaped, parse_symbol_encoding(parser, &content, &unescaped,
true)));
16067 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16072 pm_token_t string_opening = not_provided(parser);
16073 pm_token_t string_closing = not_provided(parser);
16075 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &string_opening, &parser->
previous, &string_closing, &unescaped));
16076 pm_node_flag_set(part, parse_unescaped_encoding(parser));
16077 pm_node_list_append(&parts, part);
16079 while (!match3(parser, PM_TOKEN_STRING_END, PM_TOKEN_LABEL_END, PM_TOKEN_EOF)) {
16080 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
16081 pm_node_list_append(&parts, part);
16085 if (accept1(parser, PM_TOKEN_LABEL_END)) {
16086 node = UP(pm_interpolated_symbol_node_create(parser, &opening, &parts, &parser->
previous));
16087 if (!label_allowed) pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_LABEL);
16088 }
else if (match1(parser, PM_TOKEN_EOF)) {
16089 pm_parser_err_token(parser, &opening, PM_ERR_STRING_INTERPOLATED_TERM);
16090 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
current));
16092 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_STRING_INTERPOLATED_TERM);
16093 node = UP(pm_interpolated_string_node_create(parser, &opening, &parts, &parser->
previous));
16096 pm_node_list_free(&parts);
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);
16125 if (current == NULL) {
16129 if (PM_NODE_TYPE_P(node, PM_SYMBOL_NODE) || PM_NODE_TYPE_P(node, PM_INTERPOLATED_SYMBOL_NODE)) {
16140 if (!PM_NODE_TYPE_P(node, PM_STRING_NODE) && !PM_NODE_TYPE_P(node, PM_INTERPOLATED_STRING_NODE)) {
16141 pm_parser_err_node(parser, node, PM_ERR_STRING_CONCATENATION);
16147 if (!PM_NODE_TYPE_P(current, PM_STRING_NODE) && !PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
16148 pm_parser_err_node(parser, current, PM_ERR_STRING_CONCATENATION);
16155 pm_interpolated_string_node_append(container, current);
16156 current = UP(container);
16166#define PM_PARSE_PATTERN_SINGLE 0
16167#define PM_PARSE_PATTERN_TOP 1
16168#define PM_PARSE_PATTERN_MULTI 2
16181 if (peek_at(parser, location->
start) ==
'_')
return;
16183 if (pm_constant_id_list_includes(captures, capture)) {
16184 pm_parser_err(parser, location->
start, location->
end, PM_ERR_PATTERN_CAPTURE_DUPLICATE);
16186 pm_constant_id_list_append(captures, capture);
16197 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
16199 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16200 node = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
16206 if (!match2(parser, PM_TOKEN_BRACKET_LEFT, PM_TOKEN_PARENTHESIS_LEFT)) {
16214 if (accept1(parser, PM_TOKEN_BRACKET_LEFT)) {
16216 accept1(parser, PM_TOKEN_NEWLINE);
16218 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16219 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16220 accept1(parser, PM_TOKEN_NEWLINE);
16221 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16226 parser_lex(parser);
16228 accept1(parser, PM_TOKEN_NEWLINE);
16230 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
16231 inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16232 accept1(parser, PM_TOKEN_NEWLINE);
16233 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16242 return UP(pm_array_pattern_node_constant_create(parser, node, &opening, &closing));
16249 switch (PM_NODE_TYPE(inner)) {
16250 case PM_ARRAY_PATTERN_NODE: {
16258 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16259 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16261 return UP(pattern_node);
16266 case PM_FIND_PATTERN_NODE: {
16274 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16275 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16277 return UP(pattern_node);
16282 case PM_HASH_PATTERN_NODE: {
16290 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16291 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16293 return UP(pattern_node);
16305 pm_array_pattern_node_t *pattern_node = pm_array_pattern_node_constant_create(parser, node, &opening, &closing);
16306 pm_array_pattern_node_requireds_append(pattern_node, inner);
16307 return UP(pattern_node);
16322 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16324 pm_constant_id_t constant_id = pm_parser_constant_id_token(parser, &identifier);
16327 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16328 pm_parser_local_add(parser, constant_id, identifier.
start, identifier.
end, 0);
16331 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&identifier));
16332 name = UP(pm_local_variable_target_node_create(
16334 &PM_LOCATION_TOKEN_VALUE(&identifier),
16336 (uint32_t) (depth == -1 ? 0 : depth)
16341 return pm_splat_node_create(parser, &
operator, name);
16349 assert(parser->
current.type == PM_TOKEN_USTAR_STAR);
16350 parser_lex(parser);
16355 if (accept1(parser, PM_TOKEN_KEYWORD_NIL)) {
16356 return UP(pm_no_keywords_parameter_node_create(parser, &
operator, &parser->
previous));
16359 if (accept1(parser, PM_TOKEN_IDENTIFIER)) {
16363 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16367 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16368 value = UP(pm_local_variable_target_node_create(
16370 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16372 (uint32_t) (depth == -1 ? 0 : depth)
16376 return UP(pm_assoc_splat_node_create(parser, value, &
operator));
16384pm_slice_is_valid_local(
const pm_parser_t *parser,
const uint8_t *start,
const uint8_t *end) {
16385 ptrdiff_t length = end - start;
16386 if (length == 0)
return false;
16389 size_t width = char_is_identifier_start(parser, start, end - start);
16390 if (width == 0)
return false;
16396 if (pm_encoding_utf_8_isupper_char(start, length))
return false;
16401 const uint8_t *cursor = start + width;
16402 while ((width = char_is_identifier(parser, cursor, end - cursor))) cursor += width;
16403 return cursor == end;
16417 if (pm_slice_is_valid_local(parser, value_loc->
start, value_loc->
end)) {
16418 depth = pm_parser_local_depth_constant_id(parser, constant_id);
16420 pm_parser_err(parser, key->base.location.start, key->base.location.end, PM_ERR_PATTERN_HASH_KEY_LOCALS);
16422 if ((value_loc->
end > value_loc->
start) && ((value_loc->
end[-1] ==
'!') || (value_loc->
end[-1] ==
'?'))) {
16423 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);
16428 pm_parser_local_add(parser, constant_id, value_loc->
start, value_loc->
end, 0);
16431 parse_pattern_capture(parser, captures, constant_id, value_loc);
16436 (uint32_t) (depth == -1 ? 0 : depth)
16439 return UP(pm_implicit_node_create(parser, UP(target)));
16449 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_KEY_DUPLICATE);
16462 switch (PM_NODE_TYPE(first_node)) {
16463 case PM_ASSOC_SPLAT_NODE:
16464 case PM_NO_KEYWORDS_PARAMETER_NODE:
16467 case PM_SYMBOL_NODE: {
16468 if (pm_symbol_node_label_p(first_node)) {
16469 parse_pattern_hash_key(parser, &keys, first_node);
16472 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)) {
16475 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) first_node);
16479 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16483 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16485 pm_node_list_append(&assocs, assoc);
16494 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;
16495 pm_parser_err_node(parser, first_node, diag_id);
16499 pm_node_t *assoc = UP(pm_assoc_node_create(parser, first_node, &
operator, value));
16501 pm_node_list_append(&assocs, assoc);
16507 while (accept1(parser, PM_TOKEN_COMMA)) {
16509 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)) {
16511 if (rest != NULL) {
16512 pm_parser_err_token(parser, &parser->
current, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16518 if (match1(parser, PM_TOKEN_USTAR_STAR)) {
16519 pm_node_t *assoc = parse_pattern_keyword_rest(parser, captures);
16521 if (rest == NULL) {
16524 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16525 pm_node_list_append(&assocs, assoc);
16530 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
16531 key = parse_strings(parser, NULL,
true, (uint16_t) (depth + 1));
16533 if (PM_NODE_TYPE_P(key, PM_INTERPOLATED_SYMBOL_NODE)) {
16534 pm_parser_err_node(parser, key, PM_ERR_PATTERN_HASH_KEY_INTERPOLATED);
16535 }
else if (!pm_symbol_node_label_p(key)) {
16536 pm_parser_err_node(parser, key, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16539 expect1(parser, PM_TOKEN_LABEL, PM_ERR_PATTERN_LABEL_AFTER_COMMA);
16540 key = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16543 parse_pattern_hash_key(parser, &keys, key);
16546 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)) {
16547 if (PM_NODE_TYPE_P(key, PM_SYMBOL_NODE)) {
16548 value = parse_pattern_hash_implicit_value(parser, captures, (
pm_symbol_node_t *) key);
16550 value = UP(pm_missing_node_create(parser, key->location.end, key->location.end));
16553 value = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_KEY, (uint16_t) (depth + 1));
16557 pm_node_t *assoc = UP(pm_assoc_node_create(parser, key, &
operator, value));
16559 if (rest != NULL) {
16560 pm_parser_err_node(parser, assoc, PM_ERR_PATTERN_EXPRESSION_AFTER_REST);
16563 pm_node_list_append(&assocs, assoc);
16570 pm_static_literals_free(&keys);
16579 switch (parser->
current.type) {
16580 case PM_TOKEN_IDENTIFIER:
16581 case PM_TOKEN_METHOD_NAME: {
16582 parser_lex(parser);
16586 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16590 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16591 return UP(pm_local_variable_target_node_create(
16593 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16595 (uint32_t) (depth == -1 ? 0 : depth)
16598 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
16600 parser_lex(parser);
16602 if (accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
16605 return UP(pm_array_pattern_node_empty_create(parser, &opening, &parser->
previous));
16610 pm_node_t *inner = parse_pattern(parser, captures, PM_PARSE_PATTERN_MULTI, PM_ERR_PATTERN_EXPRESSION_AFTER_BRACKET, (uint16_t) (depth + 1));
16612 accept1(parser, PM_TOKEN_NEWLINE);
16613 expect1_opening(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_PATTERN_TERM_BRACKET, &opening);
16616 switch (PM_NODE_TYPE(inner)) {
16617 case PM_ARRAY_PATTERN_NODE: {
16623 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16624 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16626 return UP(pattern_node);
16631 case PM_FIND_PATTERN_NODE: {
16637 pattern_node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16638 pattern_node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16640 return UP(pattern_node);
16650 pm_array_pattern_node_requireds_append(node, inner);
16653 case PM_TOKEN_BRACE_LEFT: {
16659 parser_lex(parser);
16661 if (accept1(parser, PM_TOKEN_BRACE_RIGHT)) {
16664 node = pm_hash_pattern_node_empty_create(parser, &opening, &parser->
previous);
16668 switch (parser->
current.type) {
16669 case PM_TOKEN_LABEL:
16670 parser_lex(parser);
16671 first_node = UP(pm_symbol_node_label_create(parser, &parser->
previous));
16673 case PM_TOKEN_USTAR_STAR:
16674 first_node = parse_pattern_keyword_rest(parser, captures);
16676 case PM_TOKEN_STRING_BEGIN:
16677 first_node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, PM_ERR_PATTERN_HASH_KEY_LABEL, (uint16_t) (depth + 1));
16681 parser_lex(parser);
16688 node = parse_pattern_hash(parser, captures, first_node, (uint16_t) (depth + 1));
16690 accept1(parser, PM_TOKEN_NEWLINE);
16691 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_PATTERN_TERM_BRACE, &opening);
16697 node->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
16698 node->
closing_loc = PM_LOCATION_TOKEN_VALUE(&closing);
16704 case PM_TOKEN_UDOT_DOT:
16705 case PM_TOKEN_UDOT_DOT_DOT: {
16707 parser_lex(parser);
16711 switch (parser->
current.type) {
16712 case PM_CASE_PRIMITIVE: {
16713 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16714 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16717 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE);
16718 pm_node_t *right = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16719 return UP(pm_range_node_create(parser, NULL, &
operator, right));
16723 case PM_CASE_PRIMITIVE: {
16724 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
true, diag_id, (uint16_t) (depth + 1));
16727 if (pm_symbol_node_label_p(node))
return node;
16730 if (PM_NODE_TYPE(node) == PM_CALL_NODE) {
16731 pm_parser_err_node(parser, node, diag_id);
16734 pm_node_unreference(parser, node);
16735 pm_node_destroy(parser, node);
16736 return UP(missing_node);
16740 if (accept2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
16746 switch (parser->
current.type) {
16747 case PM_CASE_PRIMITIVE: {
16748 pm_node_t *right = parse_expression(parser, PM_BINDING_POWER_MAX,
false,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_RANGE, (uint16_t) (depth + 1));
16749 return UP(pm_range_node_create(parser, node, &
operator, right));
16752 return UP(pm_range_node_create(parser, node, &
operator, NULL));
16758 case PM_TOKEN_CARET: {
16759 parser_lex(parser);
16764 switch (parser->
current.type) {
16765 case PM_TOKEN_IDENTIFIER: {
16766 parser_lex(parser);
16767 pm_node_t *variable = UP(parse_variable(parser));
16769 if (variable == NULL) {
16770 PM_PARSER_ERR_TOKEN_FORMAT_CONTENT(parser, parser->
previous, PM_ERR_NO_LOCAL_VARIABLE);
16771 variable = UP(pm_local_variable_read_node_missing_create(parser, &parser->
previous, 0));
16774 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16776 case PM_TOKEN_INSTANCE_VARIABLE: {
16777 parser_lex(parser);
16778 pm_node_t *variable = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
16780 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16782 case PM_TOKEN_CLASS_VARIABLE: {
16783 parser_lex(parser);
16784 pm_node_t *variable = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
16786 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16788 case PM_TOKEN_GLOBAL_VARIABLE: {
16789 parser_lex(parser);
16790 pm_node_t *variable = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
16792 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16794 case PM_TOKEN_NUMBERED_REFERENCE: {
16795 parser_lex(parser);
16796 pm_node_t *variable = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
16798 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16800 case PM_TOKEN_BACK_REFERENCE: {
16801 parser_lex(parser);
16802 pm_node_t *variable = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
16804 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16806 case PM_TOKEN_PARENTHESIS_LEFT: {
16811 parser_lex(parser);
16813 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN, (uint16_t) (depth + 1));
16816 accept1(parser, PM_TOKEN_NEWLINE);
16817 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &lparen);
16818 return UP(pm_pinned_expression_node_create(parser, expression, &
operator, &lparen, &parser->
previous));
16823 pm_parser_err_token(parser, &
operator, PM_ERR_PATTERN_EXPRESSION_AFTER_PIN);
16824 pm_node_t *variable = UP(pm_missing_node_create(parser,
operator.start,
operator.end));
16825 return UP(pm_pinned_variable_node_create(parser, &
operator, variable));
16829 case PM_TOKEN_UCOLON_COLON: {
16831 parser_lex(parser);
16833 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
16836 return parse_pattern_constant_path(parser, captures, UP(node), (uint16_t) (depth + 1));
16838 case PM_TOKEN_CONSTANT: {
16840 parser_lex(parser);
16842 pm_node_t *node = UP(pm_constant_read_node_create(parser, &constant));
16843 return parse_pattern_constant_path(parser, captures, node, (uint16_t) (depth + 1));
16846 pm_parser_err_current(parser, diag_id);
16847 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
16852parse_pattern_alternation_error_each(
const pm_node_t *node,
void *data) {
16853 switch (PM_NODE_TYPE(node)) {
16854 case PM_LOCAL_VARIABLE_TARGET_NODE:
16868 pm_visit_node(node, parse_pattern_alternation_error_each, parser);
16878 bool alternation =
false;
16880 while ((node == NULL) || (alternation = accept1(parser, PM_TOKEN_PIPE))) {
16881 if (alternation && !PM_NODE_TYPE_P(node, PM_ALTERNATION_PATTERN_NODE) && captures->
size) {
16882 parse_pattern_alternation_error(parser, node);
16885 switch (parser->
current.type) {
16886 case PM_TOKEN_IDENTIFIER:
16887 case PM_TOKEN_BRACKET_LEFT_ARRAY:
16888 case PM_TOKEN_BRACE_LEFT:
16889 case PM_TOKEN_CARET:
16890 case PM_TOKEN_CONSTANT:
16891 case PM_TOKEN_UCOLON_COLON:
16892 case PM_TOKEN_UDOT_DOT:
16893 case PM_TOKEN_UDOT_DOT_DOT:
16894 case PM_CASE_PRIMITIVE: {
16895 if (!alternation) {
16896 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
16899 pm_node_t *right = parse_pattern_primitive(parser, captures, PM_ERR_PATTERN_EXPRESSION_AFTER_PIPE, (uint16_t) (depth + 1));
16901 if (captures->
size) parse_pattern_alternation_error(parser, right);
16902 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16907 case PM_TOKEN_PARENTHESIS_LEFT:
16908 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
16911 parser_lex(parser);
16913 pm_node_t *body = parse_pattern(parser, captures, PM_PARSE_PATTERN_SINGLE, PM_ERR_PATTERN_EXPRESSION_AFTER_PAREN, (uint16_t) (depth + 1));
16914 accept1(parser, PM_TOKEN_NEWLINE);
16915 expect1_opening(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_PATTERN_TERM_PAREN, &opening);
16916 pm_node_t *right = UP(pm_parentheses_node_create(parser, &opening, body, &parser->
previous, 0));
16918 if (!alternation) {
16921 if (captures->
size) parse_pattern_alternation_error(parser, right);
16922 node = UP(pm_alternation_pattern_node_create(parser, node, right, &
operator));
16928 pm_parser_err_current(parser, diag_id);
16931 if (!alternation) {
16934 if (captures->
size) parse_pattern_alternation_error(parser, right);
16935 node = UP(pm_alternation_pattern_node_create(parser, node, right, &parser->
previous));
16945 while (accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
16947 expect1(parser, PM_TOKEN_IDENTIFIER, PM_ERR_PATTERN_IDENT_AFTER_HROCKET);
16952 if ((depth = pm_parser_local_depth_constant_id(parser, constant_id)) == -1) {
16956 parse_pattern_capture(parser, captures, constant_id, &PM_LOCATION_TOKEN_VALUE(&parser->
previous));
16959 &PM_LOCATION_TOKEN_VALUE(&parser->
previous),
16961 (uint32_t) (depth == -1 ? 0 : depth)
16964 node = UP(pm_capture_pattern_node_create(parser, node, target, &
operator));
16977 bool leading_rest =
false;
16978 bool trailing_rest =
false;
16980 switch (parser->
current.type) {
16981 case PM_TOKEN_LABEL: {
16982 parser_lex(parser);
16984 node = UP(parse_pattern_hash(parser, captures, key, (uint16_t) (depth + 1)));
16986 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16987 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
16992 case PM_TOKEN_USTAR_STAR: {
16993 node = parse_pattern_keyword_rest(parser, captures);
16994 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
16996 if (!(flags & PM_PARSE_PATTERN_TOP)) {
16997 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17002 case PM_TOKEN_STRING_BEGIN: {
17005 node = parse_pattern_primitive(parser, captures, diag_id, (uint16_t) (depth + 1));
17007 if (pm_symbol_node_label_p(node)) {
17008 node = UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17010 if (!(flags & PM_PARSE_PATTERN_TOP)) {
17011 pm_parser_err_node(parser, node, PM_ERR_PATTERN_HASH_IMPLICIT);
17017 node = parse_pattern_primitives(parser, captures, node, diag_id, (uint16_t) (depth + 1));
17020 case PM_TOKEN_USTAR: {
17021 if (flags & (PM_PARSE_PATTERN_TOP | PM_PARSE_PATTERN_MULTI)) {
17022 parser_lex(parser);
17023 node = UP(parse_pattern_rest(parser, captures));
17024 leading_rest =
true;
17030 node = parse_pattern_primitives(parser, captures, NULL, diag_id, (uint16_t) (depth + 1));
17036 if (pm_symbol_node_label_p(node)) {
17037 return UP(parse_pattern_hash(parser, captures, node, (uint16_t) (depth + 1)));
17040 if ((flags & PM_PARSE_PATTERN_MULTI) && match1(parser, PM_TOKEN_COMMA)) {
17045 pm_node_list_append(&nodes, node);
17048 while (accept1(parser, PM_TOKEN_COMMA)) {
17050 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)) {
17051 node = UP(pm_implicit_rest_node_create(parser, &parser->
previous));
17052 pm_node_list_append(&nodes, node);
17053 trailing_rest =
true;
17057 if (accept1(parser, PM_TOKEN_USTAR)) {
17058 node = UP(parse_pattern_rest(parser, captures));
17063 if (trailing_rest) {
17064 pm_parser_err_previous(parser, PM_ERR_PATTERN_REST);
17067 trailing_rest =
true;
17069 node = parse_pattern_primitives(parser, captures, NULL, PM_ERR_PATTERN_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
17072 pm_node_list_append(&nodes, node);
17079 if (leading_rest && PM_NODE_TYPE_P(nodes.
nodes[nodes.
size - 1], PM_SPLAT_NODE)) {
17080 node = UP(pm_find_pattern_node_create(parser, &nodes));
17082 if (nodes.
size == 2) {
17083 pm_parser_err_node(parser, node, PM_ERR_PATTERN_FIND_MISSING_INNER);
17086 node = UP(pm_array_pattern_node_node_list_create(parser, &nodes));
17088 if (leading_rest && trailing_rest) {
17089 pm_parser_err_node(parser, node, PM_ERR_PATTERN_ARRAY_MULTIPLE_RESTS);
17094 }
else if (leading_rest) {
17097 node = UP(pm_array_pattern_node_rest_create(parser, node));
17109parse_negative_numeric(
pm_node_t *node) {
17110 switch (PM_NODE_TYPE(node)) {
17111 case PM_INTEGER_NODE: {
17117 case PM_FLOAT_NODE: {
17123 case PM_RATIONAL_NODE: {
17129 case PM_IMAGINARY_NODE:
17134 assert(
false &&
"unreachable");
17147 case PM_ERR_HASH_KEY: {
17151 case PM_ERR_HASH_VALUE:
17152 case PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR: {
17156 case PM_ERR_UNARY_RECEIVER: {
17161 case PM_ERR_UNARY_DISALLOWED:
17162 case PM_ERR_EXPECT_ARGUMENT: {
17167 pm_parser_err_previous(parser, diag_id);
17177#define CONTEXT_NONE 0
17178#define CONTEXT_THROUGH_ENSURE 1
17179#define CONTEXT_THROUGH_ELSE 2
17182 int context = CONTEXT_NONE;
17184 while (context_node != NULL) {
17185 switch (context_node->
context) {
17206 if (context == CONTEXT_NONE) {
17207 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_WITHOUT_RESCUE);
17208 }
else if (context == CONTEXT_THROUGH_ENSURE) {
17209 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ENSURE);
17210 }
else if (context == CONTEXT_THROUGH_ELSE) {
17211 pm_parser_err_node(parser, node, PM_ERR_INVALID_RETRY_AFTER_ELSE);
17223 context = CONTEXT_THROUGH_ELSE;
17234 context = CONTEXT_THROUGH_ENSURE;
17238 assert(
false &&
"unreachable");
17269 context_node = context_node->
prev;
17273#undef CONTEXT_ENSURE
17284 while (context_node != NULL) {
17285 switch (context_node->
context) {
17310 pm_parser_err_node(parser, node, PM_ERR_INVALID_YIELD);
17314 assert(
false &&
"unreachable");
17356 context_node = context_node->
prev;
17388parse_regular_expression_error(
const uint8_t *start,
const uint8_t *end,
const char *message,
void *data) {
17392 if (callback_data->
shared) {
17398 PM_PARSER_ERR_FORMAT(callback_data->
parser, location.
start, location.
end, PM_ERR_REGEXP_PARSE_ERROR, message);
17411 .shared = unescaped->
type == PM_STRING_SHARED
17414 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);
17421parse_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) {
17422 switch (parser->
current.type) {
17423 case PM_TOKEN_BRACKET_LEFT_ARRAY: {
17424 parser_lex(parser);
17427 pm_accepts_block_stack_push(parser,
true);
17428 bool parsed_bare_hash =
false;
17430 while (!match2(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_EOF)) {
17431 bool accepted_newline = accept1(parser, PM_TOKEN_NEWLINE);
17435 if (accepted_newline && match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17441 if (accept1(parser, PM_TOKEN_COMMA)) {
17444 if (accepted_newline) {
17445 pm_parser_err_previous(parser, PM_ERR_INVALID_COMMA);
17461 if (match1(parser, PM_TOKEN_BRACKET_RIGHT))
break;
17465 if (accept1(parser, PM_TOKEN_USTAR)) {
17469 if (match3(parser, PM_TOKEN_BRACKET_RIGHT, PM_TOKEN_COMMA, PM_TOKEN_EOF)) {
17470 pm_parser_scope_forwarding_positionals_check(parser, &
operator);
17472 expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_ARRAY_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
17475 element = UP(pm_splat_node_create(parser, &
operator, expression));
17476 }
else if (match2(parser, PM_TOKEN_LABEL, PM_TOKEN_USTAR_STAR)) {
17477 if (parsed_bare_hash) {
17478 pm_parser_err_current(parser, PM_ERR_EXPRESSION_BARE_HASH);
17481 element = UP(pm_keyword_hash_node_create(parser));
17484 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)) {
17485 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17488 pm_static_literals_free(&hash_keys);
17489 parsed_bare_hash =
true;
17491 element = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
true, PM_ERR_ARRAY_EXPRESSION, (uint16_t) (depth + 1));
17493 if (pm_symbol_node_label_p(element) || accept1(parser, PM_TOKEN_EQUAL_GREATER)) {
17494 if (parsed_bare_hash) {
17495 pm_parser_err_previous(parser, PM_ERR_EXPRESSION_BARE_HASH);
17500 pm_hash_key_static_literals_add(parser, &hash_keys, element);
17503 if (parser->
previous.
type == PM_TOKEN_EQUAL_GREATER) {
17506 operator = not_provided(parser);
17509 pm_node_t *value = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_HASH_VALUE, (uint16_t) (depth + 1));
17510 pm_node_t *assoc = UP(pm_assoc_node_create(parser, element, &
operator, value));
17511 pm_keyword_hash_node_elements_append(hash, assoc);
17513 element = UP(hash);
17514 if (accept1(parser, PM_TOKEN_COMMA) && !match1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17515 parse_assocs(parser, &hash_keys, element, (uint16_t) (depth + 1));
17518 pm_static_literals_free(&hash_keys);
17519 parsed_bare_hash =
true;
17523 pm_array_node_elements_append(array, element);
17524 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
17527 accept1(parser, PM_TOKEN_NEWLINE);
17529 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
17535 pm_array_node_close_set(array, &parser->
previous);
17536 pm_accepts_block_stack_pop(parser);
17540 case PM_TOKEN_PARENTHESIS_LEFT:
17541 case PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES: {
17543 pm_node_flags_t flags = 0;
17546 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
17548 parser_lex(parser);
17550 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17551 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17552 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17559 if (match2(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_TOKEN_EOF)) {
17560 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17562 pop_block_exits(parser, previous_block_exits);
17563 pm_node_list_free(¤t_block_exits);
17565 return UP(pm_parentheses_node_create(parser, &opening, NULL, &parser->
previous, flags));
17570 pm_accepts_block_stack_push(parser,
true);
17572 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17573 context_pop(parser);
17578 bool terminator_found =
false;
17580 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17581 terminator_found =
true;
17582 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17583 }
else if (accept1(parser, PM_TOKEN_NEWLINE)) {
17584 terminator_found =
true;
17587 if (terminator_found) {
17589 if (accept1(parser, PM_TOKEN_SEMICOLON)) {
17590 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17591 }
else if (!accept1(parser, PM_TOKEN_NEWLINE)) {
17600 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17601 if (opening.
type == PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES) {
17602 lex_state_set(parser, PM_LEX_STATE_ENDARG);
17605 parser_lex(parser);
17606 pm_accepts_block_stack_pop(parser);
17608 pop_block_exits(parser, previous_block_exits);
17609 pm_node_list_free(¤t_block_exits);
17611 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) || PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17617 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE) && ((
pm_multi_target_node_t *) statement)->lparen_loc.start == NULL) {
17620 multi_target = pm_multi_target_node_create(parser);
17621 pm_multi_target_node_targets_append(parser, multi_target, statement);
17624 pm_location_t lparen_loc = PM_LOCATION_TOKEN_VALUE(&opening);
17633 if (match1(parser, PM_TOKEN_COMMA) && (binding_power == PM_BINDING_POWER_STATEMENT)) {
17634 result = parse_targets(parser, UP(multi_target), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17635 accept1(parser, PM_TOKEN_NEWLINE);
17637 result = UP(multi_target);
17646 }
else if (binding_power != PM_BINDING_POWER_STATEMENT) {
17649 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17650 }
else if (!match2(parser, PM_TOKEN_EQUAL, PM_TOKEN_PARENTHESIS_RIGHT)) {
17654 pm_parser_err_node(parser, result, PM_ERR_WRITE_TARGET_UNEXPECTED);
17664 pm_statements_node_body_append(parser, statements, statement,
true);
17666 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17673 flags |= PM_PARENTHESES_NODE_FLAGS_MULTIPLE_STATEMENTS;
17676 pm_statements_node_body_append(parser, statements, statement,
true);
17680 if (!terminator_found && !match1(parser, PM_TOKEN_EOF)) {
17686 pm_node_t *node = parse_expression(parser, PM_BINDING_POWER_STATEMENT,
true,
false, PM_ERR_CANNOT_PARSE_EXPRESSION, (uint16_t) (depth + 1));
17687 pm_statements_node_body_append(parser, statements, node,
true);
17694 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) parser->
recovering =
false;
17700 if (PM_NODE_TYPE_P(node, PM_MISSING_NODE))
break;
17704 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
17705 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
17706 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT))
break;
17707 }
else if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
17709 }
else if (!match1(parser, PM_TOKEN_EOF)) {
17716 context_pop(parser);
17717 pm_accepts_block_stack_pop(parser);
17718 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
17727 if (PM_NODE_TYPE_P(statement, PM_SPLAT_NODE)) {
17729 pm_multi_target_node_targets_append(parser, multi_target, statement);
17731 statement = UP(multi_target);
17735 if (PM_NODE_TYPE_P(statement, PM_MULTI_TARGET_NODE)) {
17737 pm_token_t operator = { .
type = PM_TOKEN_EQUAL, .start = offset, .end = offset };
17738 pm_node_t *value = UP(pm_missing_node_create(parser, offset, offset));
17740 statement = UP(pm_multi_write_node_create(parser, (
pm_multi_target_node_t *) statement, &
operator, value));
17743 pm_parser_err_node(parser, statement, PM_ERR_WRITE_TARGET_UNEXPECTED);
17747 pop_block_exits(parser, previous_block_exits);
17748 pm_node_list_free(¤t_block_exits);
17750 pm_void_statements_check(parser, statements,
true);
17751 return UP(pm_parentheses_node_create(parser, &opening, UP(statements), &parser->
previous, flags));
17753 case PM_TOKEN_BRACE_LEFT: {
17764 pm_accepts_block_stack_push(parser,
true);
17765 parser_lex(parser);
17770 if (!match2(parser, PM_TOKEN_BRACE_RIGHT, PM_TOKEN_EOF)) {
17771 if (current_hash_keys != NULL) {
17772 parse_assocs(parser, current_hash_keys, UP(node), (uint16_t) (depth + 1));
17775 parse_assocs(parser, &hash_keys, UP(node), (uint16_t) (depth + 1));
17776 pm_static_literals_free(&hash_keys);
17779 accept1(parser, PM_TOKEN_NEWLINE);
17782 pm_accepts_block_stack_pop(parser);
17783 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_HASH_TERM, &opening);
17784 pm_hash_node_closing_loc_set(node, &parser->
previous);
17788 case PM_TOKEN_CHARACTER_LITERAL: {
17790 pm_node_t *node = UP(pm_string_node_create_current_string(
17793 .type = PM_TOKEN_STRING_BEGIN,
17794 .start = parser->
current.start,
17795 .end = parser->
current.start + 1
17798 .type = PM_TOKEN_STRING_CONTENT,
17799 .start = parser->
current.start + 1,
17805 pm_node_flag_set(node, parse_unescaped_encoding(parser));
17809 parser_lex(parser);
17813 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
17814 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
17819 case PM_TOKEN_CLASS_VARIABLE: {
17820 parser_lex(parser);
17821 pm_node_t *node = UP(pm_class_variable_read_node_create(parser, &parser->
previous));
17823 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17824 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17829 case PM_TOKEN_CONSTANT: {
17830 parser_lex(parser);
17836 match1(parser, PM_TOKEN_PARENTHESIS_LEFT) ||
17837 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17838 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17839 match1(parser, PM_TOKEN_BRACE_LEFT)
17842 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17843 return UP(pm_call_node_fcall_create(parser, &constant, &arguments));
17848 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17851 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17856 case PM_TOKEN_UCOLON_COLON: {
17857 parser_lex(parser);
17860 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
17861 pm_node_t *node = UP(pm_constant_path_node_create(parser, NULL, &delimiter, &parser->
previous));
17863 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17864 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17869 case PM_TOKEN_UDOT_DOT:
17870 case PM_TOKEN_UDOT_DOT_DOT: {
17872 parser_lex(parser);
17874 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));
17880 if (match2(parser, PM_TOKEN_DOT_DOT, PM_TOKEN_DOT_DOT_DOT)) {
17881 pm_parser_err_current(parser, PM_ERR_UNEXPECTED_RANGE_OPERATOR);
17884 return UP(pm_range_node_create(parser, NULL, &
operator, right));
17886 case PM_TOKEN_FLOAT:
17887 parser_lex(parser);
17888 return UP(pm_float_node_create(parser, &parser->
previous));
17889 case PM_TOKEN_FLOAT_IMAGINARY:
17890 parser_lex(parser);
17891 return UP(pm_float_node_imaginary_create(parser, &parser->
previous));
17892 case PM_TOKEN_FLOAT_RATIONAL:
17893 parser_lex(parser);
17894 return UP(pm_float_node_rational_create(parser, &parser->
previous));
17895 case PM_TOKEN_FLOAT_RATIONAL_IMAGINARY:
17896 parser_lex(parser);
17897 return UP(pm_float_node_rational_imaginary_create(parser, &parser->
previous));
17898 case PM_TOKEN_NUMBERED_REFERENCE: {
17899 parser_lex(parser);
17900 pm_node_t *node = UP(pm_numbered_reference_read_node_create(parser, &parser->
previous));
17902 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17903 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17908 case PM_TOKEN_GLOBAL_VARIABLE: {
17909 parser_lex(parser);
17910 pm_node_t *node = UP(pm_global_variable_read_node_create(parser, &parser->
previous));
17912 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17913 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17918 case PM_TOKEN_BACK_REFERENCE: {
17919 parser_lex(parser);
17920 pm_node_t *node = UP(pm_back_reference_read_node_create(parser, &parser->
previous));
17922 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
17923 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
17928 case PM_TOKEN_IDENTIFIER:
17929 case PM_TOKEN_METHOD_NAME: {
17930 parser_lex(parser);
17932 pm_node_t *node = parse_variable_call(parser);
17934 if (PM_NODE_TYPE_P(node, PM_CALL_NODE)) {
17942 if (parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1))) {
17945 pm_node_flag_unset(UP(call), PM_CALL_NODE_FLAGS_VARIABLE_CALL);
17952 const uint8_t *end = pm_arguments_end(&arguments);
17963 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR))) ||
17964 (pm_accepts_block_stack_p(parser) && match1(parser, PM_TOKEN_KEYWORD_DO)) ||
17965 match1(parser, PM_TOKEN_BRACE_LEFT)
17968 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
17969 pm_call_node_t *fcall = pm_call_node_fcall_create(parser, &identifier, &arguments);
17971 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
17975 pm_node_unreference(parser, node);
17981 assert(PM_NODE_TYPE_P(node, PM_LOCAL_VARIABLE_READ_NODE));
17983 if (pm_token_is_numbered_parameter(identifier.
start, identifier.
end)) {
17984 pm_node_unreference(parser, node);
17987 pm_locals_unread(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
17991 pm_node_destroy(parser, node);
17996 if ((binding_power == PM_BINDING_POWER_STATEMENT) && match1(parser, PM_TOKEN_COMMA)) {
17997 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18002 case PM_TOKEN_HEREDOC_START: {
18008 size_t common_whitespace = (size_t) -1;
18011 parser_lex(parser);
18017 if (match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18023 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18024 node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
previous, &
PM_STRING_EMPTY));
18030 }
else if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) == NULL) {
18038 }
else if (PM_NODE_TYPE_P(part, PM_STRING_NODE) && match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18043 pm_node_flag_set(part, parse_unescaped_encoding(parser));
18046 cast->
opening_loc = PM_LOCATION_TOKEN_VALUE(&opening);
18050 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18052 cast->
base.
type = PM_X_STRING_NODE;
18055 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18056 parse_heredoc_dedent_string(&cast->
unescaped, common_whitespace);
18066 pm_node_list_append(&parts, part);
18068 while (!match2(parser, PM_TOKEN_HEREDOC_END, PM_TOKEN_EOF)) {
18069 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
18070 pm_node_list_append(&parts, part);
18076 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18078 cast->
parts = parts;
18081 pm_interpolated_xstring_node_closing_set(cast, &parser->
previous);
18087 pm_node_list_free(&parts);
18090 pm_interpolated_string_node_closing_set(cast, &parser->
previous);
18098 if (lex_mode.
indent == PM_HEREDOC_INDENT_TILDE && (common_whitespace != (
size_t) -1) && (common_whitespace != 0)) {
18100 if (lex_mode.
quote == PM_HEREDOC_QUOTE_BACKTICK) {
18106 parse_heredoc_dedent(parser, nodes, common_whitespace);
18110 if (match1(parser, PM_TOKEN_STRING_BEGIN)) {
18111 return parse_strings(parser, node,
false, (uint16_t) (depth + 1));
18116 case PM_TOKEN_INSTANCE_VARIABLE: {
18117 parser_lex(parser);
18118 pm_node_t *node = UP(pm_instance_variable_read_node_create(parser, &parser->
previous));
18120 if (binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
18121 node = parse_targets_validate(parser, node, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
18126 case PM_TOKEN_INTEGER: {
18128 parser_lex(parser);
18129 return UP(pm_integer_node_create(parser, base, &parser->
previous));
18131 case PM_TOKEN_INTEGER_IMAGINARY: {
18133 parser_lex(parser);
18134 return UP(pm_integer_node_imaginary_create(parser, base, &parser->
previous));
18136 case PM_TOKEN_INTEGER_RATIONAL: {
18138 parser_lex(parser);
18139 return UP(pm_integer_node_rational_create(parser, base, &parser->
previous));
18141 case PM_TOKEN_INTEGER_RATIONAL_IMAGINARY: {
18143 parser_lex(parser);
18144 return UP(pm_integer_node_rational_imaginary_create(parser, base, &parser->
previous));
18146 case PM_TOKEN_KEYWORD___ENCODING__:
18147 parser_lex(parser);
18148 return UP(pm_source_encoding_node_create(parser, &parser->
previous));
18149 case PM_TOKEN_KEYWORD___FILE__:
18150 parser_lex(parser);
18151 return UP(pm_source_file_node_create(parser, &parser->
previous));
18152 case PM_TOKEN_KEYWORD___LINE__:
18153 parser_lex(parser);
18154 return UP(pm_source_line_node_create(parser, &parser->
previous));
18155 case PM_TOKEN_KEYWORD_ALIAS: {
18156 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18157 pm_parser_err_current(parser, PM_ERR_STATEMENT_ALIAS);
18160 parser_lex(parser);
18163 pm_node_t *new_name = parse_alias_argument(parser,
true, (uint16_t) (depth + 1));
18164 pm_node_t *old_name = parse_alias_argument(parser,
false, (uint16_t) (depth + 1));
18166 switch (PM_NODE_TYPE(new_name)) {
18167 case PM_BACK_REFERENCE_READ_NODE:
18168 case PM_NUMBERED_REFERENCE_READ_NODE:
18169 case PM_GLOBAL_VARIABLE_READ_NODE: {
18170 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)) {
18171 if (PM_NODE_TYPE_P(old_name, PM_NUMBERED_REFERENCE_READ_NODE)) {
18172 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT_NUMBERED_REFERENCE);
18175 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18178 return UP(pm_alias_global_variable_node_create(parser, &keyword, new_name, old_name));
18180 case PM_SYMBOL_NODE:
18181 case PM_INTERPOLATED_SYMBOL_NODE: {
18182 if (!PM_NODE_TYPE_P(old_name, PM_SYMBOL_NODE) && !PM_NODE_TYPE_P(old_name, PM_INTERPOLATED_SYMBOL_NODE)) {
18183 pm_parser_err_node(parser, old_name, PM_ERR_ALIAS_ARGUMENT);
18188 return UP(pm_alias_method_node_create(parser, &keyword, new_name, old_name));
18191 case PM_TOKEN_KEYWORD_CASE: {
18192 size_t opening_newline_index = token_newline_index(parser);
18193 parser_lex(parser);
18199 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18201 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18202 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18204 }
else if (match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_END)) {
18206 }
else if (!token_begins_expression_p(parser->
current.type)) {
18209 predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CASE_EXPRESSION_AFTER_CASE, (uint16_t) (depth + 1));
18210 while (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON));
18213 if (match1(parser, PM_TOKEN_KEYWORD_END)) {
18214 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18215 parser_lex(parser);
18217 pop_block_exits(parser, previous_block_exits);
18218 pm_node_list_free(¤t_block_exits);
18220 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18221 return UP(pm_case_node_create(parser, &case_keyword, predicate, &parser->
previous));
18226 pm_token_t end_keyword = not_provided(parser);
18229 if (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18230 pm_case_node_t *case_node = pm_case_node_create(parser, &case_keyword, predicate, &end_keyword);
18236 while (match1(parser, PM_TOKEN_KEYWORD_WHEN)) {
18237 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18238 parser_lex(parser);
18241 pm_when_node_t *when_node = pm_when_node_create(parser, &when_keyword);
18244 if (accept1(parser, PM_TOKEN_USTAR)) {
18246 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
18248 pm_splat_node_t *splat_node = pm_splat_node_create(parser, &
operator, expression);
18249 pm_when_node_conditions_append(when_node, UP(splat_node));
18251 if (PM_NODE_TYPE_P(expression, PM_MISSING_NODE))
break;
18253 pm_node_t *condition = parse_value_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_CASE_EXPRESSION_AFTER_WHEN, (uint16_t) (depth + 1));
18254 pm_when_node_conditions_append(when_node, condition);
18258 if (PM_NODE_TYPE_P(condition, PM_MISSING_NODE))
break;
18262 if (PM_NODE_TYPE_P(condition, PM_STRING_NODE)) {
18263 pm_node_flag_set(condition, PM_STRING_FLAGS_FROZEN | PM_NODE_FLAG_STATIC_LITERAL);
18264 }
else if (PM_NODE_TYPE_P(condition, PM_SOURCE_FILE_NODE)) {
18265 pm_node_flag_set(condition, PM_NODE_FLAG_STATIC_LITERAL);
18268 pm_when_clause_static_literals_add(parser, &literals, condition);
18270 }
while (accept1(parser, PM_TOKEN_COMMA));
18272 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18273 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18274 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18277 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_WHEN_DELIMITER);
18278 pm_when_node_then_keyword_loc_set(when_node, &parser->
previous);
18281 if (!match3(parser, PM_TOKEN_KEYWORD_WHEN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18283 if (statements != NULL) {
18284 pm_when_node_statements_set(when_node, statements);
18288 pm_case_node_condition_append(case_node, UP(when_node));
18294 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18297 pm_static_literals_free(&literals);
18298 node = UP(case_node);
18300 pm_case_match_node_t *case_node = pm_case_match_node_create(parser, &case_keyword, predicate, &end_keyword);
18304 if (predicate == NULL) {
18305 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MATCH_MISSING_PREDICATE);
18311 while (match1(parser, PM_TOKEN_KEYWORD_IN)) {
18312 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
true);
18317 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
18319 parser_lex(parser);
18324 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));
18327 pm_constant_id_list_free(&captures);
18332 if (accept1(parser, PM_TOKEN_KEYWORD_IF_MODIFIER)) {
18334 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
18335 pattern = UP(pm_if_node_modifier_create(parser, pattern, &keyword, predicate));
18336 }
else if (accept1(parser, PM_TOKEN_KEYWORD_UNLESS_MODIFIER)) {
18338 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
18339 pattern = UP(pm_unless_node_modifier_create(parser, pattern, &keyword, predicate));
18346 if (accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18347 if (accept1(parser, PM_TOKEN_KEYWORD_THEN)) {
18350 then_keyword = not_provided(parser);
18353 expect1(parser, PM_TOKEN_KEYWORD_THEN, PM_ERR_EXPECT_IN_DELIMITER);
18360 if (match3(parser, PM_TOKEN_KEYWORD_IN, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18368 pm_node_t *condition = UP(pm_in_node_create(parser, pattern, statements, &in_keyword, &then_keyword));
18369 pm_case_match_node_condition_append(case_node, condition);
18375 pm_parser_err_token(parser, &case_keyword, PM_ERR_CASE_MISSING_CONDITIONS);
18378 node = UP(case_node);
18381 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18382 if (accept1(parser, PM_TOKEN_KEYWORD_ELSE)) {
18386 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
18387 else_node = pm_else_node_create(parser, &else_keyword, parse_statements(parser,
PM_CONTEXT_ELSE, (uint16_t) (depth + 1)), &parser->
current);
18389 else_node = pm_else_node_create(parser, &else_keyword, NULL, &parser->
current);
18392 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18393 pm_case_node_else_clause_set((
pm_case_node_t *) node, else_node);
18399 parser_warn_indentation_mismatch(parser, opening_newline_index, &case_keyword,
false,
false);
18400 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CASE_TERM, &case_keyword);
18402 if (PM_NODE_TYPE_P(node, PM_CASE_NODE)) {
18408 pop_block_exits(parser, previous_block_exits);
18409 pm_node_list_free(¤t_block_exits);
18413 case PM_TOKEN_KEYWORD_BEGIN: {
18414 size_t opening_newline_index = token_newline_index(parser);
18415 parser_lex(parser);
18418 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18421 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18424 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18425 pm_accepts_block_stack_push(parser,
true);
18426 begin_statements = parse_statements(parser,
PM_CONTEXT_BEGIN, (uint16_t) (depth + 1));
18427 pm_accepts_block_stack_pop(parser);
18428 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18431 pm_begin_node_t *begin_node = pm_begin_node_create(parser, &begin_keyword, begin_statements);
18432 parse_rescues(parser, opening_newline_index, &begin_keyword, begin_node, PM_RESCUES_BEGIN, (uint16_t) (depth + 1));
18433 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_BEGIN_TERM, &begin_keyword);
18436 pm_begin_node_end_keyword_set(begin_node, &parser->
previous);
18438 pop_block_exits(parser, previous_block_exits);
18439 pm_node_list_free(¤t_block_exits);
18441 return UP(begin_node);
18443 case PM_TOKEN_KEYWORD_BEGIN_UPCASE: {
18445 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18447 if (binding_power != PM_BINDING_POWER_STATEMENT) {
18448 pm_parser_err_current(parser, PM_ERR_STATEMENT_PREEXE_BEGIN);
18451 parser_lex(parser);
18454 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_BEGIN_UPCASE_BRACE);
18458 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_BEGIN_UPCASE_TERM, &opening);
18461 pm_parser_err_token(parser, &keyword, PM_ERR_BEGIN_UPCASE_TOPLEVEL);
18464 flush_block_exits(parser, previous_block_exits);
18465 pm_node_list_free(¤t_block_exits);
18467 return UP(pm_pre_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
18469 case PM_TOKEN_KEYWORD_BREAK:
18470 case PM_TOKEN_KEYWORD_NEXT:
18471 case PM_TOKEN_KEYWORD_RETURN: {
18472 parser_lex(parser);
18478 token_begins_expression_p(parser->
current.type) ||
18479 match2(parser, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)
18481 pm_binding_power_t binding_power = pm_binding_powers[parser->
current.type].
left;
18483 if (binding_power == PM_BINDING_POWER_UNSET || binding_power >= PM_BINDING_POWER_RANGE) {
18485 parse_arguments(parser, &arguments,
false, PM_TOKEN_EOF, (uint16_t) (depth + 1));
18488 if (!accepts_command_call && arguments.
arguments != NULL) {
18494 switch (keyword.
type) {
18495 case PM_TOKEN_KEYWORD_BREAK: {
18500 case PM_TOKEN_KEYWORD_NEXT: {
18505 case PM_TOKEN_KEYWORD_RETURN: {
18507 parse_return(parser, node);
18511 assert(
false &&
"unreachable");
18515 case PM_TOKEN_KEYWORD_SUPER: {
18516 parser_lex(parser);
18520 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
18525 ((arguments.
block == NULL) || PM_NODE_TYPE_P(arguments.
block, PM_BLOCK_NODE))
18527 return UP(pm_forwarding_super_node_create(parser, &keyword, &arguments));
18530 return UP(pm_super_node_create(parser, &keyword, &arguments));
18532 case PM_TOKEN_KEYWORD_YIELD: {
18533 parser_lex(parser);
18537 parse_arguments_list(parser, &arguments,
false, accepts_command_call, (uint16_t) (depth + 1));
18543 if (arguments.
block != NULL) {
18544 pm_parser_err_node(parser, arguments.
block, PM_ERR_UNEXPECTED_BLOCK_ARGUMENT);
18545 pm_node_unreference(parser, arguments.
block);
18546 pm_node_destroy(parser, arguments.
block);
18547 arguments.
block = NULL;
18555 case PM_TOKEN_KEYWORD_CLASS: {
18556 size_t opening_newline_index = token_newline_index(parser);
18557 parser_lex(parser);
18560 pm_do_loop_stack_push(parser,
false);
18563 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18565 if (accept1(parser, PM_TOKEN_LESS_LESS)) {
18567 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));
18569 pm_parser_scope_push(parser,
true);
18570 if (!match2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON)) {
18575 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18576 pm_accepts_block_stack_push(parser,
true);
18577 statements = UP(parse_statements(parser,
PM_CONTEXT_SCLASS, (uint16_t) (depth + 1)));
18578 pm_accepts_block_stack_pop(parser);
18581 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18582 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18583 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)));
18585 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18588 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18593 pm_parser_scope_pop(parser);
18594 pm_do_loop_stack_pop(parser);
18596 flush_block_exits(parser, previous_block_exits);
18597 pm_node_list_free(¤t_block_exits);
18599 return UP(pm_singleton_class_node_create(parser, &locals, &class_keyword, &
operator, expression, statements, &parser->
previous));
18602 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_CLASS_NAME, (uint16_t) (depth + 1));
18604 if (name.
type != PM_TOKEN_CONSTANT) {
18605 pm_parser_err_token(parser, &name, PM_ERR_CLASS_NAME);
18611 if (match1(parser, PM_TOKEN_LESS)) {
18612 inheritance_operator = parser->
current;
18613 lex_state_set(parser, PM_LEX_STATE_BEG);
18616 parser_lex(parser);
18618 superclass = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CLASS_SUPERCLASS, (uint16_t) (depth + 1));
18620 inheritance_operator = not_provided(parser);
18624 pm_parser_scope_push(parser,
true);
18626 if (inheritance_operator.
type != PM_TOKEN_NOT_PROVIDED) {
18627 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CLASS_UNEXPECTED_END);
18629 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18633 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18634 pm_accepts_block_stack_push(parser,
true);
18635 statements = UP(parse_statements(parser,
PM_CONTEXT_CLASS, (uint16_t) (depth + 1)));
18636 pm_accepts_block_stack_pop(parser);
18639 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
18640 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18641 statements = UP(parse_rescues_implicit_begin(parser, opening_newline_index, &class_keyword, class_keyword.
start, (
pm_statements_node_t *) statements, PM_RESCUES_CLASS, (uint16_t) (depth + 1)));
18643 parser_warn_indentation_mismatch(parser, opening_newline_index, &class_keyword,
false,
false);
18646 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_CLASS_TERM, &class_keyword);
18648 if (context_def_p(parser)) {
18649 pm_parser_err_token(parser, &class_keyword, PM_ERR_CLASS_IN_METHOD);
18655 pm_parser_scope_pop(parser);
18656 pm_do_loop_stack_pop(parser);
18658 if (!PM_NODE_TYPE_P(constant_path, PM_CONSTANT_PATH_NODE) && !(PM_NODE_TYPE_P(constant_path, PM_CONSTANT_READ_NODE))) {
18659 pm_parser_err_node(parser, constant_path, PM_ERR_CLASS_NAME);
18662 pop_block_exits(parser, previous_block_exits);
18663 pm_node_list_free(¤t_block_exits);
18665 return UP(pm_class_node_create(parser, &locals, &class_keyword, constant_path, &name, &inheritance_operator, superclass, statements, &parser->
previous));
18667 case PM_TOKEN_KEYWORD_DEF: {
18669 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
18672 size_t opening_newline_index = token_newline_index(parser);
18682 parser_lex(parser);
18686 bool valid_name =
true;
18688 switch (parser->
current.type) {
18689 case PM_CASE_OPERATOR:
18690 pm_parser_scope_push(parser,
true);
18691 lex_state_set(parser, PM_LEX_STATE_ENDFN);
18692 parser_lex(parser);
18696 case PM_TOKEN_IDENTIFIER: {
18697 parser_lex(parser);
18699 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18700 receiver = parse_variable_call(parser);
18702 pm_parser_scope_push(parser,
true);
18703 lex_state_set(parser, PM_LEX_STATE_FNAME);
18704 parser_lex(parser);
18707 name = parse_method_definition_name(parser);
18710 pm_parser_scope_push(parser,
true);
18717 case PM_TOKEN_INSTANCE_VARIABLE:
18718 case PM_TOKEN_CLASS_VARIABLE:
18719 case PM_TOKEN_GLOBAL_VARIABLE:
18720 valid_name =
false;
18722 case PM_TOKEN_CONSTANT:
18723 case PM_TOKEN_KEYWORD_NIL:
18724 case PM_TOKEN_KEYWORD_SELF:
18725 case PM_TOKEN_KEYWORD_TRUE:
18726 case PM_TOKEN_KEYWORD_FALSE:
18727 case PM_TOKEN_KEYWORD___FILE__:
18728 case PM_TOKEN_KEYWORD___LINE__:
18729 case PM_TOKEN_KEYWORD___ENCODING__: {
18730 pm_parser_scope_push(parser,
true);
18731 parser_lex(parser);
18735 if (match2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON)) {
18736 lex_state_set(parser, PM_LEX_STATE_FNAME);
18737 parser_lex(parser);
18740 switch (identifier.
type) {
18741 case PM_TOKEN_CONSTANT:
18742 receiver = UP(pm_constant_read_node_create(parser, &identifier));
18744 case PM_TOKEN_INSTANCE_VARIABLE:
18745 receiver = UP(pm_instance_variable_read_node_create(parser, &identifier));
18747 case PM_TOKEN_CLASS_VARIABLE:
18748 receiver = UP(pm_class_variable_read_node_create(parser, &identifier));
18750 case PM_TOKEN_GLOBAL_VARIABLE:
18751 receiver = UP(pm_global_variable_read_node_create(parser, &identifier));
18753 case PM_TOKEN_KEYWORD_NIL:
18754 receiver = UP(pm_nil_node_create(parser, &identifier));
18756 case PM_TOKEN_KEYWORD_SELF:
18757 receiver = UP(pm_self_node_create(parser, &identifier));
18759 case PM_TOKEN_KEYWORD_TRUE:
18760 receiver = UP(pm_true_node_create(parser, &identifier));
18762 case PM_TOKEN_KEYWORD_FALSE:
18763 receiver = UP(pm_false_node_create(parser, &identifier));
18765 case PM_TOKEN_KEYWORD___FILE__:
18766 receiver = UP(pm_source_file_node_create(parser, &identifier));
18768 case PM_TOKEN_KEYWORD___LINE__:
18769 receiver = UP(pm_source_line_node_create(parser, &identifier));
18771 case PM_TOKEN_KEYWORD___ENCODING__:
18772 receiver = UP(pm_source_encoding_node_create(parser, &identifier));
18778 name = parse_method_definition_name(parser);
18788 case PM_TOKEN_PARENTHESIS_LEFT: {
18793 context_pop(parser);
18794 parser_lex(parser);
18797 pm_node_t *expression = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEF_RECEIVER, (uint16_t) (depth + 1));
18799 accept1(parser, PM_TOKEN_NEWLINE);
18800 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
18803 lex_state_set(parser, PM_LEX_STATE_FNAME);
18804 expect2(parser, PM_TOKEN_DOT, PM_TOKEN_COLON_COLON, PM_ERR_DEF_RECEIVER_TERM);
18807 receiver = UP(pm_parentheses_node_create(parser, &lparen, expression, &rparen, 0));
18811 pm_parser_scope_push(parser,
true);
18813 name = parse_method_definition_name(parser);
18817 pm_parser_scope_push(parser,
true);
18818 name = parse_method_definition_name(parser);
18826 bool accept_endless_def =
true;
18827 switch (parser->
current.type) {
18828 case PM_TOKEN_PARENTHESIS_LEFT: {
18829 parser_lex(parser);
18832 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18835 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
true,
false,
true,
true,
false, (uint16_t) (depth + 1));
18838 lex_state_set(parser, PM_LEX_STATE_BEG);
18841 context_pop(parser);
18842 if (!accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
18851 case PM_CASE_PARAMETER: {
18854 if (parser->
current.type == PM_TOKEN_LABEL) {
18855 lex_state_set(parser, parser->
lex_state | PM_LEX_STATE_LABEL);
18858 lparen = not_provided(parser);
18859 rparen = not_provided(parser);
18860 params = parse_parameters(parser, PM_BINDING_POWER_DEFINED,
false,
false,
true,
true,
false, (uint16_t) (depth + 1));
18864 accept_endless_def =
false;
18866 context_pop(parser);
18870 lparen = not_provided(parser);
18871 rparen = not_provided(parser);
18874 context_pop(parser);
18883 if (accept1(parser, PM_TOKEN_EQUAL)) {
18884 if (token_is_setter_name(&name)) {
18885 pm_parser_err_token(parser, &name, PM_ERR_DEF_ENDLESS_SETTER);
18887 if (!accept_endless_def) {
18888 pm_parser_err_previous(parser, PM_ERR_DEF_ENDLESS_PARAMETERS);
18894 PM_PARSER_ERR_FORMAT(parser, def_keyword.
start, parser->
previous.
end, PM_ERR_UNEXPECTED_PARAMETER_DEFAULT_VALUE,
"endless method definition");
18899 pm_do_loop_stack_push(parser,
false);
18900 statements = UP(pm_statements_node_create(parser));
18902 bool allow_command_call;
18904 allow_command_call = accepts_command_call;
18907 allow_command_call = binding_power == PM_BINDING_POWER_ASSIGNMENT || binding_power < PM_BINDING_POWER_COMPOSITION;
18910 pm_node_t *statement = parse_expression(parser, PM_BINDING_POWER_DEFINED + 1, allow_command_call,
false, PM_ERR_DEF_ENDLESS, (uint16_t) (depth + 1));
18912 if (accept1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
18916 pm_node_t *value = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
18917 context_pop(parser);
18919 statement = UP(pm_rescue_modifier_node_create(parser, statement, &rescue_keyword, value));
18922 pm_statements_node_body_append(parser, (
pm_statements_node_t *) statements, statement,
false);
18923 pm_do_loop_stack_pop(parser);
18924 context_pop(parser);
18925 end_keyword = not_provided(parser);
18927 equal = not_provided(parser);
18929 if (lparen.
type == PM_TOKEN_NOT_PROVIDED) {
18930 lex_state_set(parser, PM_LEX_STATE_BEG);
18932 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_DEF_PARAMS_TERM);
18934 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
18937 pm_accepts_block_stack_push(parser,
true);
18938 pm_do_loop_stack_push(parser,
false);
18940 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
18941 pm_accepts_block_stack_push(parser,
true);
18942 statements = UP(parse_statements(parser,
PM_CONTEXT_DEF, (uint16_t) (depth + 1)));
18943 pm_accepts_block_stack_pop(parser);
18946 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
18947 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
18948 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)));
18950 parser_warn_indentation_mismatch(parser, opening_newline_index, &def_keyword,
false,
false);
18953 pm_accepts_block_stack_pop(parser);
18954 pm_do_loop_stack_pop(parser);
18956 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_DEF_TERM, &def_keyword);
18962 pm_parser_scope_pop(parser);
18969 pm_constant_id_t name_id = pm_parser_constant_id_location(parser, name.
start, parse_operator_symbol_name(&name));
18971 flush_block_exits(parser, previous_block_exits);
18972 pm_node_list_free(¤t_block_exits);
18974 return UP(pm_def_node_create(
18990 case PM_TOKEN_KEYWORD_DEFINED: {
18991 parser_lex(parser);
18999 bool newline = accept1(parser, PM_TOKEN_NEWLINE);
19001 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19004 if (newline && accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19005 expression = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19006 lparen = not_provided(parser);
19007 rparen = not_provided(parser);
19009 expression = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19012 rparen = not_provided(parser);
19014 accept1(parser, PM_TOKEN_NEWLINE);
19015 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19020 lparen = not_provided(parser);
19021 rparen = not_provided(parser);
19022 expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_DEFINED_EXPRESSION, (uint16_t) (depth + 1));
19025 context_pop(parser);
19026 return UP(pm_defined_node_create(
19034 case PM_TOKEN_KEYWORD_END_UPCASE: {
19035 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19036 pm_parser_err_current(parser, PM_ERR_STATEMENT_POSTEXE_END);
19039 parser_lex(parser);
19042 if (context_def_p(parser)) {
19043 pm_parser_warn_token(parser, &keyword, PM_WARN_END_IN_METHOD);
19046 expect1(parser, PM_TOKEN_BRACE_LEFT, PM_ERR_END_UPCASE_BRACE);
19050 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_END_UPCASE_TERM, &opening);
19051 return UP(pm_post_execution_node_create(parser, &keyword, &opening, statements, &parser->
previous));
19053 case PM_TOKEN_KEYWORD_FALSE:
19054 parser_lex(parser);
19055 return UP(pm_false_node_create(parser, &parser->
previous));
19056 case PM_TOKEN_KEYWORD_FOR: {
19057 size_t opening_newline_index = token_newline_index(parser);
19058 parser_lex(parser);
19066 if (accept1(parser, PM_TOKEN_USTAR)) {
19070 if (token_begins_expression_p(parser->
current.type)) {
19071 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19074 index = UP(pm_splat_node_create(parser, &star_operator, name));
19075 }
else if (token_begins_expression_p(parser->
current.type)) {
19076 index = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_COMMA, (uint16_t) (depth + 1));
19078 pm_parser_err_token(parser, &for_keyword, PM_ERR_FOR_INDEX);
19079 index = UP(pm_missing_node_create(parser, for_keyword.
start, for_keyword.
end));
19083 if (match1(parser, PM_TOKEN_COMMA)) {
19084 index = parse_targets(parser, index, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19086 index = parse_target(parser, index,
false,
false);
19089 context_pop(parser);
19090 pm_do_loop_stack_push(parser,
true);
19092 expect1(parser, PM_TOKEN_KEYWORD_IN, PM_ERR_FOR_IN);
19095 pm_node_t *collection = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_FOR_COLLECTION, (uint16_t) (depth + 1));
19096 pm_do_loop_stack_pop(parser);
19099 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19102 do_keyword = not_provided(parser);
19103 if (!match2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE)) {
19109 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19110 statements = parse_statements(parser,
PM_CONTEXT_FOR, (uint16_t) (depth + 1));
19113 parser_warn_indentation_mismatch(parser, opening_newline_index, &for_keyword,
false,
false);
19114 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_FOR_TERM, &for_keyword);
19116 return UP(pm_for_node_create(parser, index, collection, statements, &for_keyword, &in_keyword, &do_keyword, &parser->
previous));
19118 case PM_TOKEN_KEYWORD_IF:
19119 if (parser_end_of_line_p(parser)) {
19120 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_KEYWORD_EOL);
19123 size_t opening_newline_index = token_newline_index(parser);
19124 bool if_after_else = parser->
previous.
type == PM_TOKEN_KEYWORD_ELSE;
19125 parser_lex(parser);
19127 return parse_conditional(parser,
PM_CONTEXT_IF, opening_newline_index, if_after_else, (uint16_t) (depth + 1));
19128 case PM_TOKEN_KEYWORD_UNDEF: {
19129 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19130 pm_parser_err_current(parser, PM_ERR_STATEMENT_UNDEF);
19133 parser_lex(parser);
19135 pm_node_t *name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19137 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19138 pm_node_destroy(parser, name);
19140 pm_undef_node_append(undef, name);
19142 while (match1(parser, PM_TOKEN_COMMA)) {
19143 lex_state_set(parser, PM_LEX_STATE_FNAME | PM_LEX_STATE_FITEM);
19144 parser_lex(parser);
19145 name = parse_undef_argument(parser, (uint16_t) (depth + 1));
19147 if (PM_NODE_TYPE_P(name, PM_MISSING_NODE)) {
19148 pm_node_destroy(parser, name);
19152 pm_undef_node_append(undef, name);
19158 case PM_TOKEN_KEYWORD_NOT: {
19159 parser_lex(parser);
19168 if (!accepts_command_call && !match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19169 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT_PARENTHESES)) {
19170 pm_parser_err(parser, parser->
previous.
end, parser->
previous.
end + 1, PM_ERR_EXPECT_LPAREN_AFTER_NOT_LPAREN);
19172 accept1(parser, PM_TOKEN_NEWLINE);
19173 pm_parser_err_current(parser, PM_ERR_EXPECT_LPAREN_AFTER_NOT_OTHER);
19176 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
19179 accept1(parser, PM_TOKEN_NEWLINE);
19181 if (accept1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
19184 if (accept1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
19185 receiver = UP(pm_parentheses_node_create(parser, &lparen, NULL, &parser->
previous, 0));
19187 arguments.
opening_loc = PM_LOCATION_TOKEN_VALUE(&lparen);
19188 receiver = parse_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19191 accept1(parser, PM_TOKEN_NEWLINE);
19192 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
19197 receiver = parse_expression(parser, PM_BINDING_POWER_NOT,
true,
false, PM_ERR_NOT_EXPRESSION, (uint16_t) (depth + 1));
19200 return UP(pm_call_node_not_create(parser, receiver, &message, &arguments));
19202 case PM_TOKEN_KEYWORD_UNLESS: {
19203 size_t opening_newline_index = token_newline_index(parser);
19204 parser_lex(parser);
19206 return parse_conditional(parser,
PM_CONTEXT_UNLESS, opening_newline_index,
false, (uint16_t) (depth + 1));
19208 case PM_TOKEN_KEYWORD_MODULE: {
19210 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
19212 size_t opening_newline_index = token_newline_index(parser);
19213 parser_lex(parser);
19216 pm_node_t *constant_path = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_MODULE_NAME, (uint16_t) (depth + 1));
19221 if (PM_NODE_TYPE_P(constant_path, PM_MISSING_NODE)) {
19222 pop_block_exits(parser, previous_block_exits);
19223 pm_node_list_free(¤t_block_exits);
19226 return UP(pm_module_node_create(parser, NULL, &module_keyword, constant_path, &missing, NULL, &missing));
19229 while (accept1(parser, PM_TOKEN_COLON_COLON)) {
19232 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
19233 constant_path = UP(pm_constant_path_node_create(parser, constant_path, &double_colon, &parser->
previous));
19240 if (name.
type != PM_TOKEN_CONSTANT) {
19241 pm_parser_err_token(parser, &name, PM_ERR_MODULE_NAME);
19244 pm_parser_scope_push(parser,
true);
19245 accept2(parser, PM_TOKEN_SEMICOLON, PM_TOKEN_NEWLINE);
19248 if (!match4(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE, PM_TOKEN_KEYWORD_END)) {
19249 pm_accepts_block_stack_push(parser,
true);
19250 statements = UP(parse_statements(parser,
PM_CONTEXT_MODULE, (uint16_t) (depth + 1)));
19251 pm_accepts_block_stack_pop(parser);
19254 if (match3(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE, PM_TOKEN_KEYWORD_ELSE)) {
19255 assert(statements == NULL || PM_NODE_TYPE_P(statements, PM_STATEMENTS_NODE));
19256 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)));
19258 parser_warn_indentation_mismatch(parser, opening_newline_index, &module_keyword,
false,
false);
19264 pm_parser_scope_pop(parser);
19265 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_MODULE_TERM, &module_keyword);
19267 if (context_def_p(parser)) {
19268 pm_parser_err_token(parser, &module_keyword, PM_ERR_MODULE_IN_METHOD);
19271 pop_block_exits(parser, previous_block_exits);
19272 pm_node_list_free(¤t_block_exits);
19274 return UP(pm_module_node_create(parser, &locals, &module_keyword, constant_path, &name, statements, &parser->
previous));
19276 case PM_TOKEN_KEYWORD_NIL:
19277 parser_lex(parser);
19278 return UP(pm_nil_node_create(parser, &parser->
previous));
19279 case PM_TOKEN_KEYWORD_REDO: {
19280 parser_lex(parser);
19287 case PM_TOKEN_KEYWORD_RETRY: {
19288 parser_lex(parser);
19291 parse_retry(parser, node);
19295 case PM_TOKEN_KEYWORD_SELF:
19296 parser_lex(parser);
19297 return UP(pm_self_node_create(parser, &parser->
previous));
19298 case PM_TOKEN_KEYWORD_TRUE:
19299 parser_lex(parser);
19300 return UP(pm_true_node_create(parser, &parser->
previous));
19301 case PM_TOKEN_KEYWORD_UNTIL: {
19302 size_t opening_newline_index = token_newline_index(parser);
19305 pm_do_loop_stack_push(parser,
true);
19307 parser_lex(parser);
19309 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
19311 pm_do_loop_stack_pop(parser);
19312 context_pop(parser);
19315 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19318 do_keyword = not_provided(parser);
19319 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_UNTIL_PREDICATE);
19323 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19324 pm_accepts_block_stack_push(parser,
true);
19325 statements = parse_statements(parser,
PM_CONTEXT_UNTIL, (uint16_t) (depth + 1));
19326 pm_accepts_block_stack_pop(parser);
19327 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19330 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19331 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_UNTIL_TERM, &keyword);
19333 return UP(pm_until_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19335 case PM_TOKEN_KEYWORD_WHILE: {
19336 size_t opening_newline_index = token_newline_index(parser);
19339 pm_do_loop_stack_push(parser,
true);
19341 parser_lex(parser);
19343 pm_node_t *predicate = parse_value_expression(parser, PM_BINDING_POWER_COMPOSITION,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
19345 pm_do_loop_stack_pop(parser);
19346 context_pop(parser);
19349 if (accept1(parser, PM_TOKEN_KEYWORD_DO_LOOP)) {
19352 do_keyword = not_provided(parser);
19353 expect2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON, PM_ERR_CONDITIONAL_WHILE_PREDICATE);
19357 if (!match1(parser, PM_TOKEN_KEYWORD_END)) {
19358 pm_accepts_block_stack_push(parser,
true);
19359 statements = parse_statements(parser,
PM_CONTEXT_WHILE, (uint16_t) (depth + 1));
19360 pm_accepts_block_stack_pop(parser);
19361 accept2(parser, PM_TOKEN_NEWLINE, PM_TOKEN_SEMICOLON);
19364 parser_warn_indentation_mismatch(parser, opening_newline_index, &keyword,
false,
false);
19365 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_WHILE_TERM, &keyword);
19367 return UP(pm_while_node_create(parser, &keyword, &do_keyword, &parser->
previous, predicate, statements, 0));
19369 case PM_TOKEN_PERCENT_LOWER_I: {
19370 parser_lex(parser);
19375 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19376 accept1(parser, PM_TOKEN_WORDS_SEP);
19377 if (match1(parser, PM_TOKEN_STRING_END))
break;
19381 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19386 if (current == NULL) {
19387 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19388 parser_lex(parser);
19389 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19390 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19391 parser_lex(parser);
19393 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19398 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19399 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19400 parser_lex(parser);
19403 pm_interpolated_symbol_node_append(interpolated, first_string);
19404 pm_interpolated_symbol_node_append(interpolated, second_string);
19407 current = UP(interpolated);
19409 assert(
false &&
"unreachable");
19414 pm_array_node_elements_append(array, current);
19417 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_LOWER_ELEMENT);
19422 if (match1(parser, PM_TOKEN_EOF)) {
19423 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_LOWER_TERM);
19426 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_LOWER_TERM);
19428 pm_array_node_close_set(array, &closing);
19432 case PM_TOKEN_PERCENT_UPPER_I: {
19433 parser_lex(parser);
19441 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19442 switch (parser->
current.type) {
19443 case PM_TOKEN_WORDS_SEP: {
19444 if (current == NULL) {
19450 pm_array_node_elements_append(array, current);
19454 parser_lex(parser);
19457 case PM_TOKEN_STRING_CONTENT: {
19461 if (current == NULL) {
19465 current = UP(pm_symbol_node_create_current_string(parser, &opening, &parser->
current, &closing));
19466 parser_lex(parser);
19467 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19471 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19472 parser_lex(parser);
19475 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19483 pm_node_t *first_string = UP(pm_string_node_create_unescaped(parser, &bounds, &content, &bounds, &cast->
unescaped));
19484 pm_node_t *second_string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
previous, &closing));
19485 parser_lex(parser);
19488 pm_interpolated_symbol_node_append(interpolated, first_string);
19489 pm_interpolated_symbol_node_append(interpolated, second_string);
19492 current = UP(interpolated);
19494 assert(
false &&
"unreachable");
19499 case PM_TOKEN_EMBVAR: {
19500 bool start_location_set =
false;
19501 if (current == NULL) {
19507 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19508 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19516 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19517 pm_interpolated_symbol_node_append(interpolated, current);
19519 start_location_set =
true;
19520 current = UP(interpolated);
19526 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19528 if (!start_location_set) {
19533 case PM_TOKEN_EMBEXPR_BEGIN: {
19534 bool start_location_set =
false;
19535 if (current == NULL) {
19541 current = UP(pm_interpolated_symbol_node_create(parser, &opening, NULL, &closing));
19542 }
else if (PM_NODE_TYPE_P(current, PM_SYMBOL_NODE)) {
19551 current = UP(pm_symbol_node_to_string_node(parser, (
pm_symbol_node_t *) current));
19552 pm_interpolated_symbol_node_append(interpolated, current);
19554 start_location_set =
true;
19555 current = UP(interpolated);
19556 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_SYMBOL_NODE)) {
19560 assert(
false &&
"unreachable");
19563 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19565 if (!start_location_set) {
19571 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_I_UPPER_ELEMENT);
19572 parser_lex(parser);
19579 pm_array_node_elements_append(array, current);
19583 if (match1(parser, PM_TOKEN_EOF)) {
19584 pm_parser_err_token(parser, &opening, PM_ERR_LIST_I_UPPER_TERM);
19587 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_I_UPPER_TERM);
19589 pm_array_node_close_set(array, &closing);
19593 case PM_TOKEN_PERCENT_LOWER_W: {
19594 parser_lex(parser);
19599 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19600 accept1(parser, PM_TOKEN_WORDS_SEP);
19601 if (match1(parser, PM_TOKEN_STRING_END))
break;
19605 while (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19609 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19612 if (current == NULL) {
19614 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19616 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19618 pm_interpolated_string_node_append(interpolated, current);
19619 pm_interpolated_string_node_append(interpolated,
string);
19620 current = UP(interpolated);
19622 assert(
false &&
"unreachable");
19624 parser_lex(parser);
19628 pm_array_node_elements_append(array, current);
19631 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_LOWER_ELEMENT);
19636 if (match1(parser, PM_TOKEN_EOF)) {
19637 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_LOWER_TERM);
19640 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_LOWER_TERM);
19643 pm_array_node_close_set(array, &closing);
19646 case PM_TOKEN_PERCENT_UPPER_W: {
19647 parser_lex(parser);
19655 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19656 switch (parser->
current.type) {
19657 case PM_TOKEN_WORDS_SEP: {
19662 if (current == NULL) {
19669 pm_array_node_elements_append(array, current);
19673 parser_lex(parser);
19676 case PM_TOKEN_STRING_CONTENT: {
19680 pm_node_t *
string = UP(pm_string_node_create_current_string(parser, &opening, &parser->
current, &closing));
19681 pm_node_flag_set(
string, parse_unescaped_encoding(parser));
19682 parser_lex(parser);
19684 if (current == NULL) {
19690 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19695 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19701 pm_interpolated_string_node_append(interpolated, current);
19702 pm_interpolated_string_node_append(interpolated,
string);
19703 current = UP(interpolated);
19705 assert(
false &&
"unreachable");
19710 case PM_TOKEN_EMBVAR: {
19711 if (current == NULL) {
19718 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19719 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19727 pm_interpolated_string_node_append(interpolated, current);
19728 current = UP(interpolated);
19735 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19739 case PM_TOKEN_EMBEXPR_BEGIN: {
19740 if (current == NULL) {
19747 current = UP(pm_interpolated_string_node_create(parser, &opening, NULL, &closing));
19748 }
else if (PM_NODE_TYPE_P(current, PM_STRING_NODE)) {
19756 pm_interpolated_string_node_append(interpolated, current);
19757 current = UP(interpolated);
19758 }
else if (PM_NODE_TYPE_P(current, PM_INTERPOLATED_STRING_NODE)) {
19763 assert(
false &&
"unreachable");
19766 pm_node_t *part = parse_string_part(parser, (uint16_t) (depth + 1));
19771 expect1(parser, PM_TOKEN_STRING_CONTENT, PM_ERR_LIST_W_UPPER_ELEMENT);
19772 parser_lex(parser);
19779 pm_array_node_elements_append(array, current);
19783 if (match1(parser, PM_TOKEN_EOF)) {
19784 pm_parser_err_token(parser, &opening, PM_ERR_LIST_W_UPPER_TERM);
19787 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_LIST_W_UPPER_TERM);
19790 pm_array_node_close_set(array, &closing);
19793 case PM_TOKEN_REGEXP_BEGIN: {
19795 parser_lex(parser);
19797 if (match1(parser, PM_TOKEN_REGEXP_END)) {
19802 .
type = PM_TOKEN_STRING_CONTENT,
19807 parser_lex(parser);
19809 pm_node_t *node = UP(pm_regular_expression_node_create(parser, &opening, &content, &parser->
previous));
19810 pm_node_flag_set(node, PM_REGULAR_EXPRESSION_FLAGS_FORCED_US_ASCII_ENCODING);
19817 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19825 parser_lex(parser);
19830 if (accept1(parser, PM_TOKEN_REGEXP_END)) {
19837 if (!match1(parser, PM_TOKEN_EQUAL_TILDE)) {
19838 parse_regular_expression_errors(parser, node);
19841 pm_node_flag_set(UP(node), parse_and_validate_regular_expression_encoding(parser, &unescaped, ascii_only, FL(node)));
19847 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19851 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19857 pm_node_flag_set(part, PM_STRING_FLAGS_FORCED_BINARY_ENCODING);
19860 pm_interpolated_regular_expression_node_append(interpolated, part);
19865 interpolated = pm_interpolated_regular_expression_node_create(parser, &opening);
19871 while (!match2(parser, PM_TOKEN_REGEXP_END, PM_TOKEN_EOF)) {
19872 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19873 pm_interpolated_regular_expression_node_append(interpolated, part);
19878 if (match1(parser, PM_TOKEN_EOF)) {
19879 pm_parser_err_token(parser, &opening, PM_ERR_REGEXP_TERM);
19882 expect1(parser, PM_TOKEN_REGEXP_END, PM_ERR_REGEXP_TERM);
19885 pm_interpolated_regular_expression_node_closing_set(parser, interpolated, &closing);
19886 return UP(interpolated);
19888 case PM_TOKEN_BACKTICK:
19889 case PM_TOKEN_PERCENT_LOWER_X: {
19890 parser_lex(parser);
19897 if (match1(parser, PM_TOKEN_STRING_END)) {
19902 .
type = PM_TOKEN_STRING_CONTENT,
19907 parser_lex(parser);
19908 return UP(pm_xstring_node_create(parser, &opening, &content, &parser->
previous));
19913 if (match1(parser, PM_TOKEN_STRING_CONTENT)) {
19920 parser_lex(parser);
19922 if (match1(parser, PM_TOKEN_STRING_END)) {
19923 pm_node_t *node = UP(pm_xstring_node_create_unescaped(parser, &opening, &content, &parser->
current, &unescaped));
19924 pm_node_flag_set(node, parse_unescaped_encoding(parser));
19925 parser_lex(parser);
19931 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19936 pm_node_t *part = UP(pm_string_node_create_unescaped(parser, &opening, &parser->
previous, &closing, &unescaped));
19937 pm_node_flag_set(part, parse_unescaped_encoding(parser));
19939 pm_interpolated_xstring_node_append(node, part);
19944 node = pm_interpolated_xstring_node_create(parser, &opening, &opening);
19948 while (!match2(parser, PM_TOKEN_STRING_END, PM_TOKEN_EOF)) {
19949 if ((part = parse_string_part(parser, (uint16_t) (depth + 1))) != NULL) {
19950 pm_interpolated_xstring_node_append(node, part);
19955 if (match1(parser, PM_TOKEN_EOF)) {
19956 pm_parser_err_token(parser, &opening, PM_ERR_XSTRING_TERM);
19959 expect1(parser, PM_TOKEN_STRING_END, PM_ERR_XSTRING_TERM);
19961 pm_interpolated_xstring_node_closing_set(node, &closing);
19965 case PM_TOKEN_USTAR: {
19966 parser_lex(parser);
19971 if (binding_power != PM_BINDING_POWER_STATEMENT) {
19972 pm_parser_err_prefix(parser, diag_id);
19979 if (token_begins_expression_p(parser->
current.type)) {
19980 name = parse_expression(parser, PM_BINDING_POWER_INDEX,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_STAR, (uint16_t) (depth + 1));
19983 pm_node_t *splat = UP(pm_splat_node_create(parser, &
operator, name));
19985 if (match1(parser, PM_TOKEN_COMMA)) {
19986 return parse_targets_validate(parser, splat, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
19988 return parse_target_validate(parser, splat,
true);
19991 case PM_TOKEN_BANG: {
19992 if (binding_power > PM_BINDING_POWER_UNARY) {
19993 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
19996 parser_lex(parser);
19999 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));
20000 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"!");
20002 pm_conditional_predicate(parser, receiver, PM_CONDITIONAL_PREDICATE_TYPE_NOT);
20005 case PM_TOKEN_TILDE: {
20006 if (binding_power > PM_BINDING_POWER_UNARY) {
20007 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20009 parser_lex(parser);
20012 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20013 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"~");
20017 case PM_TOKEN_UMINUS: {
20018 if (binding_power > PM_BINDING_POWER_UNARY) {
20019 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20021 parser_lex(parser);
20024 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20025 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"-@");
20029 case PM_TOKEN_UMINUS_NUM: {
20030 parser_lex(parser);
20033 pm_node_t *node = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20035 if (accept1(parser, PM_TOKEN_STAR_STAR)) {
20037 pm_node_t *exponent = parse_expression(parser, pm_binding_powers[exponent_operator.
type].right,
false,
false, PM_ERR_EXPECT_ARGUMENT, (uint16_t) (depth + 1));
20038 node = UP(pm_call_node_binary_create(parser, node, &exponent_operator, exponent, 0));
20039 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20041 switch (PM_NODE_TYPE(node)) {
20042 case PM_INTEGER_NODE:
20043 case PM_FLOAT_NODE:
20044 case PM_RATIONAL_NODE:
20045 case PM_IMAGINARY_NODE:
20046 parse_negative_numeric(node);
20049 node = UP(pm_call_node_unary_create(parser, &
operator, node,
"-@"));
20056 case PM_TOKEN_MINUS_GREATER: {
20060 size_t opening_newline_index = token_newline_index(parser);
20061 pm_accepts_block_stack_push(parser,
true);
20062 parser_lex(parser);
20065 pm_parser_scope_push(parser,
false);
20069 switch (parser->
current.type) {
20070 case PM_TOKEN_PARENTHESIS_LEFT: {
20072 parser_lex(parser);
20074 if (match1(parser, PM_TOKEN_PARENTHESIS_RIGHT)) {
20075 block_parameters = pm_block_parameters_node_create(parser, NULL, &opening);
20077 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
true, (uint16_t) (depth + 1));
20080 accept1(parser, PM_TOKEN_NEWLINE);
20081 expect1(parser, PM_TOKEN_PARENTHESIS_RIGHT, PM_ERR_EXPECT_RPAREN);
20083 pm_block_parameters_node_closing_set(block_parameters, &parser->
previous);
20086 case PM_CASE_PARAMETER: {
20087 pm_accepts_block_stack_push(parser,
false);
20089 block_parameters = parse_block_parameters(parser,
false, &opening,
true,
false, (uint16_t) (depth + 1));
20090 pm_accepts_block_stack_pop(parser);
20094 block_parameters = NULL;
20103 if (accept1(parser, PM_TOKEN_LAMBDA_BEGIN)) {
20106 if (!match1(parser, PM_TOKEN_BRACE_RIGHT)) {
20110 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20111 expect1_opening(parser, PM_TOKEN_BRACE_RIGHT, PM_ERR_LAMBDA_TERM_BRACE, &opening);
20113 expect1(parser, PM_TOKEN_KEYWORD_DO, PM_ERR_LAMBDA_OPEN);
20116 if (!match3(parser, PM_TOKEN_KEYWORD_END, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20117 pm_accepts_block_stack_push(parser,
true);
20119 pm_accepts_block_stack_pop(parser);
20122 if (match2(parser, PM_TOKEN_KEYWORD_RESCUE, PM_TOKEN_KEYWORD_ENSURE)) {
20123 assert(body == NULL || PM_NODE_TYPE_P(body, PM_STATEMENTS_NODE));
20124 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)));
20126 parser_warn_indentation_mismatch(parser, opening_newline_index, &
operator,
false,
false);
20129 expect1_opening(parser, PM_TOKEN_KEYWORD_END, PM_ERR_LAMBDA_TERM_END, &
operator);
20133 pm_locals_order(parser, &parser->
current_scope->
locals, &locals, pm_parser_scope_toplevel_p(parser));
20134 pm_node_t *parameters = parse_blocklike_parameters(parser, UP(block_parameters), &
operator, &parser->
previous);
20136 pm_parser_scope_pop(parser);
20137 pm_accepts_block_stack_pop(parser);
20139 return UP(pm_lambda_node_create(parser, &locals, &
operator, &opening, &parser->
previous, parameters, body));
20141 case PM_TOKEN_UPLUS: {
20142 if (binding_power > PM_BINDING_POWER_UNARY) {
20143 pm_parser_err_prefix(parser, PM_ERR_UNARY_DISALLOWED);
20145 parser_lex(parser);
20148 pm_node_t *receiver = parse_expression(parser, pm_binding_powers[parser->
previous.
type].right,
false,
false, PM_ERR_UNARY_RECEIVER, (uint16_t) (depth + 1));
20149 pm_call_node_t *node = pm_call_node_unary_create(parser, &
operator, receiver,
"+@");
20153 case PM_TOKEN_STRING_BEGIN:
20154 return parse_strings(parser, NULL, accepts_label, (uint16_t) (depth + 1));
20155 case PM_TOKEN_SYMBOL_BEGIN: {
20157 parser_lex(parser);
20159 return parse_symbol(parser, &lex_mode, PM_LEX_STATE_END, (uint16_t) (depth + 1));
20170 if (diag_id != PM_ERR_CANNOT_PARSE_EXPRESSION) {
20171 pm_parser_err_prefix(parser, diag_id);
20177 PM_PARSER_ERR_TOKEN_FORMAT(parser, parser->
current, PM_ERR_UNEXPECTED_TOKEN_CLOSE_CONTEXT,
pm_token_type_human(parser->
current.type), context_human(recoverable));
20178 }
else if (diag_id == PM_ERR_CANNOT_PARSE_EXPRESSION) {
20184 pm_parser_err_prefix(parser, diag_id);
20202parse_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) {
20203 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));
20207 if (match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20211 parser_lex(parser);
20213 pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right,
false,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20214 context_pop(parser);
20216 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20228 switch (PM_NODE_TYPE(node)) {
20229 case PM_BEGIN_NODE: {
20234 case PM_LOCAL_VARIABLE_WRITE_NODE: {
20236 pm_locals_read(&pm_parser_scope_find(parser, cast->
depth)->
locals, cast->
name);
20239 case PM_PARENTHESES_NODE: {
20241 if (cast->
body != NULL) parse_assignment_value_local(parser, cast->
body);
20244 case PM_STATEMENTS_NODE: {
20249 parse_assignment_value_local(parser, statement);
20271parse_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) {
20272 bool permitted =
true;
20273 if (previous_binding_power != PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_USTAR)) permitted =
false;
20275 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));
20276 if (!permitted) pm_parser_err_node(parser, value, PM_ERR_UNEXPECTED_MULTI_WRITE);
20278 parse_assignment_value_local(parser, value);
20279 bool single_value =
true;
20281 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && (PM_NODE_TYPE_P(value, PM_SPLAT_NODE) || match1(parser, PM_TOKEN_COMMA))) {
20282 single_value =
false;
20287 pm_array_node_elements_append(array, value);
20290 while (accept1(parser, PM_TOKEN_COMMA)) {
20291 pm_node_t *element = parse_starred_expression(parser, binding_power,
false, PM_ERR_ARRAY_ELEMENT, (uint16_t) (depth + 1));
20293 pm_array_node_elements_append(array, element);
20294 if (PM_NODE_TYPE_P(element, PM_MISSING_NODE))
break;
20296 parse_assignment_value_local(parser, element);
20302 if ((single_value || (binding_power == (PM_BINDING_POWER_MULTI_ASSIGNMENT + 1))) && match1(parser, PM_TOKEN_KEYWORD_RESCUE_MODIFIER)) {
20306 parser_lex(parser);
20308 bool accepts_command_call_inner =
false;
20312 if (PM_NODE_TYPE_P(value, PM_CALL_NODE)) {
20315 accepts_command_call_inner =
true;
20319 pm_node_t *right = parse_expression(parser, pm_binding_powers[PM_TOKEN_KEYWORD_RESCUE_MODIFIER].right, accepts_command_call_inner,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
20320 context_pop(parser);
20322 return UP(pm_rescue_modifier_node_create(parser, value, &rescue, right));
20338 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_ARGUMENTS);
20339 pm_node_unreference(parser, UP(call_node->
arguments));
20340 pm_node_destroy(parser, UP(call_node->
arguments));
20344 if (call_node->
block != NULL) {
20345 pm_parser_err_token(parser,
operator, PM_ERR_OPERATOR_WRITE_BLOCK);
20346 pm_node_unreference(parser, UP(call_node->
block));
20347 pm_node_destroy(parser, UP(call_node->
block));
20348 call_node->
block = NULL;
20377static inline const uint8_t *
20378pm_named_capture_escape_hex(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20381 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20382 uint8_t value = escape_hexadecimal_digit(*cursor);
20385 if (cursor < end && pm_char_is_hexadecimal_digit(*cursor)) {
20386 value = (uint8_t) ((value << 4) | escape_hexadecimal_digit(*cursor));
20390 pm_buffer_append_byte(unescaped, value);
20392 pm_buffer_append_string(unescaped,
"\\x", 2);
20398static inline const uint8_t *
20399pm_named_capture_escape_octal(
pm_buffer_t *unescaped,
const uint8_t *cursor,
const uint8_t *end) {
20400 uint8_t value = (uint8_t) (*cursor -
'0');
20403 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20404 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20407 if (cursor < end && pm_char_is_octal_digit(*cursor)) {
20408 value = ((uint8_t) (value << 3)) | ((uint8_t) (*cursor -
'0'));
20413 pm_buffer_append_byte(unescaped, value);
20417static inline const uint8_t *
20419 const uint8_t *start = cursor - 1;
20422 if (cursor >= end) {
20423 pm_buffer_append_string(unescaped,
"\\u", 2);
20427 if (*cursor !=
'{') {
20428 size_t length = pm_strspn_hexadecimal_digit(cursor, MIN(end - cursor, 4));
20429 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20431 if (!pm_buffer_append_unicode_codepoint(unescaped, value)) {
20432 pm_buffer_append_string(unescaped, (
const char *) start, (
size_t) ((cursor + length) - start));
20435 return cursor + length;
20440 while (cursor < end && *cursor ==
' ') cursor++;
20442 if (cursor >= end)
break;
20443 if (*cursor ==
'}') {
20448 size_t length = pm_strspn_hexadecimal_digit(cursor, end - cursor);
20452 uint32_t value = escape_unicode(parser, cursor, length, error_location);
20454 (void) pm_buffer_append_unicode_codepoint(unescaped, value);
20462pm_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) {
20463 const uint8_t *end = source + length;
20464 pm_buffer_append_string(unescaped, (
const char *) source, (
size_t) (cursor - source));
20467 if (++cursor >= end) {
20468 pm_buffer_append_byte(unescaped,
'\\');
20474 cursor = pm_named_capture_escape_hex(unescaped, cursor, end);
20476 case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
20477 cursor = pm_named_capture_escape_octal(unescaped, cursor, end);
20480 cursor = pm_named_capture_escape_unicode(parser, unescaped, cursor, end, error_location);
20483 pm_buffer_append_byte(unescaped,
'\\');
20487 const uint8_t *next_cursor = pm_memchr(cursor,
'\\', (
size_t) (end - cursor), parser->
encoding_changed, parser->
encoding);
20488 if (next_cursor == NULL)
break;
20490 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (next_cursor - cursor));
20491 cursor = next_cursor;
20494 pm_buffer_append_string(unescaped, (
const char *) cursor, (
size_t) (end - cursor));
20502parse_regular_expression_named_capture(
const pm_string_t *capture,
void *data) {
20523 pm_named_capture_escape(parser, &unescaped, source, length, cursor, callback_data->
shared ? NULL : &call->receiver->location);
20533 if (!pm_slice_is_valid_local(parser, source, source + length)) {
20538 if (callback_data->
shared) {
20542 name = pm_parser_constant_id_location(parser, location.
start, location.
end);
20548 void *memory =
xmalloc(length);
20549 if (memory == NULL) abort();
20551 memcpy(memory, source, length);
20552 name = pm_parser_constant_id_owned(parser, (uint8_t *) memory, length);
20557 if (name != 0 && !pm_constant_id_list_includes(names, name)) {
20558 pm_constant_id_list_append(names, name);
20561 if ((depth = pm_parser_local_depth_constant_id(parser, name)) == -1) {
20564 if (pm_local_is_keyword((
const char *) source, length)) {
20571 pm_parser_local_add(parser, name, location.
start, location.
end, 0);
20576 if (callback_data->
match == NULL) {
20577 callback_data->
match = pm_match_write_node_create(parser, call);
20582 pm_node_t *target = UP(pm_local_variable_target_node_create(parser, &location, name, depth == -1 ? 0 : (uint32_t) depth));
20583 pm_node_list_append(&callback_data->
match->
targets, target);
20599 .shared = content->
type == PM_STRING_SHARED
20606 .shared = content->
type == PM_STRING_SHARED
20609 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);
20610 pm_constant_id_list_free(&callback_data.
names);
20612 if (callback_data.
match != NULL) {
20613 return UP(callback_data.
match);
20620parse_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) {
20623 switch (token.type) {
20624 case PM_TOKEN_EQUAL: {
20625 switch (PM_NODE_TYPE(node)) {
20626 case PM_CALL_NODE: {
20632 if (PM_NODE_FLAG_P(call_node, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20637 case PM_CASE_WRITABLE: {
20641 if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
20645 parser_lex(parser);
20646 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));
20648 if (PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) && previous_binding_power != PM_BINDING_POWER_STATEMENT) {
20649 pm_parser_err_node(parser, node, PM_ERR_UNEXPECTED_MULTI_WRITE);
20652 return parse_write(parser, node, &token, value);
20654 case PM_SPLAT_NODE: {
20656 pm_multi_target_node_targets_append(parser, multi_target, node);
20658 parser_lex(parser);
20659 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));
20660 return parse_write(parser, UP(multi_target), &token, value);
20662 case PM_SOURCE_ENCODING_NODE:
20663 case PM_FALSE_NODE:
20664 case PM_SOURCE_FILE_NODE:
20665 case PM_SOURCE_LINE_NODE:
20668 case PM_TRUE_NODE: {
20671 parser_lex(parser);
20672 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));
20673 return parse_unwriteable_write(parser, node, &token, value);
20679 parser_lex(parser);
20680 pm_parser_err_token(parser, &token, PM_ERR_EXPRESSION_NOT_WRITABLE);
20684 case PM_TOKEN_AMPERSAND_AMPERSAND_EQUAL: {
20685 switch (PM_NODE_TYPE(node)) {
20686 case PM_BACK_REFERENCE_READ_NODE:
20687 case PM_NUMBERED_REFERENCE_READ_NODE:
20688 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20690 case PM_GLOBAL_VARIABLE_READ_NODE: {
20691 parser_lex(parser);
20693 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));
20694 pm_node_t *result = UP(pm_global_variable_and_write_node_create(parser, node, &token, value));
20696 pm_node_destroy(parser, node);
20699 case PM_CLASS_VARIABLE_READ_NODE: {
20700 parser_lex(parser);
20702 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));
20705 pm_node_destroy(parser, node);
20708 case PM_CONSTANT_PATH_NODE: {
20709 parser_lex(parser);
20711 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));
20714 return parse_shareable_constant_write(parser, write);
20716 case PM_CONSTANT_READ_NODE: {
20717 parser_lex(parser);
20719 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));
20722 pm_node_destroy(parser, node);
20723 return parse_shareable_constant_write(parser, write);
20725 case PM_INSTANCE_VARIABLE_READ_NODE: {
20726 parser_lex(parser);
20728 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));
20731 pm_node_destroy(parser, node);
20734 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20736 parser_lex(parser);
20738 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));
20739 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, name, 0));
20741 pm_node_unreference(parser, node);
20742 pm_node_destroy(parser, node);
20745 case PM_LOCAL_VARIABLE_READ_NODE: {
20748 pm_node_unreference(parser, node);
20752 parser_lex(parser);
20754 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));
20755 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20757 pm_node_destroy(parser, node);
20760 case PM_CALL_NODE: {
20766 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20768 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20771 parser_lex(parser);
20773 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));
20774 pm_node_t *result = UP(pm_local_variable_and_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20776 pm_node_destroy(parser, UP(cast));
20782 parser_lex(parser);
20787 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20788 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));
20789 return UP(pm_index_and_write_node_create(parser, cast, &token, value));
20793 if (pm_call_node_writable_p(parser, cast)) {
20794 parse_write_name(parser, &cast->
name);
20796 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20799 parse_call_operator_write(parser, cast, &token);
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 return UP(pm_call_and_write_node_create(parser, cast, &token, value));
20803 case PM_MULTI_WRITE_NODE: {
20804 parser_lex(parser);
20805 pm_parser_err_token(parser, &token, PM_ERR_AMPAMPEQ_MULTI_ASSIGN);
20809 parser_lex(parser);
20814 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_AMPAMPEQ);
20818 case PM_TOKEN_PIPE_PIPE_EQUAL: {
20819 switch (PM_NODE_TYPE(node)) {
20820 case PM_BACK_REFERENCE_READ_NODE:
20821 case PM_NUMBERED_REFERENCE_READ_NODE:
20822 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20824 case PM_GLOBAL_VARIABLE_READ_NODE: {
20825 parser_lex(parser);
20827 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));
20828 pm_node_t *result = UP(pm_global_variable_or_write_node_create(parser, node, &token, value));
20830 pm_node_destroy(parser, node);
20833 case PM_CLASS_VARIABLE_READ_NODE: {
20834 parser_lex(parser);
20836 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));
20839 pm_node_destroy(parser, node);
20842 case PM_CONSTANT_PATH_NODE: {
20843 parser_lex(parser);
20845 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));
20848 return parse_shareable_constant_write(parser, write);
20850 case PM_CONSTANT_READ_NODE: {
20851 parser_lex(parser);
20853 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));
20856 pm_node_destroy(parser, node);
20857 return parse_shareable_constant_write(parser, write);
20859 case PM_INSTANCE_VARIABLE_READ_NODE: {
20860 parser_lex(parser);
20862 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));
20865 pm_node_destroy(parser, node);
20868 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
20870 parser_lex(parser);
20872 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));
20873 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, name, 0));
20875 pm_node_unreference(parser, node);
20876 pm_node_destroy(parser, node);
20879 case PM_LOCAL_VARIABLE_READ_NODE: {
20882 pm_node_unreference(parser, node);
20886 parser_lex(parser);
20888 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));
20889 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
20891 pm_node_destroy(parser, node);
20894 case PM_CALL_NODE: {
20900 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
20902 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
20905 parser_lex(parser);
20907 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));
20908 pm_node_t *result = UP(pm_local_variable_or_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
20910 pm_node_destroy(parser, UP(cast));
20916 parser_lex(parser);
20921 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
20922 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));
20923 return UP(pm_index_or_write_node_create(parser, cast, &token, value));
20927 if (pm_call_node_writable_p(parser, cast)) {
20928 parse_write_name(parser, &cast->
name);
20930 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
20933 parse_call_operator_write(parser, cast, &token);
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 return UP(pm_call_or_write_node_create(parser, cast, &token, value));
20937 case PM_MULTI_WRITE_NODE: {
20938 parser_lex(parser);
20939 pm_parser_err_token(parser, &token, PM_ERR_PIPEPIPEEQ_MULTI_ASSIGN);
20943 parser_lex(parser);
20948 pm_parser_err_token(parser, &token, PM_ERR_EXPECT_EXPRESSION_AFTER_PIPEPIPEEQ);
20952 case PM_TOKEN_AMPERSAND_EQUAL:
20953 case PM_TOKEN_CARET_EQUAL:
20954 case PM_TOKEN_GREATER_GREATER_EQUAL:
20955 case PM_TOKEN_LESS_LESS_EQUAL:
20956 case PM_TOKEN_MINUS_EQUAL:
20957 case PM_TOKEN_PERCENT_EQUAL:
20958 case PM_TOKEN_PIPE_EQUAL:
20959 case PM_TOKEN_PLUS_EQUAL:
20960 case PM_TOKEN_SLASH_EQUAL:
20961 case PM_TOKEN_STAR_EQUAL:
20962 case PM_TOKEN_STAR_STAR_EQUAL: {
20963 switch (PM_NODE_TYPE(node)) {
20964 case PM_BACK_REFERENCE_READ_NODE:
20965 case PM_NUMBERED_REFERENCE_READ_NODE:
20966 PM_PARSER_ERR_NODE_FORMAT_CONTENT(parser, node, PM_ERR_WRITE_TARGET_READONLY);
20968 case PM_GLOBAL_VARIABLE_READ_NODE: {
20969 parser_lex(parser);
20971 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));
20972 pm_node_t *result = UP(pm_global_variable_operator_write_node_create(parser, node, &token, value));
20974 pm_node_destroy(parser, node);
20977 case PM_CLASS_VARIABLE_READ_NODE: {
20978 parser_lex(parser);
20980 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));
20983 pm_node_destroy(parser, node);
20986 case PM_CONSTANT_PATH_NODE: {
20987 parser_lex(parser);
20989 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));
20992 return parse_shareable_constant_write(parser, write);
20994 case PM_CONSTANT_READ_NODE: {
20995 parser_lex(parser);
20997 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));
21000 pm_node_destroy(parser, node);
21001 return parse_shareable_constant_write(parser, write);
21003 case PM_INSTANCE_VARIABLE_READ_NODE: {
21004 parser_lex(parser);
21006 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));
21009 pm_node_destroy(parser, node);
21012 case PM_IT_LOCAL_VARIABLE_READ_NODE: {
21014 parser_lex(parser);
21016 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));
21017 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, name, 0));
21019 pm_node_unreference(parser, node);
21020 pm_node_destroy(parser, node);
21023 case PM_LOCAL_VARIABLE_READ_NODE: {
21026 pm_node_unreference(parser, node);
21030 parser_lex(parser);
21032 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));
21033 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, node, &token, value, cast->
name, cast->
depth));
21035 pm_node_destroy(parser, node);
21038 case PM_CALL_NODE: {
21039 parser_lex(parser);
21045 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_VARIABLE_CALL)) {
21047 pm_refute_numbered_parameter(parser, message_loc->
start, message_loc->
end);
21050 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));
21051 pm_node_t *result = UP(pm_local_variable_operator_write_node_create(parser, UP(cast), &token, value, constant_id, 0));
21053 pm_node_destroy(parser, UP(cast));
21060 if (PM_NODE_FLAG_P(cast, PM_CALL_NODE_FLAGS_INDEX)) {
21061 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));
21062 return UP(pm_index_operator_write_node_create(parser, cast, &token, value));
21066 if (pm_call_node_writable_p(parser, cast)) {
21067 parse_write_name(parser, &cast->
name);
21069 pm_parser_err_node(parser, node, PM_ERR_WRITE_TARGET_UNEXPECTED);
21072 parse_call_operator_write(parser, cast, &token);
21073 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));
21074 return UP(pm_call_operator_write_node_create(parser, cast, &token, value));
21076 case PM_MULTI_WRITE_NODE: {
21077 parser_lex(parser);
21078 pm_parser_err_token(parser, &token, PM_ERR_OPERATOR_MULTI_ASSIGN);
21082 parser_lex(parser);
21091 case PM_TOKEN_AMPERSAND_AMPERSAND:
21092 case PM_TOKEN_KEYWORD_AND: {
21093 parser_lex(parser);
21095 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));
21096 return UP(pm_and_node_create(parser, node, &token, right));
21098 case PM_TOKEN_KEYWORD_OR:
21099 case PM_TOKEN_PIPE_PIPE: {
21100 parser_lex(parser);
21102 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));
21103 return UP(pm_or_node_create(parser, node, &token, right));
21105 case PM_TOKEN_EQUAL_TILDE: {
21113 parser_lex(parser);
21114 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21117 pm_call_node_t *call = pm_call_node_binary_create(parser, node, &token, argument, 0);
21123 if (PM_NODE_TYPE_P(node, PM_INTERPOLATED_REGULAR_EXPRESSION_NODE)) {
21130 bool interpolated =
false;
21131 size_t total_length = 0;
21135 if (PM_NODE_TYPE_P(part, PM_STRING_NODE)) {
21138 interpolated =
true;
21143 if (!interpolated && total_length > 0) {
21144 void *memory =
xmalloc(total_length);
21145 if (!memory) abort();
21147 uint8_t *cursor = memory;
21157 pm_string_owned_init(&owned, (uint8_t *) memory, total_length);
21159 result = parse_regular_expression_named_captures(parser, &owned, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21162 }
else if (PM_NODE_TYPE_P(node, PM_REGULAR_EXPRESSION_NODE)) {
21166 result = parse_regular_expression_named_captures(parser, content, call, PM_NODE_FLAG_P(node, PM_REGULAR_EXPRESSION_FLAGS_EXTENDED));
21171 case PM_TOKEN_UAMPERSAND:
21172 case PM_TOKEN_USTAR:
21173 case PM_TOKEN_USTAR_STAR:
21176 case PM_TOKEN_BANG_EQUAL:
21177 case PM_TOKEN_BANG_TILDE:
21178 case PM_TOKEN_EQUAL_EQUAL:
21179 case PM_TOKEN_EQUAL_EQUAL_EQUAL:
21180 case PM_TOKEN_LESS_EQUAL_GREATER:
21181 case PM_TOKEN_CARET:
21182 case PM_TOKEN_PIPE:
21183 case PM_TOKEN_AMPERSAND:
21184 case PM_TOKEN_GREATER_GREATER:
21185 case PM_TOKEN_LESS_LESS:
21186 case PM_TOKEN_MINUS:
21187 case PM_TOKEN_PLUS:
21188 case PM_TOKEN_PERCENT:
21189 case PM_TOKEN_SLASH:
21190 case PM_TOKEN_STAR:
21191 case PM_TOKEN_STAR_STAR: {
21192 parser_lex(parser);
21194 switch (PM_NODE_TYPE(node)) {
21195 case PM_RESCUE_MODIFIER_NODE: {
21198 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21202 case PM_AND_NODE: {
21204 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21205 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21211 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21212 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21220 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21221 return UP(pm_call_node_binary_create(parser, node, &token, argument, 0));
21223 case PM_TOKEN_GREATER:
21224 case PM_TOKEN_GREATER_EQUAL:
21225 case PM_TOKEN_LESS:
21226 case PM_TOKEN_LESS_EQUAL: {
21227 if (PM_NODE_TYPE_P(node, PM_CALL_NODE) && PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_COMPARISON)) {
21228 PM_PARSER_WARN_TOKEN_FORMAT_CONTENT(parser, parser->
current, PM_WARN_COMPARISON_AFTER_COMPARISON);
21231 parser_lex(parser);
21232 pm_node_t *argument = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21233 return UP(pm_call_node_binary_create(parser, node, &token, argument, PM_CALL_NODE_FLAGS_COMPARISON));
21235 case PM_TOKEN_AMPERSAND_DOT:
21236 case PM_TOKEN_DOT: {
21237 parser_lex(parser);
21242 if (match1(parser, PM_TOKEN_PARENTHESIS_LEFT)) {
21243 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21244 return UP(pm_call_node_shorthand_create(parser, node, &
operator, &arguments));
21247 switch (PM_NODE_TYPE(node)) {
21248 case PM_RESCUE_MODIFIER_NODE: {
21251 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21255 case PM_AND_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));
21264 if (PM_NODE_TYPE_P(cast->
right, PM_MATCH_PREDICATE_NODE) || PM_NODE_TYPE_P(cast->
right, PM_MATCH_REQUIRED_NODE)) {
21265 PM_PARSER_ERR_TOKEN_FORMAT(parser,
operator, PM_ERR_EXPECT_EOL_AFTER_STATEMENT,
pm_token_type_human(
operator.
type));
21275 switch (parser->
current.type) {
21276 case PM_CASE_OPERATOR:
21277 case PM_CASE_KEYWORD:
21278 case PM_TOKEN_CONSTANT:
21279 case PM_TOKEN_IDENTIFIER:
21280 case PM_TOKEN_METHOD_NAME: {
21281 parser_lex(parser);
21291 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21292 pm_call_node_t *call = pm_call_node_call_create(parser, node, &
operator, &message, &arguments);
21295 (previous_binding_power == PM_BINDING_POWER_STATEMENT) &&
21298 match1(parser, PM_TOKEN_COMMA)
21300 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21305 case PM_TOKEN_DOT_DOT:
21306 case PM_TOKEN_DOT_DOT_DOT: {
21307 parser_lex(parser);
21310 if (token_begins_expression_p(parser->
current.type)) {
21311 right = parse_expression(parser, binding_power,
false,
false, PM_ERR_EXPECT_EXPRESSION_AFTER_OPERATOR, (uint16_t) (depth + 1));
21314 return UP(pm_range_node_create(parser, node, &token, right));
21316 case PM_TOKEN_KEYWORD_IF_MODIFIER: {
21318 parser_lex(parser);
21320 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_IF_PREDICATE, (uint16_t) (depth + 1));
21321 return UP(pm_if_node_modifier_create(parser, node, &keyword, predicate));
21323 case PM_TOKEN_KEYWORD_UNLESS_MODIFIER: {
21325 parser_lex(parser);
21327 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNLESS_PREDICATE, (uint16_t) (depth + 1));
21328 return UP(pm_unless_node_modifier_create(parser, node, &keyword, predicate));
21330 case PM_TOKEN_KEYWORD_UNTIL_MODIFIER: {
21331 parser_lex(parser);
21333 pm_statements_node_body_append(parser, statements, node,
true);
21335 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_UNTIL_PREDICATE, (uint16_t) (depth + 1));
21336 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));
21338 case PM_TOKEN_KEYWORD_WHILE_MODIFIER: {
21339 parser_lex(parser);
21341 pm_statements_node_body_append(parser, statements, node,
true);
21343 pm_node_t *predicate = parse_value_expression(parser, binding_power,
true,
false, PM_ERR_CONDITIONAL_WHILE_PREDICATE, (uint16_t) (depth + 1));
21344 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));
21346 case PM_TOKEN_QUESTION_MARK: {
21349 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21352 parser_lex(parser);
21354 pm_node_t *true_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_TRUE, (uint16_t) (depth + 1));
21364 pm_node_t *false_expression = UP(pm_missing_node_create(parser, colon.
start, colon.
end));
21366 context_pop(parser);
21367 pop_block_exits(parser, previous_block_exits);
21368 pm_node_list_free(¤t_block_exits);
21370 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21373 accept1(parser, PM_TOKEN_NEWLINE);
21374 expect1(parser, PM_TOKEN_COLON, PM_ERR_TERNARY_COLON);
21377 pm_node_t *false_expression = parse_expression(parser, PM_BINDING_POWER_DEFINED,
false,
false, PM_ERR_TERNARY_EXPRESSION_FALSE, (uint16_t) (depth + 1));
21379 context_pop(parser);
21380 pop_block_exits(parser, previous_block_exits);
21381 pm_node_list_free(¤t_block_exits);
21383 return UP(pm_if_node_ternary_create(parser, node, &qmark, true_expression, &colon, false_expression));
21385 case PM_TOKEN_COLON_COLON: {
21386 parser_lex(parser);
21389 switch (parser->
current.type) {
21390 case PM_TOKEN_CONSTANT: {
21391 parser_lex(parser);
21395 (parser->
current.type == PM_TOKEN_PARENTHESIS_LEFT) ||
21396 (accepts_command_call && (token_begins_expression_p(parser->
current.type) || match3(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_USTAR_STAR)))
21407 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21408 path = UP(pm_call_node_call_create(parser, node, &delimiter, &message, &arguments));
21411 path = UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21415 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21416 return parse_targets_validate(parser, path, PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21421 case PM_CASE_OPERATOR:
21422 case PM_CASE_KEYWORD:
21423 case PM_TOKEN_IDENTIFIER:
21424 case PM_TOKEN_METHOD_NAME: {
21425 parser_lex(parser);
21431 parse_arguments_list(parser, &arguments,
true, accepts_command_call, (uint16_t) (depth + 1));
21432 pm_call_node_t *call = pm_call_node_call_create(parser, node, &delimiter, &message, &arguments);
21435 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21436 return parse_targets_validate(parser, UP(call), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21441 case PM_TOKEN_PARENTHESIS_LEFT: {
21445 parse_arguments_list(parser, &arguments,
true,
false, (uint16_t) (depth + 1));
21447 return UP(pm_call_node_shorthand_create(parser, node, &delimiter, &arguments));
21450 expect1(parser, PM_TOKEN_CONSTANT, PM_ERR_CONSTANT_PATH_COLON_COLON_CONSTANT);
21451 return UP(pm_constant_path_node_create(parser, node, &delimiter, &parser->
previous));
21455 case PM_TOKEN_KEYWORD_RESCUE_MODIFIER: {
21457 parser_lex(parser);
21458 accept1(parser, PM_TOKEN_NEWLINE);
21460 pm_node_t *value = parse_expression(parser, binding_power,
true,
false, PM_ERR_RESCUE_MODIFIER_VALUE, (uint16_t) (depth + 1));
21461 context_pop(parser);
21463 return UP(pm_rescue_modifier_node_create(parser, node, &token, value));
21465 case PM_TOKEN_BRACKET_LEFT: {
21466 parser_lex(parser);
21471 if (!accept1(parser, PM_TOKEN_BRACKET_RIGHT)) {
21472 pm_accepts_block_stack_push(parser,
true);
21473 parse_arguments(parser, &arguments,
false, PM_TOKEN_BRACKET_RIGHT, (uint16_t) (depth + 1));
21474 pm_accepts_block_stack_pop(parser);
21475 expect1(parser, PM_TOKEN_BRACKET_RIGHT, PM_ERR_EXPECT_RBRACKET);
21482 if (previous_binding_power == PM_BINDING_POWER_STATEMENT && match1(parser, PM_TOKEN_COMMA)) {
21483 pm_call_node_t *aref = pm_call_node_aref_create(parser, node, &arguments);
21484 return parse_targets_validate(parser, UP(aref), PM_BINDING_POWER_INDEX, (uint16_t) (depth + 1));
21491 if (accept1(parser, PM_TOKEN_BRACE_LEFT)) {
21492 block = parse_block(parser, (uint16_t) (depth + 1));
21493 pm_arguments_validate_block(parser, &arguments, block);
21494 }
else if (pm_accepts_block_stack_p(parser) && accept1(parser, PM_TOKEN_KEYWORD_DO)) {
21495 block = parse_block(parser, (uint16_t) (depth + 1));
21498 if (block != NULL) {
21499 if (arguments.
block != NULL) {
21500 pm_parser_err_node(parser, UP(block), PM_ERR_ARGUMENT_AFTER_BLOCK);
21502 arguments.
arguments = pm_arguments_node_create(parser);
21504 pm_arguments_node_arguments_append(arguments.
arguments, arguments.
block);
21507 arguments.
block = UP(block);
21510 return UP(pm_call_node_aref_create(parser, node, &arguments));
21512 case PM_TOKEN_KEYWORD_IN: {
21518 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21519 parser_lex(parser);
21522 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));
21525 pm_constant_id_list_free(&captures);
21527 return UP(pm_match_predicate_node_create(parser, node, pattern, &
operator));
21529 case PM_TOKEN_EQUAL_GREATER: {
21535 lex_state_set(parser, PM_LEX_STATE_BEG | PM_LEX_STATE_LABEL);
21536 parser_lex(parser);
21539 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));
21542 pm_constant_id_list_free(&captures);
21544 return UP(pm_match_required_node_create(parser, node, pattern, &
operator));
21547 assert(
false &&
"unreachable");
21552#undef PM_PARSE_PATTERN_SINGLE
21553#undef PM_PARSE_PATTERN_TOP
21554#undef PM_PARSE_PATTERN_MULTI
21564 (node->
block == NULL || PM_NODE_TYPE_P(node->
block, PM_BLOCK_ARGUMENT_NODE)) &&
21578parse_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) {
21580 pm_parser_err_current(parser, PM_ERR_NESTING_TOO_DEEP);
21581 return UP(pm_missing_node_create(parser, parser->
current.start, parser->
current.end));
21584 pm_node_t *node = parse_expression_prefix(parser, binding_power, accepts_command_call, accepts_label, diag_id, depth);
21586 switch (PM_NODE_TYPE(node)) {
21587 case PM_MISSING_NODE:
21591 case PM_PRE_EXECUTION_NODE:
21592 case PM_POST_EXECUTION_NODE:
21593 case PM_ALIAS_GLOBAL_VARIABLE_NODE:
21594 case PM_ALIAS_METHOD_NODE:
21595 case PM_MULTI_WRITE_NODE:
21596 case PM_UNDEF_NODE:
21599 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21609 if ((pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_COMPOSITION) && pm_call_node_command_p((
pm_call_node_t *) node)) {
21613 case PM_SYMBOL_NODE:
21617 if (pm_symbol_node_label_p(node)) {
21628 pm_token_type_t current_token_type;
21631 current_token_type = parser->
current.type,
21632 current_binding_powers = pm_binding_powers[current_token_type],
21633 binding_power <= current_binding_powers.
left &&
21634 current_binding_powers.
binary
21636 node = parse_expression_infix(parser, node, binding_power, current_binding_powers.
right, accepts_command_call, (uint16_t) (depth + 1));
21644 switch (PM_NODE_TYPE(node)) {
21645 case PM_MULTI_WRITE_NODE:
21648 if (pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21652 case PM_CLASS_VARIABLE_WRITE_NODE:
21653 case PM_CONSTANT_PATH_WRITE_NODE:
21654 case PM_CONSTANT_WRITE_NODE:
21655 case PM_GLOBAL_VARIABLE_WRITE_NODE:
21656 case PM_INSTANCE_VARIABLE_WRITE_NODE:
21657 case PM_LOCAL_VARIABLE_WRITE_NODE:
21660 if (PM_NODE_FLAG_P(node, PM_WRITE_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21668 if (PM_NODE_FLAG_P(node, PM_CALL_NODE_FLAGS_IMPLICIT_ARRAY) && pm_binding_powers[parser->
current.type].left > PM_BINDING_POWER_MODIFIER) {
21678 if (current_binding_powers.
nonassoc) {
21681 if (match1(parser, current_token_type)) {
21693 if (PM_NODE_TYPE_P(node, PM_RANGE_NODE) && ((
pm_range_node_t *) node)->right == NULL) {
21694 if (match4(parser, PM_TOKEN_UAMPERSAND, PM_TOKEN_USTAR, PM_TOKEN_DOT, PM_TOKEN_AMPERSAND_DOT)) {
21699 if (PM_BINDING_POWER_TERM <= pm_binding_powers[parser->
current.type].left) {
21702 }
else if (current_binding_powers.
left <= pm_binding_powers[parser->
current.type].left) {
21707 if (accepts_command_call) {
21716 switch (node->
type) {
21717 case PM_CALL_NODE: {
21731 cast->
block == NULL &&
21741 cast->
block != NULL && PM_NODE_TYPE_P(cast->
block, PM_BLOCK_NODE)
21744 accepts_command_call =
false;
21749 case PM_CONSTANT_PATH_NODE:
21752 accepts_command_call =
false;
21767 if (PM_PARSER_COMMAND_LINE_OPTION_P(parser)) {
21768 if (statements == NULL) {
21769 statements = pm_statements_node_create(parser);
21773 pm_arguments_node_arguments_append(
21775 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2)))
21778 pm_statements_node_body_append(parser, statements, UP(pm_call_node_fcall_synthesized_create(
21781 pm_parser_constant_id_constant(parser,
"print", 5)
21785 if (PM_PARSER_COMMAND_LINE_OPTION_N(parser)) {
21786 if (PM_PARSER_COMMAND_LINE_OPTION_A(parser)) {
21787 if (statements == NULL) {
21788 statements = pm_statements_node_create(parser);
21792 pm_arguments_node_arguments_append(
21794 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$;", 2)))
21797 pm_global_variable_read_node_t *receiver = pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$_", 2));
21798 pm_call_node_t *call = pm_call_node_call_synthesized_create(parser, UP(receiver),
"split", arguments);
21802 pm_parser_constant_id_constant(parser,
"$F", 2),
21806 pm_statements_node_body_prepend(statements, UP(write));
21810 pm_arguments_node_arguments_append(
21812 UP(pm_global_variable_read_node_synthesized_create(parser, pm_parser_constant_id_constant(parser,
"$/", 2)))
21815 if (PM_PARSER_COMMAND_LINE_OPTION_L(parser)) {
21817 pm_keyword_hash_node_elements_append(keywords, UP(pm_assoc_node_create(
21819 UP(pm_symbol_node_synthesized_create(parser,
"chomp")),
21820 &(
pm_token_t) { .type = PM_TOKEN_NOT_PROVIDED, .start = parser->
start, .end = parser->
start },
21821 UP(pm_true_node_synthesized_create(parser))
21824 pm_arguments_node_arguments_append(arguments, UP(keywords));
21825 pm_node_flag_set(UP(arguments), PM_ARGUMENTS_NODE_FLAGS_CONTAINS_KEYWORDS);
21829 pm_statements_node_body_append(parser, wrapped_statements, UP(pm_while_node_synthesized_create(
21831 UP(pm_call_node_fcall_synthesized_create(parser, arguments, pm_parser_constant_id_constant(parser,
"gets", 4))),
21835 statements = wrapped_statements;
21850 pm_parser_scope_push(parser,
true);
21854 pm_node_list_t *previous_block_exits = push_block_exits(parser, ¤t_block_exits);
21856 parser_lex(parser);
21863 assert(statements->
body.
size > 0);
21864 pm_void_statement_check(parser, statements->
body.
nodes[statements->
body.
size - 1]);
21869 pm_parser_scope_pop(parser);
21874 statements = wrap_statements(parser, statements);
21876 flush_block_exits(parser, previous_block_exits);
21879 pm_node_list_free(¤t_block_exits);
21884 if (statements == NULL) {
21885 statements = pm_statements_node_create(parser);
21886 pm_statements_node_location_set(statements, parser->
start, parser->
start);
21889 return UP(pm_program_node_create(parser, &locals, statements));
21906pm_strnstr(
const char *big,
const char *little,
size_t big_length) {
21907 size_t little_length = strlen(little);
21909 for (
const char *max = big + big_length - little_length; big <= max; big++) {
21910 if (*big == *little && memcmp(big, little, little_length) == 0)
return big;
21917#define pm_parser_warn_shebang_carriage_return(parser, start, length) ((void) 0)
21925pm_parser_warn_shebang_carriage_return(
pm_parser_t *parser,
const uint8_t *start,
size_t length) {
21926 if (length > 2 && start[length - 2] ==
'\r' && start[length - 1] ==
'\n') {
21927 pm_parser_warn(parser, start, start + length, PM_WARN_SHEBANG_CARRIAGE_RETURN);
21938 const char *switches = pm_strnstr(engine,
" -", length);
21939 if (switches == NULL)
return;
21944 (
const uint8_t *) (switches + 1),
21945 length - ((
size_t) (switches - engine)) - 1,
21949 size_t encoding_length;
21952 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
21964 assert(source != NULL);
21968 .lex_state = PM_LEX_STATE_BEG,
21969 .enclosure_nesting = 0,
21970 .lambda_enclosure_nesting = -1,
21971 .brace_nesting = 0,
21972 .do_loop_stack = 0,
21973 .accepts_block_stack = 0,
21976 .stack = {{ .mode = PM_LEX_DEFAULT }},
21980 .end = source + size,
21981 .previous = { .type = PM_TOKEN_EOF, .start = source, .end = source },
21982 .current = { .type = PM_TOKEN_EOF, .start = source, .end = source },
21983 .next_start = NULL,
21984 .heredoc_end = NULL,
21985 .data_loc = { .start = NULL, .end = NULL },
21986 .comment_list = { 0 },
21987 .magic_comment_list = { 0 },
21988 .warning_list = { 0 },
21989 .error_list = { 0 },
21990 .current_scope = NULL,
21991 .current_context = NULL,
21993 .encoding_changed_callback = NULL,
21994 .encoding_comment_start = source,
21995 .lex_callback = NULL,
21997 .constant_pool = { 0 },
21998 .newline_list = { 0 },
22002 .explicit_encoding = NULL,
22004 .parsing_eval =
false,
22005 .partial_script =
false,
22006 .command_start =
true,
22007 .recovering =
false,
22008 .encoding_locked =
false,
22009 .encoding_changed =
false,
22010 .pattern_matching_newlines =
false,
22011 .in_keyword_arg =
false,
22012 .current_block_exits = NULL,
22013 .semantic_token_seen =
false,
22015 .current_regular_expression_ascii_only =
false,
22016 .warn_mismatched_indentation =
true
22033 uint32_t constant_size = ((uint32_t) size) / 95;
22034 pm_constant_pool_init(&parser->
constant_pool, constant_size < 4 ? 4 : constant_size);
22039 size_t newline_size = size / 22;
22040 pm_newline_list_init(&parser->
newline_list, source, newline_size < 4 ? 4 : newline_size);
22043 if (options != NULL) {
22052 if (encoding_length > 0) {
22054 parser_lex_magic_comment_encoding_value(parser, encoding_source, encoding_source + encoding_length);
22076 for (
size_t scope_index = 0; scope_index < options->
scopes_count; scope_index++) {
22078 pm_parser_scope_push(parser, scope_index == 0);
22084 for (
size_t local_index = 0; local_index < scope->
locals_count; local_index++) {
22090 void *allocated =
xmalloc(length);
22091 if (allocated == NULL)
continue;
22093 memcpy(allocated, source, length);
22094 pm_parser_local_add_owned(parser, (uint8_t *) allocated, length);
22105 pm_accepts_block_stack_push(parser,
true);
22108 if (size >= 3 && source[0] == 0xef && source[1] == 0xbb && source[2] == 0xbf) {
22121 bool search_shebang = PM_PARSER_COMMAND_LINE_OPTION_X(parser);
22138 const uint8_t *newline = next_newline(parser->
current.end, parser->
end - parser->
current.end);
22139 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - parser->
current.end);
22141 if (length > 2 && parser->
current.end[0] ==
'#' && parser->
current.end[1] ==
'!') {
22142 const char *engine;
22144 if ((engine = pm_strnstr((
const char *) parser->
start,
"ruby", length)) != NULL) {
22145 if (newline != NULL) {
22149 pm_parser_warn_shebang_carriage_return(parser, parser->
start, length + 1);
22154 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) parser->
start)));
22157 search_shebang =
false;
22159 search_shebang =
true;
22165 if (search_shebang) {
22168 bool found_shebang =
false;
22172 const uint8_t *cursor = parser->
start;
22176 const uint8_t *newline = next_newline(cursor, parser->
end - cursor);
22178 while (newline != NULL) {
22179 pm_newline_list_append(&parser->
newline_list, newline);
22181 cursor = newline + 1;
22182 newline = next_newline(cursor, parser->
end - cursor);
22184 size_t length = (size_t) ((newline != NULL ? newline : parser->
end) - cursor);
22185 if (length > 2 && cursor[0] ==
'#' && cursor[1] ==
'!') {
22186 const char *engine;
22187 if ((engine = pm_strnstr((
const char *) cursor,
"ruby", length)) != NULL) {
22188 found_shebang =
true;
22190 if (newline != NULL) {
22191 pm_parser_warn_shebang_carriage_return(parser, cursor, length + 1);
22196 pm_parser_init_shebang(parser, options, engine, length - ((
size_t) (engine - (
const char *) cursor)));
22204 if (found_shebang) {
22206 parser->
current = (
pm_token_t) { .type = PM_TOKEN_EOF, .start = cursor, .end = cursor };
22208 pm_parser_err(parser, parser->
start, parser->
start, PM_ERR_SCRIPT_NOT_FOUND);
22235 for (node = list->
head; node != NULL; node = next) {
22247pm_magic_comment_list_free(
pm_list_t *list) {
22250 for (node = list->
head; node != NULL; node = next) {
22264 pm_diagnostic_list_free(&parser->
error_list);
22276 pm_parser_scope_pop(parser);
22280 lex_mode_pop(parser);
22289 return parse_program(parser);
22299#define LINE_SIZE 4096
22300 char line[LINE_SIZE];
22302 while (memset(line,
'\n', LINE_SIZE), stream_fgets(line, LINE_SIZE, stream) != NULL) {
22303 size_t length = LINE_SIZE;
22304 while (length > 0 && line[length - 1] ==
'\n') length--;
22306 if (length == LINE_SIZE) {
22311 pm_buffer_append_string(buffer, line, length);
22317 pm_buffer_append_string(buffer, line, length);
22325 if (strncmp(line,
"__END__", 7) == 0)
return false;
22328 if (strncmp(line,
"__END__\n", 8) == 0)
return false;
22331 if (strncmp(line,
"__END__\r\n", 9) == 0)
return false;
22337 if (stream_feof(stream)) {
22356pm_parse_stream_unterminated_heredoc_p(
pm_parser_t *parser) {
22359 for (; diagnostic != NULL; diagnostic = (
pm_diagnostic_t *) diagnostic->node.next) {
22360 if (diagnostic->diag_id == PM_ERR_HEREDOC_TERM) {
22378 bool eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22384 pm_node_destroy(parser, node);
22385 eof = pm_parse_stream_read(buffer, stream, stream_fgets, stream_feof);
22399pm_parse_success_p(
const uint8_t *source,
size_t size,
const char *data) {
22401 pm_options_read(&options, data);
22407 pm_node_destroy(&parser, node);
22416#undef PM_CASE_KEYWORD
22417#undef PM_CASE_OPERATOR
22418#undef PM_CASE_WRITABLE
22419#undef PM_STRING_EMPTY
22424#ifndef PRISM_EXCLUDE_SERIALIZATION
22428 pm_buffer_append_string(buffer,
"PRISM", 5);
22432 pm_buffer_append_byte(buffer, PRISM_SERIALIZE_ONLY_SEMANTICS_FIELDS ? 1 : 0);
22440 pm_serialize_header(buffer);
22442 pm_buffer_append_byte(buffer,
'\0');
22450pm_serialize_parse(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22452 pm_options_read(&options, data);
22459 pm_serialize_header(buffer);
22461 pm_buffer_append_byte(buffer,
'\0');
22463 pm_node_destroy(&parser, node);
22476 pm_options_read(&options, data);
22480 pm_serialize_header(buffer);
22482 pm_buffer_append_byte(buffer,
'\0');
22484 pm_node_destroy(&parser, node);
22494pm_serialize_parse_comments(
pm_buffer_t *buffer,
const uint8_t *source,
size_t size,
const char *data) {
22496 pm_options_read(&options, data);
22502 pm_serialize_header(buffer);
22504 pm_buffer_append_varsint(buffer, parser.
start_line);
22507 pm_node_destroy(&parser, node);
22521 PM_SLICE_TYPE_ERROR = -1,
22524 PM_SLICE_TYPE_NONE,
22527 PM_SLICE_TYPE_LOCAL,
22530 PM_SLICE_TYPE_CONSTANT,
22533 PM_SLICE_TYPE_METHOD_NAME
22540pm_slice_type(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22542 const pm_encoding_t *encoding = pm_encoding_find((
const uint8_t *) encoding_name, (
const uint8_t *) (encoding_name + strlen(encoding_name)));
22543 if (encoding == NULL)
return PM_SLICE_TYPE_ERROR;
22546 if (length == 0)
return PM_SLICE_TYPE_NONE;
22549 if ((width = encoding->
alpha_char(source, (ptrdiff_t) length)) != 0) {
22551 }
else if (*source ==
'_') {
22554 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, (ptrdiff_t) length)) > 0)) {
22558 return PM_SLICE_TYPE_NONE;
22562 const uint8_t *end = source + length;
22563 pm_slice_type_t result = encoding->
isupper_char(source, end - source) ? PM_SLICE_TYPE_CONSTANT : PM_SLICE_TYPE_LOCAL;
22569 while (source < end) {
22570 if ((width = encoding->
alnum_char(source, end - source)) != 0) {
22573 }
else if (*source ==
'_') {
22576 }
else if ((*source >= 0x80) && ((width = encoding->
char_width(source, end - source)) > 0)) {
22586 if (*source ==
'!' || *source ==
'?' || *source ==
'=') {
22588 result = PM_SLICE_TYPE_METHOD_NAME;
22592 return source == end ? result : PM_SLICE_TYPE_NONE;
22599pm_string_query_local(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22600 switch (pm_slice_type(source, length, encoding_name)) {
22601 case PM_SLICE_TYPE_ERROR:
22603 case PM_SLICE_TYPE_NONE:
22604 case PM_SLICE_TYPE_CONSTANT:
22605 case PM_SLICE_TYPE_METHOD_NAME:
22607 case PM_SLICE_TYPE_LOCAL:
22611 assert(
false &&
"unreachable");
22619pm_string_query_constant(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22620 switch (pm_slice_type(source, length, encoding_name)) {
22621 case PM_SLICE_TYPE_ERROR:
22623 case PM_SLICE_TYPE_NONE:
22624 case PM_SLICE_TYPE_LOCAL:
22625 case PM_SLICE_TYPE_METHOD_NAME:
22627 case PM_SLICE_TYPE_CONSTANT:
22631 assert(
false &&
"unreachable");
22639pm_string_query_method_name(
const uint8_t *source,
size_t length,
const char *encoding_name) {
22640#define B(p) ((p) ? PM_STRING_QUERY_TRUE : PM_STRING_QUERY_FALSE)
22641#define C1(c) (*source == c)
22642#define C2(s) (memcmp(source, s, 2) == 0)
22643#define C3(s) (memcmp(source, s, 3) == 0)
22645 switch (pm_slice_type(source, length, encoding_name)) {
22646 case PM_SLICE_TYPE_ERROR:
22648 case PM_SLICE_TYPE_NONE:
22650 case PM_SLICE_TYPE_LOCAL:
22652 return B((length != 2) || (source[0] !=
'_') || (source[1] ==
'0') || !pm_char_is_decimal_digit(source[1]));
22653 case PM_SLICE_TYPE_CONSTANT:
22655 case PM_SLICE_TYPE_METHOD_NAME:
22662 return B(C1(
'&') || C1(
'`') || C1(
'!') || C1(
'^') || C1(
'>') || C1(
'<') || C1(
'-') || C1(
'%') || C1(
'|') || C1(
'+') || C1(
'/') || C1(
'*') || C1(
'~'));
22664 return B(C2(
"!=") || C2(
"!~") || C2(
"[]") || C2(
"==") || C2(
"=~") || C2(
">=") || C2(
">>") || C2(
"<=") || C2(
"<<") || C2(
"**"));
22666 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.
PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options)
Free the internal memory associated with the options.
PRISM_EXPORTED_FUNCTION const pm_string_t * pm_options_scope_local_get(const pm_options_scope_t *scope, size_t index)
Return a pointer to the local at the given index within the given scope.
PRISM_EXPORTED_FUNCTION const pm_options_scope_t * pm_options_scope_get(const pm_options_t *options, size_t index)
Return a pointer to the scope at the given index within the given options.
static const uint8_t PM_OPTIONS_COMMAND_LINE_N
A bit representing whether or not the command line -n option was set.
#define PM_OPTIONS_FROZEN_STRING_LITERAL_DISABLED
String literals should 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.
static const uint8_t PM_OPTIONS_COMMAND_LINE_P
A bit representing whether or not the command line -p option was set.
@ 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.
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_comment pm_comment_t
This is a node in the linked list of comments that we've found while parsing.
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.
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_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? expression
@ 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.
void pm_buffer_free(pm_buffer_t *buffer)
Free the memory associated with the buffer.
bool pm_buffer_init(pm_buffer_t *buffer)
Initialize a pm_buffer_t with its default values.
size_t pm_buffer_length(const pm_buffer_t *buffer)
Return the length of the buffer.
char * pm_buffer_value(const pm_buffer_t *buffer)
Return the value of the buffer.
#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.
PRISM_EXPORTED_FUNCTION size_t pm_string_length(const pm_string_t *string)
Returns the length associated with the string.
PRISM_EXPORTED_FUNCTION const uint8_t * pm_string_source(const pm_string_t *string)
Returns the start pointer associated with the string.
PRISM_EXPORTED_FUNCTION void pm_string_free(pm_string_t *string)
Free the associated memory of the given string.
#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.
PRISM_EXPORTED_FUNCTION pm_node_t * pm_parse(pm_parser_t *parser)
Parse the Ruby source associated with the given parser and return the tree.
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...
PRISM_EXPORTED_FUNCTION void pm_parser_free(pm_parser_t *parser)
Free any memory associated with the given parser.
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.
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.
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.
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_encoding(const pm_encoding_t *encoding, pm_buffer_t *buffer)
Serialize the name of the encoding to the buffer.
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_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.
This is a node in a linked list of contexts.
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.
const char * name
The name of the encoding.
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...
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.
GlobalVariableTargetNode.
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.
InstanceVariableReadNode.
InstanceVariableTargetNode.
InstanceVariableWriteNode.
pm_integer_t value
IntegerNode::value.
pm_node_t base
The embedded base node.
bool negative
Whether or not the integer is negative.
InterpolatedMatchLastLineNode.
InterpolatedRegularExpressionNode.
pm_node_t base
The embedded base node.
pm_location_t opening_loc
InterpolatedStringNode::opening_loc.
pm_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...
When lexing Ruby source, the lexer has a small amount of state to tell which kind of token it is curr...
uint8_t terminator
This is the terminator of the list literal.
size_t nesting
This keeps track of the nesting level of the list.
bool interpolation
Whether or not interpolation is allowed in this list.
uint8_t incrementor
When lexing a list, it takes into account balancing the terminator if the terminator is one of (),...
enum pm_lex_mode::@98 mode
The type of this lex mode.
uint8_t breakpoints[11]
This is the character set that should be used to delimit the tokens within the list.
pm_heredoc_lex_mode_t base
All of the data necessary to lex a heredoc.
bool line_continuation
True if the previous token ended with a line continuation.
struct pm_lex_mode * prev
The previous lex state so that it knows how to pop.
bool label_allowed
Whether or not at the end of the string we should allow a :, which would indicate this was a dynamic ...
const uint8_t * next_start
This is the pointer to the character where lexing should resume once the heredoc has been completely ...
union pm_lex_mode::@99 as
The data associated with this type of lex mode.
size_t * common_whitespace
This is used to track the amount of common whitespace on each line so that we know how much to dedent...
int32_t line
The line number.
This struct represents an abstract linked list that provides common functionality.
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.
This is a set of local variables in a certain lexical context (method, class, module,...
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.
A list of nodes in the source, most often used for lists of children.
size_t size
The number of nodes in the list.
struct pm_node ** nodes
The nodes in the list.
This is the base structure that represents a node in the syntax tree.
pm_node_type_t type
This represents the type of the node.
pm_location_t location
This is the location of the node in the source.
A scope of locals surrounding the code that is being parsed.
size_t locals_count
The number of locals in the scope.
uint8_t forwarding
Flags for the set of forwarding parameters in this scope.
The options that can be passed to the parser.
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.
This struct represents the overall parser.
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.
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...
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.
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.
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_lex_mode_t stack[PM_LEX_STACK_SIZE]
The stack of lexer modes.
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.
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 ...
struct pm_parser::@104 lex_modes
A stack of lex modes.
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_lex_mode_t * current
The current mode of the lexer.
pm_list_t comment_list
The list of comments that have been found while parsing.
size_t index
The current index into the lexer mode stack.
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...
uint32_t node_id
The next node identifier that will be assigned.
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.
This struct represents a node in a linked list of scopes.
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.
enum pm_string_t::@105 type
The type of the string.
pm_location_t value_loc
SymbolNode::value_loc.
pm_string_t unescaped
SymbolNode::unescaped.
When we're lexing certain types (strings, symbols, lists, etc.) we have string content associated wit...
pm_buffer_t buffer
The buffer that we're using to keep track of the string content.
const uint8_t * cursor
The cursor into the source string that points to how far we have currently copied into the buffer.
This struct represents a token in the Ruby source.
const uint8_t * end
A pointer to the end location of the token in the source.
const uint8_t * start
A pointer to the start location of the token in the source.
pm_token_type_t type
The type of the token.
struct pm_statements_node * statements
UnlessNode::statements.
struct pm_else_node * else_clause
UnlessNode::else_clause.